diff --git a/circle_app/assets/images/msg/emoji.png b/circle_app/assets/images/msg/emoji.png new file mode 100644 index 0000000..740fe9c Binary files /dev/null and b/circle_app/assets/images/msg/emoji.png differ diff --git a/circle_app/assets/images/msg/photo.png b/circle_app/assets/images/msg/photo.png new file mode 100644 index 0000000..f1f07f6 Binary files /dev/null and b/circle_app/assets/images/msg/photo.png differ diff --git a/circle_app/assets/images/msg/send.png b/circle_app/assets/images/msg/send.png new file mode 100644 index 0000000..b4e5c93 Binary files /dev/null and b/circle_app/assets/images/msg/send.png differ diff --git a/circle_app/assets/images/msg/take_photo.png b/circle_app/assets/images/msg/take_photo.png new file mode 100644 index 0000000..1a91a8f Binary files /dev/null and b/circle_app/assets/images/msg/take_photo.png differ diff --git a/circle_app/assets/images/msg/voice.png b/circle_app/assets/images/msg/voice.png new file mode 100644 index 0000000..6cca7c9 Binary files /dev/null and b/circle_app/assets/images/msg/voice.png differ diff --git a/circle_app/ios/Podfile.lock b/circle_app/ios/Podfile.lock index 43764b2..fcd0b25 100644 --- a/circle_app/ios/Podfile.lock +++ b/circle_app/ios/Podfile.lock @@ -3,6 +3,8 @@ PODS: - Flutter - camera_avfoundation (0.0.1): - Flutter + - device_info (0.0.1): + - Flutter - device_info_plus (0.0.1): - Flutter - disk_space (0.0.1): @@ -129,10 +131,13 @@ PODS: - Flutter - wakelock (0.0.1): - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter DEPENDENCIES: - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`) - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) + - device_info (from `.symlinks/plugins/device_info/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - disk_space (from `.symlinks/plugins/disk_space/ios`) - fc_native_video_thumbnail_for_us (from `.symlinks/plugins/fc_native_video_thumbnail_for_us/ios`) @@ -156,6 +161,7 @@ DEPENDENCIES: - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) - wakelock (from `.symlinks/plugins/wakelock/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) SPEC REPOS: trunk: @@ -178,6 +184,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/audioplayers_darwin/ios" camera_avfoundation: :path: ".symlinks/plugins/camera_avfoundation/ios" + device_info: + :path: ".symlinks/plugins/device_info/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" disk_space: @@ -224,10 +232,13 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/video_player_avfoundation/ios" wakelock: :path: ".symlinks/plugins/wakelock/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" SPEC CHECKSUMS: audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40 camera_avfoundation: 3125e8cd1a4387f6f31c6c63abb8a55892a9eeeb + device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed disk_space: e94d34bbdf77954adfb39e60bde9cc5c7233eda6 DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac @@ -264,6 +275,7 @@ SPEC CHECKSUMS: url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126 wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f + webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a PODFILE CHECKSUM: 9f3fe3e871b4a811f0f2f55cc60906d65b3d629e diff --git a/circle_app/ios/Runner/Info.plist b/circle_app/ios/Runner/Info.plist index fc10eaf..1a0eee6 100644 --- a/circle_app/ios/Runner/Info.plist +++ b/circle_app/ios/Runner/Info.plist @@ -2,7 +2,7 @@ - Microphone Usage Description + NSMicrophoneUsageDescription 应用想要访问您的麦克风,用于发送语音 NSCameraUsageDescription 应用想要访问您的相机,用于设置头像/动态发布 diff --git a/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart b/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart index bcd1a2e..1ef8dfa 100644 --- a/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart +++ b/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart @@ -16,7 +16,7 @@ import 'package:tencent_cloud_chat_uikit/ui/utils/permission.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/sound_record.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; -class SendSoundMessage extends StatefulWidget { +class TIMSendSoundMessage extends StatefulWidget { /// conversation ID final String conversationID; @@ -26,7 +26,7 @@ class SendSoundMessage extends StatefulWidget { /// the conversation type final ConvType conversationType; - const SendSoundMessage( + const TIMSendSoundMessage( {required this.conversationID, required this.conversationType, Key? key, @@ -34,10 +34,10 @@ class SendSoundMessage extends StatefulWidget { : super(key: key); @override - State createState() => _SendSoundMessageState(); + State createState() => _TIMSendSoundMessageState(); } -class _SendSoundMessageState extends TIMUIKitState { +class _TIMSendSoundMessageState extends TIMUIKitState { final TUIChatGlobalModel model = serviceLocator(); String soundTipsText = ""; bool isRecording = false; @@ -68,7 +68,8 @@ class _SendSoundMessageState extends TIMUIKitState { width: 160, height: 160, decoration: const BoxDecoration( - color: Color(0xff77797A), + color: Colors.transparent, + // color: Color(0xff77797A), borderRadius: BorderRadius.all(Radius.circular(20.0)), ), child: Column( diff --git a/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart b/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart index 5c5d473..a0834c5 100644 --- a/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart +++ b/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart @@ -1,5 +1,7 @@ import 'dart:async'; import 'dart:math'; +import 'package:circle_app/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart'; +import 'package:circle_app/util/util.dart'; import 'package:diff_match_patch/diff_match_patch.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; @@ -23,24 +25,10 @@ import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField enum MuteStatus { none, me, all } -typedef CustomStickerPanel = Widget Function({ - void Function() sendTextMessage, - void Function(int index, String data) sendFaceMessage, - void Function() deleteText, - void Function(int unicode) addText, - void Function(String singleEmojiName) addCustomEmojiText, - List defaultCustomEmojiStickerList, - /// If non-null, requires the child to have exactly this width. - double? width, +GlobalKey<_InputTextFieldState> myInputTextFieldState = GlobalKey(); - /// If non-null, requires the child to have exactly this height. - double? height, -}); - -GlobalKey<_InputTextFieldState> inputTextFieldState = GlobalKey(); - -class TIMUIKitInputTextField extends StatefulWidget { +class TIMInputTextField extends StatefulWidget { /// conversation id final String conversationID; @@ -95,7 +83,7 @@ class TIMUIKitInputTextField extends StatefulWidget { final String? groupType; - const TIMUIKitInputTextField( + const TIMInputTextField( {Key? key, required this.conversationID, required this.conversationType, @@ -122,7 +110,7 @@ class TIMUIKitInputTextField extends StatefulWidget { State createState() => _InputTextFieldState(); } -class _InputTextFieldState extends TIMUIKitState { +class _InputTextFieldState extends TIMUIKitState { final TUIChatGlobalModel globalModel = serviceLocator(); final TUISettingModel settingModel = serviceLocator(); final RegExp atTextReg = RegExp(r'@([^@\s]*)'); @@ -297,8 +285,10 @@ class _InputTextFieldState extends TIMUIKitState { goDownBottom(); _handleSendEditStatus("", false); + } else { + showToast('请输入消息内容'); } - } +} void goDownBottom() { if (globalModel.getMessageListPosition(widget.conversationID) == @@ -647,7 +637,7 @@ class _InputTextFieldState extends TIMUIKitState { } @override - void didUpdateWidget(TIMUIKitInputTextField oldWidget) { + void didUpdateWidget(TIMInputTextField oldWidget) { super.didUpdateWidget(oldWidget); if (widget.conversationID != oldWidget.conversationID) { handleSetDraftText(oldWidget.conversationID, oldWidget.conversationType); @@ -763,7 +753,7 @@ class _InputTextFieldState extends TIMUIKitState { builder: (BuildContext context, BoxConstraints constraints) { inputWidth = constraints.maxWidth; return TUIKitScreenUtils.getDeviceWidget( - defaultWidget: TIMUIKitTextFieldLayoutNarrow( + defaultWidget: TIMTextFieldLayoutNarrow( onEmojiSubmitted: onEmojiSubmitted, onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted, backSpaceText: backSpaceText, @@ -793,7 +783,7 @@ class _InputTextFieldState extends TIMUIKitState { handleSoftKeyBoardDelete: _handleSoftKeyBoardDelete, onSubmitted: onSubmitted, goDownBottom: goDownBottom, - showSendAudio: widget.showSendAudio, + showSendAudio: false, showSendEmoji: widget.showSendEmoji, showMorePanel: widget.showMorePanel, customEmojiStickerList: widget.customEmojiStickerList), diff --git a/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart b/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart index 40679d4..00fc3e4 100644 --- a/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart +++ b/circle_app/lib/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart @@ -1,8 +1,14 @@ import 'dart:async'; import 'dart:math'; +import 'package:circle_app/app/chat/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart'; +import 'package:circle_app/util/util.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:get/get.dart'; +import 'package:get/get_core/src/get_main.dart'; +import 'package:image_picker/image_picker.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart'; @@ -20,9 +26,9 @@ import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField import 'package:tencent_extended_text_field/extended_text_field.dart'; import 'package:tencent_keyboard_visibility/tencent_keyboard_visibility.dart'; -GlobalKey<_TIMUIKitTextFieldLayoutNarrowState> narrowTextFieldKey = GlobalKey(); +GlobalKey<_TIMTextFieldLayoutNarrowState> TIMnarrowTextFieldKey = GlobalKey(); -class TIMUIKitTextFieldLayoutNarrow extends StatefulWidget { +class TIMTextFieldLayoutNarrow extends StatefulWidget { /// sticker panel customization final CustomStickerPanel? customStickerPanel; @@ -93,7 +99,7 @@ class TIMUIKitTextFieldLayoutNarrow extends StatefulWidget { final List customEmojiStickerList; - const TIMUIKitTextFieldLayoutNarrow( + const TIMTextFieldLayoutNarrow( {Key? key, this.customStickerPanel, required this.onEmojiSubmitted, @@ -129,13 +135,14 @@ class TIMUIKitTextFieldLayoutNarrow extends StatefulWidget { : super(key: key); @override - State createState() => - _TIMUIKitTextFieldLayoutNarrowState(); + State createState() => + _TIMTextFieldLayoutNarrowState(); } -class _TIMUIKitTextFieldLayoutNarrowState - extends TIMUIKitState { +class _TIMTextFieldLayoutNarrowState + extends TIMUIKitState { final TUISettingModel settingModel = serviceLocator(); + final ImagePicker _picker = ImagePicker(); bool showMore = false; bool showMoreButton = true; @@ -189,34 +196,34 @@ class _TIMUIKitTextFieldLayoutNarrowState if (showEmojiPanel) { return widget.customStickerPanel != null ? widget.customStickerPanel!( - sendTextMessage: () { - widget.onEmojiSubmitted(); - setSendButton(); - }, - sendFaceMessage: widget.onCustomEmojiFaceSubmitted, - deleteText: () { - widget.backSpaceText(); - setSendButton(); - }, - addText: (int unicode) { - final newText = String.fromCharCode(unicode); - widget.addStickerToText(newText); - // handleSetDraftText(); - }, - addCustomEmojiText: ((String singleEmojiName) { - String? emojiName = singleEmojiName.split('.png')[0]; - if (widget.isUseDefaultEmoji && - widget.languageType == 'zh' && - ConstData.emojiMapList[emojiName] != null && - ConstData.emojiMapList[emojiName] != '') { - emojiName = ConstData.emojiMapList[emojiName]; - } - final newText = '[$emojiName]'; - widget.addStickerToText(newText); - setSendButton(); - }), - defaultCustomEmojiStickerList: - widget.isUseDefaultEmoji ? ConstData.emojiList : []) + sendTextMessage: () { + widget.onEmojiSubmitted(); + setSendButton(); + }, + sendFaceMessage: widget.onCustomEmojiFaceSubmitted, + deleteText: () { + widget.backSpaceText(); + setSendButton(); + }, + addText: (int unicode) { + final newText = String.fromCharCode(unicode); + widget.addStickerToText(newText); + // handleSetDraftText(); + }, + addCustomEmojiText: ((String singleEmojiName) { + String? emojiName = singleEmojiName.split('.png')[0]; + if (widget.isUseDefaultEmoji && + widget.languageType == 'zh' && + ConstData.emojiMapList[emojiName] != null && + ConstData.emojiMapList[emojiName] != '') { + emojiName = ConstData.emojiMapList[emojiName]; + } + final newText = '[$emojiName]'; + widget.addStickerToText(newText); + setSendButton(); + }), + defaultCustomEmojiStickerList: + widget.isUseDefaultEmoji ? ConstData.emojiList : []) : EmojiPanel(onTapEmoji: (unicode) { final newText = String.fromCharCode(unicode); widget.addStickerToText(newText); @@ -256,7 +263,7 @@ class _TIMUIKitTextFieldLayoutNarrowState final height = originHeight != 0 ? originHeight : currentKeyboardHeight; return height; } else if (showMore || showEmojiPanel) { - return 248.0 + (bottomPadding ?? 0.0); + return 268.0 + (bottomPadding ?? 0.0); } else if (widget.textEditingController.text.length >= 46 && showKeyboard == false) { return 25 + (bottomPadding ?? 0.0); @@ -388,190 +395,208 @@ class _TIMUIKitTextFieldLayoutNarrowState return Column( children: [ _buildRepliedMessage(widget.repliedMessage), - Container( - color: widget.backgroundColor ?? hexToColor("f5f5f6"), - child: Column( - children: [ - Container( - padding: - const EdgeInsets.symmetric(vertical: 8, horizontal: 16), - constraints: const BoxConstraints(minHeight: 50), - child: Row( - children: [ - if (widget.forbiddenText != null) - Expanded( - child: Container( - height: 35, - color: theme.weakBackgroundColor, - alignment: Alignment.center, - child: Text( - TIM_t(widget.forbiddenText!), - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - color: theme.weakTextColor, + Stack( + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular( + 16.sp, + ), + topRight: Radius.circular(16.sp)), + color: Color(0xFF423055), + // color: Colors.yellow, + ), + child: Column( + children: [ + Container( + padding: + EdgeInsets.symmetric(vertical: 8, horizontal: 12.sp), + constraints: const BoxConstraints(minHeight: 30), + child: Row( + children: [ + if (widget.forbiddenText != null) + Expanded( + child: Container( + height: 35, + color: theme.weakBackgroundColor, + alignment: Alignment.center, + child: Text( + TIM_t(widget.forbiddenText!), + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: theme.weakTextColor, + ), + ), + )), + if (PlatformUtils().isMobile && + widget.showSendAudio && + widget.forbiddenText == null) + InkWell( + onTap: () async { + showKeyboard = showSendSoundText; + if (showSendSoundText) { + widget.focusNode.requestFocus(); + } + if (await Permissions.checkPermission( + context, + Permission.microphone.value, + theme, + )) { + setState(() { + showEmojiPanel = false; + showMore = false; + showSendSoundText = !showSendSoundText; + }); + } + }, + child: SvgPicture.asset( + showSendSoundText + ? 'images/keyboard.svg' + : 'images/voice.svg', + package: 'tencent_cloud_chat_uikit', + color: const Color.fromRGBO(68, 68, 68, 1), + height: 28, + width: 28, + ), ), - ), - )), - if (PlatformUtils().isMobile && - widget.showSendAudio && - widget.forbiddenText == null) - InkWell( - onTap: () async { - showKeyboard = showSendSoundText; - if (showSendSoundText) { - widget.focusNode.requestFocus(); - } - if (await Permissions.checkPermission( - context, - Permission.microphone.value, - theme, - )) { - setState(() { - showEmojiPanel = false; - showMore = false; - showSendSoundText = !showSendSoundText; - }); - } - }, - child: SvgPicture.asset( - showSendSoundText - ? 'images/keyboard.svg' - : 'images/voice.svg', - package: 'tencent_cloud_chat_uikit', - color: const Color.fromRGBO(68, 68, 68, 1), - height: 28, - width: 28, - ), - ), - if (widget.forbiddenText == null) - const SizedBox( - width: 10, - ), - if (widget.forbiddenText == null) - Expanded( - child: showSendSoundText - ? SendSoundMessage( - onDownBottom: widget.goDownBottom, - conversationID: widget.conversationID, - conversationType: widget.conversationType) - : KeyboardVisibility( - child: ExtendedTextField( - maxLines: 4, - minLines: 1, - focusNode: widget.focusNode, - onChanged: debounceFunc, - onTap: () { - showKeyboard = true; - widget.goDownBottom(); - setState(() { - showEmojiPanel = false; - showMore = false; - }); - }, - keyboardType: TextInputType.multiline, - textInputAction: PlatformUtils().isAndroid - ? TextInputAction.newline - : TextInputAction.send, - onEditingComplete: () { - widget.onSubmitted(); - if (showKeyboard) { - widget.focusNode.requestFocus(); - } - setState(() { - if (widget.textEditingController.text - .isEmpty) { - showMoreButton = true; - } - }); - }, - textAlignVertical: TextAlignVertical.top, - decoration: InputDecoration( - border: InputBorder.none, - hintStyle: const TextStyle( - // fontSize: 10, - color: Color(0xffAEA4A3), + if (widget.forbiddenText == null) + const SizedBox( + width: 10, + ), + Stack( + children: [ + Container( + width: 296.sp, + padding: EdgeInsets.symmetric( + vertical: 8, horizontal: 12.sp), + constraints: + const BoxConstraints(minHeight: 30), + decoration: BoxDecoration( + color: Color(0x1AFFFFFF), + borderRadius: BorderRadius.circular(26.sp), + ), + child: Row( + children: [ + if (widget.forbiddenText == null) + Expanded( + child: showSendSoundText + ? TIMSendSoundMessage( + onDownBottom: + widget.goDownBottom, + conversationID: + widget.conversationID, + conversationType: + widget.conversationType) + : KeyboardVisibility( + child: ExtendedTextField( + style: TextStyle( + color: Colors.white, + fontSize: 14.sp), + maxLines: 4, + minLines: 1, + focusNode: widget.focusNode, + onChanged: debounceFunc, + onTap: () { + showKeyboard = true; + widget.goDownBottom(); + setState(() { + showEmojiPanel = false; + showMore = false; + }); + }, + keyboardType: + TextInputType.multiline, + textInputAction: + PlatformUtils() + .isAndroid + ? TextInputAction + .newline + : TextInputAction + .send, + onEditingComplete: () { + widget.onSubmitted(); + if (showKeyboard) { + widget.focusNode + .requestFocus(); + } + setState(() { + if (widget + .textEditingController + .text + .isEmpty) { + showMoreButton = true; + } + }); + }, + textAlignVertical: + TextAlignVertical.top, + decoration: InputDecoration( + border: InputBorder.none, + hintStyle: TextStyle( + fontSize: 14.sp, + color: + Color(0xB3FFFFFF), + ), + hintText: widget.hintText, + fillColor: + Colors.transparent, + filled: true, + isDense: true, + ), + controller: widget + .textEditingController, + specialTextSpanBuilder: + PlatformUtils().isWeb + ? null + : DefaultSpecialTextSpanBuilder( + isUseDefaultEmoji: + widget + .isUseDefaultEmoji, + customEmojiStickerList: + widget + .customEmojiStickerList, + showAtBackground: + true, + )), + onChanged: (bool visibility) { + if (showKeyboard != + visibility) { + setState(() { + showKeyboard = visibility; + }); + } + }), + ), + if (widget.forbiddenText == null) + const SizedBox( + width: 10, + ), + if (widget.showSendEmoji && + widget.forbiddenText == null) + InkWell( + onTap: () { + _openEmojiPanel(); + widget.goDownBottom(); + }, + child: Image.asset( + getMsgImage('emoji'), + height: 24.sp, + width: 24.sp, ), - fillColor: Colors.white, - filled: true, - isDense: true, - hintText: widget.hintText ?? ''), - controller: widget.textEditingController, - specialTextSpanBuilder: PlatformUtils() - .isWeb - ? null - : DefaultSpecialTextSpanBuilder( - isUseDefaultEmoji: - widget.isUseDefaultEmoji, - customEmojiStickerList: - widget.customEmojiStickerList, - showAtBackground: true, - )), - onChanged: (bool visibility) { - if (showKeyboard != visibility) { - setState(() { - showKeyboard = visibility; - }); - } - }), - ), - if (widget.forbiddenText == null) - const SizedBox( - width: 10, - ), - if (widget.showSendEmoji && widget.forbiddenText == null) - InkWell( - onTap: () { - _openEmojiPanel(); - widget.goDownBottom(); - }, - child: PlatformUtils().isWeb - ? Icon( - showEmojiPanel - ? Icons.keyboard_alt_outlined - : Icons.mood_outlined, - color: hexToColor("5c6168"), - size: 32) - : SvgPicture.asset( - showEmojiPanel - ? 'images/keyboard.svg' - : 'images/face.svg', - package: 'tencent_cloud_chat_uikit', - color: const Color.fromRGBO(68, 68, 68, 1), - height: 28, - width: 28, - ), - ), - if (widget.forbiddenText == null) - const SizedBox( - width: 10, - ), - if (widget.showMorePanel && - widget.forbiddenText == null && - showMoreButton) - InkWell( - onTap: () { - // model.sendCustomMessage(data: "a", convID: model.currentSelectedConv, convType: model.currentSelectedConvType == 1 ? ConvType.c2c : ConvType.group); - _openMore(); - widget.goDownBottom(); - }, - child: PlatformUtils().isWeb - ? Icon(Icons.add_circle_outline_outlined, - color: hexToColor("5c6168"), size: 32) - : SvgPicture.asset( - 'images/add.svg', - package: 'tencent_cloud_chat_uikit', - color: const Color.fromRGBO(68, 68, 68, 1), - height: 28, - width: 28, - ), - ), - if ((isAndroidDevice() || isWebDevice()) && !showMoreButton) - SizedBox( - height: 32.0, - child: ElevatedButton( - onPressed: () { + ), + ], + )) + ], + ), + if (widget.forbiddenText == null) + const SizedBox( + width: 10, + ), + InkWell( + onTap: () { widget.onSubmitted(); if (showKeyboard) { widget.focusNode.requestFocus(); @@ -582,30 +607,167 @@ class _TIMUIKitTextFieldLayoutNarrowState } }); }, - child: Text(TIM_t("发送")), + child: Image.asset( + getMsgImage('send'), + height: 24.sp, + width: 24.sp, + ), ), - ), - ], - ), + ], + ), + ), + Container( + height: 40.sp, + width: Get.width, + // color: Colors.red, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + GestureDetector( + onTap: () async { + showKeyboard = showSendSoundText; + if (showSendSoundText) { + widget.focusNode.requestFocus(); + } + try { + var data = await Permission.microphone.status; + if (data.isGranted) { + setState(() { + showEmojiPanel = false; + showMore = false; + showSendSoundText = !showSendSoundText; + }); + } else { + var data = await Permission.microphone.request(); + if (data.isGranted) { + setState(() { + showEmojiPanel = false; + showMore = false; + showSendSoundText = !showSendSoundText; + }); + } else { + Permissions.showPermissionConfirmDialog(context, Permission.microphone.value); + } + } + } catch (e) { + print(e); + } + }, + child: Image.asset( + getMsgImage('voice'), + width: 40.sp, + ), + ), + GestureDetector( + onTap: () { + getImageFile(); + }, + child: + Image.asset(getMsgImage('photo'), width: 40.sp), + ), + GestureDetector( + onTap: () { + getTakeImageFile(); + }, + child: Image.asset(getMsgImage('take_photo'), + width: 40.sp), + ), + ], + ), + ), + AnimatedContainer( + duration: Duration( + milliseconds: + (showKeyboard && PlatformUtils().isAndroid) + ? 200 + : 340), + curve: Curves.fastOutSlowIn, + height: max(_getBottomHeight(), 0.0), + // child: ListView( + // physics: const NeverScrollableScrollPhysics(), + // children: [_getBottomContainer()], + // ), + ), + ], ), - AnimatedContainer( + ), + Positioned( + bottom: MediaQuery.of(context).padding.bottom + 20, + child: AnimatedContainer( duration: Duration( milliseconds: (showKeyboard && PlatformUtils().isAndroid) ? 200 : 340), curve: Curves.fastOutSlowIn, + width: Get.width, height: max(_getBottomHeight(), 0.0), child: ListView( physics: const NeverScrollableScrollPhysics(), - children: [ - _getBottomContainer() - ], + children: [_getBottomContainer()], ), ), - ], - ), + ) + ], ) ], ); } + + Future getImageFile() async { + try { + final XFile? pickedFile = await _picker.pickImage( + source: ImageSource.gallery, + ); + await widget.model.sendImageMessage( + imagePath: pickedFile!.path, + convID: widget.conversationID, + convType: widget.conversationType, + inputElement: context); + } catch (e) { + print(e); + // setState(() { + // _pickImageError = e; + // }); + } + } + + Future getTakeImageFile() async { + try { + final XFile? pickedFile = await _picker.pickImage( + source: ImageSource.camera, + ); + widget.model.sendImageMessage( + imagePath: pickedFile!.path, + convID: widget.conversationID, + convType: widget.conversationType, + inputElement: context); + } catch (e) {} + } + + _handleCameraAndMic() async { + // // 请求权限 + // Map permissions = await PermissionHandler().requestPermissions( + // [PermissionGroup.camera, PermissionGroup.microphone], + // ); + // + // //校验权限 + // if (permissions[PermissionGroup.camera] != PermissionStatus.granted) { + // print("无照相权限"); + // return false; + // } + // if (permissions[PermissionGroup.microphone] != PermissionStatus.granted) { + // print("无麦克风权限"); + // return false; + // } + // return true; + // } + // + // void _onVoiceCall() async { + // // await for camera and mic permissions before pushing video page + // if (await _handleCameraAndMic()) { + // navigatePushPage(this.context, + // new PageAVChatCallerStatefulWidget(Int64(this.sessionInfo.sessionId), this.sessionInfo.sessionName)); + // } + // } + } } diff --git a/circle_app/lib/app/chat/TIMUIKitChat/tim_uikit_chat.dart b/circle_app/lib/app/chat/TIMUIKitChat/tim_uikit_chat.dart index 3ac18ed..2a1f164 100644 --- a/circle_app/lib/app/chat/TIMUIKitChat/tim_uikit_chat.dart +++ b/circle_app/lib/app/chat/TIMUIKitChat/tim_uikit_chat.dart @@ -27,6 +27,8 @@ import 'TIMUIKItMessageList/tim_uikit_chat_history_message_list_config.dart'; import 'TIMUIKItMessageList/tim_uikit_history_message_list_container.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; +import 'TIMUIKitTextField/tim_uikit_text_field.dart'; + class TIMChat extends StatefulWidget { int startTime = 0; int endTime = 0; @@ -465,7 +467,7 @@ class _TUIChatState extends TIMUIKitState { ) : (widget.textFieldBuilder != null ? widget.textFieldBuilder!(context) - : TIMUIKitInputTextField( + : TIMInputTextField( key: inputTextFieldState, atMemberPanelScroll: atMemberPanelScroll, @@ -486,8 +488,7 @@ class _TUIChatState extends TIMUIKitState { scrollController: autoController, conversationID: _getConvID(), conversationType: _getConvType(), - initText: widget.draftText, - hintText: widget.textFieldHintText, + hintText: '最近心情怎么样?', showMorePanel: widget.config ?.isAllowShowMorePanel ?? true, diff --git a/circle_app/lib/app/chat/view.dart b/circle_app/lib/app/chat/view.dart index 1157560..6a6f205 100644 --- a/circle_app/lib/app/chat/view.dart +++ b/circle_app/lib/app/chat/view.dart @@ -44,6 +44,8 @@ class ChatPage extends StatelessWidget { )); }).toList(); return StickerPanel( + backgroundColor:Colors.transparent, + showBottomContainer: false, sendTextMsg: sendTextMessage, sendFaceMsg: (index, data) => sendFaceMessage(index + 1, (data.split("/")[3]).split("@")[0]), @@ -69,7 +71,7 @@ class ChatPage extends StatelessWidget { // 仅供演示,非全部配置项,实际使用中,可只传和默认项不同的参数,无需传入所有开关 isAllowClickAvatar: true, isUseDefaultEmoji: true, - isAllowLongPressMessage: true, + isAllowLongPressMessage: false, isShowReadingStatus: true, isShowGroupReadingStatus: true, notificationTitle: "", diff --git a/circle_app/lib/app/circle/view.dart b/circle_app/lib/app/circle/view.dart index 919e329..3cf6a3c 100644 --- a/circle_app/lib/app/circle/view.dart +++ b/circle_app/lib/app/circle/view.dart @@ -17,9 +17,11 @@ class CirclePage extends StatelessWidget { @override Widget build(BuildContext context) { return Container( + width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, decoration: BoxDecoration( + color: Color(0xFF423055), image: DecorationImage( fit: BoxFit.fill, image: AssetImage(getBaseImage('home_back')))), diff --git a/circle_app/lib/app/home/view.dart b/circle_app/lib/app/home/view.dart index 6000545..e5c99fd 100644 --- a/circle_app/lib/app/home/view.dart +++ b/circle_app/lib/app/home/view.dart @@ -39,6 +39,7 @@ class HomePage extends StatelessWidget { // color: Colors.red, padding: EdgeInsets.only(left: 50.sp, right: 50.sp, top: 8.sp), decoration: BoxDecoration( + color: Color(0xFF423055), image: DecorationImage( fit: BoxFit.fill, image: AssetImage( diff --git a/circle_app/lib/app/msg/view.dart b/circle_app/lib/app/msg/view.dart index cb036e8..a07366a 100644 --- a/circle_app/lib/app/msg/view.dart +++ b/circle_app/lib/app/msg/view.dart @@ -21,19 +21,18 @@ class MsgPage extends StatelessWidget { fit: BoxFit.fill, image: AssetImage(getBaseImage('home_back')))), child: Scaffold( + resizeToAvoidBottomInset:false, backgroundColor: Colors.transparent, body: SafeArea( child: GetBuilder(builder: (MsgLogic controller) { - return Container( - child: Column( - children: [ - navigatorItem(), - tipWidget(), - reconmandWidget(), - Text(controller.state.msg), - Expanded(child: msgWdiget(context)) - ], - ), + return Column( + children: [ + navigatorItem(), + tipWidget(), + reconmandWidget(), + Text(controller.state.msg), + Expanded(child: msgWdiget(context)) + ], ); }), ), diff --git a/circle_app/lib/main.dart b/circle_app/lib/main.dart index 7307b9b..df8479f 100644 --- a/circle_app/lib/main.dart +++ b/circle_app/lib/main.dart @@ -24,56 +24,71 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { // This widget is the root of your application. + final List _guideList = ['bg', 'home_back']; + final CoreServicesImpl _coreInstance = TIMUIKitCore.getInstance(); @override void initState() { initIM(); + loadBgImage(); super.initState(); } initIM() { _coreInstance.init( - sdkAppID: 1400793496, // Replace 0 with the SDKAppID of your IM application when integrating + sdkAppID: + 1400793496, // Replace 0 with the SDKAppID of your IM application when integrating // language: LanguageEnum.en, // 界面语言配置,若不配置,则跟随系统语言 loglevel: LogLevelEnum.V2TIM_LOG_DEBUG, - onTUIKitCallbackListener: (TIMCallback callbackValue){ - switch(callbackValue.type) { + onTUIKitCallbackListener: (TIMCallback callbackValue) { + switch (callbackValue.type) { case TIMCallbackType.INFO: - // Shows the recommend text for info callback directly + // Shows the recommend text for info callback directly showToast(callbackValue.infoRecommendText!); break; case TIMCallbackType.API_ERROR: - //Prints the API error to console, and shows the error message. - print("Error from TUIKit: ${callbackValue.errorMsg}, Code: ${callbackValue.errorCode}"); - if (callbackValue.errorCode == 10004 && callbackValue.errorMsg!.contains("not support @all")) { + //Prints the API error to console, and shows the error message. + print( + "Error from TUIKit: ${callbackValue.errorMsg}, Code: ${callbackValue.errorCode}"); + if (callbackValue.errorCode == 10004 && + callbackValue.errorMsg!.contains("not support @all")) { showToast("当前群组不支持@全体成员"); - }else{ - showToast(callbackValue.errorMsg ?? callbackValue.errorCode.toString()); + } else { + showToast(callbackValue.errorMsg ?? + callbackValue.errorCode.toString()); } break; case TIMCallbackType.FLUTTER_ERROR: default: - // prints the stack trace to console or shows the catch error - if(callbackValue.catchError != null){ + // prints the stack trace to console or shows the catch error + if (callbackValue.catchError != null) { showToast(callbackValue.catchError.toString()); - - }else{ + } else { print(callbackValue.stackTrace); // loginIM(); } } }, // [建议配置,详见此部分](https://cloud.tencent.com/document/product/269/70746#callback) - listener: V2TimSDKListener( - onConnectSuccess: () { - loginIM(); - } - )); + listener: V2TimSDKListener(onConnectSuccess: () { + loginIM(); + })); + } + + loadBgImage() async { + await precacheImage(precacheImages(_guideList.first),context); + await precacheImage(precacheImages(_guideList.last),context); + } + + precacheImages(String image) { + return AssetImage(getBaseImage(image)); } loginIM() async { - var info = await _coreInstance.login(userID: '123456', userSig: 'eJwtzEELgjAYxvHvsmshc25rCl40OlRIYaVX0RUvrTFsDFn03TP1*Pwe*H-Q5VgGTvYoQSTAaD1t6KS2cIeJQxJRxpfn3T0bY6BDSUgx3sQRjfn8yMFAL0dnjBGM8awWXn-jggtBY0qXCjzGcJ7tT4eVrHa6aG9FWfsms*rqK3cW2hulHKkHtzU2L9sUfX-YTTG5'); + var info = await _coreInstance.login( + userID: '123456', + userSig: + 'eJwtzEELgjAYxvHvsmshc25rCl40OlRIYaVX0RUvrTFsDFn03TP1*Pwe*H-Q5VgGTvYoQSTAaD1t6KS2cIeJQxJRxpfn3T0bY6BDSUgx3sQRjfn8yMFAL0dnjBGM8awWXn-jggtBY0qXCjzGcJ7tT4eVrHa6aG9FWfsms*rqK3cW2hulHKkHtzU2L9sUfX-YTTG5'); print(info); - } @override diff --git a/circle_app/pubspec.yaml b/circle_app/pubspec.yaml index 9e346e1..0d7f0d6 100644 --- a/circle_app/pubspec.yaml +++ b/circle_app/pubspec.yaml @@ -60,10 +60,12 @@ dependencies: dio: ^5.0.0 #获取设备信息 device_info: ^2.0.3 - + #本地数据缓存 shared_preferences: ^2.1.2 - + #集成腾讯IM包含UIKIT库 tencent_cloud_chat_uikit: ^2.0.0 + #权限申请 + permission_handler: ^10.3.0 dev_dependencies: flutter_test: