From 4377369230f7762eb6ea20be222df0dcc4334a60 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 3 Dec 2025 11:29:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=20=20=E5=8F=AA=E6=9C=89=E5=BD=95?= =?UTF-8?q?=E5=83=8F=E7=9A=84=E6=97=B6=E5=80=99=E6=89=8D=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E9=BA=A6=E5=85=8B=E9=A3=8E=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tim_uikit_more_panel.dart | 173 +++++++++++++----- pubspec.lock | 20 +- 2 files changed, 133 insertions(+), 60 deletions(-) diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_more_panel.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_more_panel.dart index 3cd3e31..419df81 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_more_panel.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_more_panel.dart @@ -72,7 +72,8 @@ class MorePanelItem { final Widget icon; final Function(BuildContext context)? onTap; - MorePanelItem({this.onTap, required this.icon, required this.id, required this.title}); + MorePanelItem( + {this.onTap, required this.icon, required this.id, required this.title}); } class MorePanel extends StatefulWidget { @@ -99,7 +100,8 @@ class MorePanel extends StatefulWidget { class _MorePanelState extends TIMUIKitState { final ImagePicker _picker = ImagePicker(); - final TUISelfInfoViewModel _selfInfoViewModel = serviceLocator(); + final TUISelfInfoViewModel _selfInfoViewModel = + serviceLocator(); Uint8List? fileContent; String? fileName; File? tempFile; @@ -120,7 +122,8 @@ class _MorePanelState extends TIMUIKitState { isInstallCallkit = value; }); }); - _betterPlayerController = BetterPlayerController(const BetterPlayerConfiguration()); + _betterPlayerController = + BetterPlayerController(const BetterPlayerConfiguration()); } } @@ -205,12 +208,12 @@ class _MorePanelState extends TIMUIKitState { colorFilter: const ColorFilter.mode( Color(0xFF606060), BlendMode.srcIn), ), - // Image.asset( - // "images/take_video.png", - // package: 'tencent_cloud_chat_uikit', - // height: 64, - // width: 64, - // ), + // Image.asset( + // "images/take_video.png", + // package: 'tencent_cloud_chat_uikit', + // height: 64, + // width: 64, + // ), ), )), if (PlatformUtils().isWeb) @@ -387,9 +390,11 @@ class _MorePanelState extends TIMUIKitState { }).toList(); } - _sendVideoMessage(String originFilePath, int duration, int size, TUIChatSeparateViewModel model) async { + _sendVideoMessage(String originFilePath, int duration, int size, + TUIChatSeparateViewModel model) async { if (size >= MorePanelConfig.VIDEO_MAX_SIZE) { - onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("文件大小超出了限制"))); + onTIMCallback(TIMCallback( + type: TIMCallbackType.INFO, infoRecommendText: TIM_t("文件大小超出了限制"))); return; } @@ -398,7 +403,9 @@ class _MorePanelState extends TIMUIKitState { final convID = widget.conversationID; final convType = widget.conversationType; - String tempPath = (await getTemporaryDirectory()).path + p.basename(originFilePath) + ".jpeg"; + String tempPath = (await getTemporaryDirectory()).path + + p.basename(originFilePath) + + ".jpeg"; await plugin.getVideoThumbnail( srcFile: originFilePath, @@ -410,7 +417,11 @@ class _MorePanelState extends TIMUIKitState { ); MessageUtils.handleMessageError( model.sendVideoMessage( - videoPath: originFilePath, duration: duration, snapshotPath: tempPath, convID: convID, convType: convType), + videoPath: originFilePath, + duration: duration, + snapshotPath: tempPath, + convID: convID, + convType: convType), context); } @@ -426,7 +437,7 @@ class _MorePanelState extends TIMUIKitState { Permission.manageExternalStorage.value, theme, ); - + if (!manageExternalStorage) { // 如果没有管理外部存储权限,则检查媒体权限 final videos = await Permissions.checkPermission( @@ -480,34 +491,47 @@ class _MorePanelState extends TIMUIKitState { if (filePath != null) { if (type == AssetType.image) { if (size >= MorePanelConfig.IMAGE_MAX_SIZE) { - onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("文件大小超出了限制"))); + onTIMCallback(TIMCallback( + type: TIMCallbackType.INFO, + infoRecommendText: TIM_t("文件大小超出了限制"))); return; } MessageUtils.handleMessageError( - model.sendImageMessage(imagePath: filePath, convID: convID, convType: convType), context); + model.sendImageMessage( + imagePath: filePath, + convID: convID, + convType: convType), + context); } if (type == AssetType.video) { - _sendVideoMessage(originFile!.path, asset.videoDuration.inSeconds, size, model); + _sendVideoMessage(originFile!.path, + asset.videoDuration.inSeconds, size, model); } } } } } else { - FilePickerResult? result = await FilePicker.platform.pickFiles(type: FileType.media); + FilePickerResult? result = + await FilePicker.platform.pickFiles(type: FileType.media); if (result != null && result.files.isNotEmpty) { File file = File(result.files.single.path!); final String savePath = file.path; - final String type = - TencentUtils.getFileType(savePath.split(".")[savePath.split(".").length - 1]).split("/")[0]; + final String type = TencentUtils.getFileType( + savePath.split(".")[savePath.split(".").length - 1]) + .split("/")[0]; if (type == "image") { MessageUtils.handleMessageError( - model.sendImageMessage(imagePath: savePath, convID: convID, convType: convType), context); + model.sendImageMessage( + imagePath: savePath, convID: convID, convType: convType), + context); } else if (type == "video") { MessageUtils.handleMessageError( - model.sendVideoMessage(videoPath: savePath, convID: convID, convType: convType), context); + model.sendVideoMessage( + videoPath: savePath, convID: convID, convType: convType), + context); } } else { throw TypeError(); @@ -518,7 +542,8 @@ class _MorePanelState extends TIMUIKitState { } } - _sendImageFromCamera(TUIChatSeparateViewModel model, TUITheme theme, {required isVideo}) async { + _sendImageFromCamera(TUIChatSeparateViewModel model, TUITheme theme, + {required isVideo}) async { try { if (!await Permissions.checkPermission( context, @@ -527,11 +552,17 @@ class _MorePanelState extends TIMUIKitState { )) { return; } - await Permissions.checkPermission( - context, - Permission.microphone.value, - theme, - ); + + // 只有录像时才需要麦克风权限 + if (isVideo) { + if (!await Permissions.checkPermission( + context, + Permission.microphone.value, + theme, + )) { + return; + } + } final convID = widget.conversationID; final convType = widget.conversationType; @@ -545,18 +576,25 @@ class _MorePanelState extends TIMUIKitState { final size = await originFile!.length(); if (!isVideo) { if (size >= MorePanelConfig.IMAGE_MAX_SIZE) { - onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("文件大小超出了限制"))); + onTIMCallback(TIMCallback( + type: TIMCallbackType.INFO, + infoRecommendText: TIM_t("文件大小超出了限制"))); return; } MessageUtils.handleMessageError( - model.sendImageMessage(imagePath: originFile.path, convID: convID, convType: convType), context); + model.sendImageMessage( + imagePath: originFile.path, convID: convID, convType: convType), + context); } else { // 监听视频准备完成事件 _betterPlayerController.addEventsListener((event) { - if (event.betterPlayerEventType == BetterPlayerEventType.initialized) { + if (event.betterPlayerEventType == + BetterPlayerEventType.initialized) { // 获取视频时长(单位:秒) - int durationInSeconds = _betterPlayerController.videoPlayerController?.value.duration?.inSeconds ?? 0; + int durationInSeconds = _betterPlayerController + .videoPlayerController?.value.duration?.inSeconds ?? + 0; _sendVideoMessage(originFile!.path, durationInSeconds, size, model); } }); @@ -583,12 +621,17 @@ class _MorePanelState extends TIMUIKitState { fileContent = imageContent; html.Node? inputElem; - inputElem = html.document.getElementById("__image_picker_web-file-input")?.querySelector("input"); + inputElem = html.document + .getElementById("__image_picker_web-file-input") + ?.querySelector("input"); final convID = widget.conversationID; final convType = widget.conversationType; MessageUtils.handleMessageError( model.sendImageMessage( - inputElement: inputElem, imagePath: tempFile?.path, convID: convID, convType: convType), + inputElement: inputElem, + imagePath: tempFile?.path, + convID: convID, + convType: convType), context); } catch (e) { outputLogger.i("_sendFileErr: ${e.toString()}"); @@ -604,18 +647,25 @@ class _MorePanelState extends TIMUIKitState { fileContent = videoContent; if (fileName!.split(".")[fileName!.split(".").length - 1] != "mp4") { - onTIMCallback( - TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频消息仅限 mp4 格式"), infoCode: 6660412)); + onTIMCallback(TIMCallback( + type: TIMCallbackType.INFO, + infoRecommendText: TIM_t("视频消息仅限 mp4 格式"), + infoCode: 6660412)); return; } html.Node? inputElem; - inputElem = html.document.getElementById("__image_picker_web-file-input")?.querySelector("input"); + inputElem = html.document + .getElementById("__image_picker_web-file-input") + ?.querySelector("input"); final convID = widget.conversationID; final convType = widget.conversationType; MessageUtils.handleMessageError( model.sendVideoMessage( - inputElement: inputElem, videoPath: tempFile?.path, convID: convID, convType: convType), + inputElement: inputElem, + videoPath: tempFile?.path, + convID: convID, + convType: convType), context); } catch (e) { outputLogger.i("_sendFileErr: ${e.toString()}"); @@ -633,29 +683,43 @@ class _MorePanelState extends TIMUIKitState { if (result != null && result.files.isNotEmpty) { if (PlatformUtils().isWeb) { html.Node? inputElem; - inputElem = html.document.getElementById("__file_picker_web-file-input")?.querySelector("input"); + inputElem = html.document + .getElementById("__file_picker_web-file-input") + ?.querySelector("input"); fileName = result.files.single.name; MessageUtils.handleMessageError( - model.sendFileMessage(inputElement: inputElem, fileName: fileName, convID: convID, convType: convType), + model.sendFileMessage( + inputElement: inputElem, + fileName: fileName, + convID: convID, + convType: convType), context); return; } String? option2 = result.files.single.path ?? ""; - outputLogger.i(TIM_t_para("选择成功{{option2}}", "选择成功$option2")(option2: option2)); + outputLogger + .i(TIM_t_para("选择成功{{option2}}", "选择成功$option2")(option2: option2)); File file = File(result.files.single.path!); final int size = file.lengthSync(); if (size >= MorePanelConfig.FILE_MAX_SIZE) { - onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("文件大小超出了限制"))); + onTIMCallback(TIMCallback( + type: TIMCallbackType.INFO, + infoRecommendText: TIM_t("文件大小超出了限制"))); return; } final String savePath = file.path; MessageUtils.handleMessageError( - model.sendFileMessage(filePath: savePath, size: size, convID: convID, convType: convType), context); + model.sendFileMessage( + filePath: savePath, + size: size, + convID: convID, + convType: convType), + context); } else { throw TypeError(); } @@ -705,13 +769,16 @@ class _MorePanelState extends TIMUIKitState { bool hasCameraPermission = false; bool hasMicrophonePermission = false; if (type == TYPE_VIDEO) { - hasCameraPermission = await Permissions.checkPermission(context, Permission.camera.value); - hasMicrophonePermission = await Permissions.checkPermission(context, Permission.microphone.value); + hasCameraPermission = + await Permissions.checkPermission(context, Permission.camera.value); + hasMicrophonePermission = await Permissions.checkPermission( + context, Permission.microphone.value); if (!hasCameraPermission || !hasMicrophonePermission) { return; } } else { - hasMicrophonePermission = await Permissions.checkPermission(context, Permission.microphone.value); + hasMicrophonePermission = await Permissions.checkPermission( + context, Permission.microphone.value); if (!hasMicrophonePermission) { return; } @@ -733,7 +800,9 @@ class _MorePanelState extends TIMUIKitState { _tUICore.callService(TUICALLKIT_SERVICE_NAME, METHOD_NAME_CALL, { PARAM_NAME_TYPE: type, PARAM_NAME_USERIDS: inviteMember, - PARAM_NAME_GROUPID: widget.conversationType == ConvType.group ? widget.conversationID : "" + PARAM_NAME_GROUPID: widget.conversationType == ConvType.group + ? widget.conversationID + : "" }); } } else { @@ -754,7 +823,8 @@ class _MorePanelState extends TIMUIKitState { @override Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { final TUITheme theme = value.theme; - final TUIChatSeparateViewModel model = Provider.of(context); + final TUIChatSeparateViewModel model = + Provider.of(context); final screenWidth = MediaQuery.of(context).size.width; final items = itemList(model, theme); final double panelHeight = items.length > 4 ? 248.0 : 120; @@ -798,12 +868,15 @@ class _MorePanelState extends TIMUIKitState { height: 64, width: 64, margin: const EdgeInsets.only(bottom: 4), - decoration: const BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(5))), + decoration: const BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(5))), child: item.icon, ), Text( item.title, - style: TextStyle(fontSize: 12, color: theme.darkTextColor), + style: TextStyle( + fontSize: 12, color: theme.darkTextColor), ) ], ), diff --git a/pubspec.lock b/pubspec.lock index aac9f4e..d48acc2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -964,18 +964,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d url: "https://pub.flutter-io.cn" source: hosted - version: "8.3.0" + version: "9.0.0" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" url: "https://pub.flutter-io.cn" source: hosted - version: "3.2.0" + version: "3.2.1" pasteboard: dependency: "direct main" description: @@ -1577,10 +1577,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.4" + version: "2.2.0" video_player: dependency: "direct main" description: @@ -1633,18 +1633,18 @@ packages: dependency: transitive description: name: wakelock_plus - sha256: a474e314c3e8fb5adef1f9ae2d247e57467ad557fa7483a2b895bc1b421c5678 + sha256: "9296d40c9adbedaba95d1e704f4e0b434be446e2792948d0e4aa977048104228" url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.2" + version: "1.4.0" wakelock_plus_platform_interface: dependency: transitive description: name: wakelock_plus_platform_interface - sha256: e10444072e50dbc4999d7316fd303f7ea53d31c824aa5eb05d7ccbdd98985207 + sha256: "036deb14cd62f558ca3b73006d52ce049fabcdcb2eddfe0bf0fe4e8a943b5cf2" url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.3" + version: "1.3.0" watcher: dependency: transitive description: