From 2fefab6196f4598fd209da11de62f63bcc80f140 Mon Sep 17 00:00:00 2001 From: anonymous Date: Wed, 19 Jul 2023 18:43:28 +0800 Subject: [PATCH] Upgrade UIKit to 2.1.3+1 --- CHANGELOG.md | 25 + README.md | 37 ++ .../flutter/generated_plugin_registrant.cc | 4 + example/linux/flutter/generated_plugins.cmake | 1 + .../Flutter/GeneratedPluginRegistrant.swift | 2 + example/pubspec.lock | 448 ++++++++++-------- .../flutter/generated_plugin_registrant.cc | 3 + .../windows/flutter/generated_plugins.cmake | 1 + .../life_cycle/base_life_cycle.dart | 11 +- .../life_cycle/block_list_life_cycle.dart | 2 +- .../life_cycle/chat_life_cycle.dart | 14 +- .../life_cycle/conversation_life_cycle.dart | 4 +- .../life_cycle/new_contact_life_cycle.dart | 4 +- .../life_cycle/profile_life_cycle.dart | 8 +- .../separate_models/tui_chat_model_tools.dart | 11 + .../tui_chat_separate_view_model.dart | 97 ++-- .../view_models/tui_chat_global_model.dart | 273 +++++++---- .../tui_conversation_view_model.dart | 4 +- .../core/core_services_implements.dart | 128 +++-- .../group/group_services_implement.dart | 1 - lib/i18n/strings.i18n.json | 2 +- lib/i18n/strings_zh-Hans.i18n.json | 10 +- lib/i18n/strings_zh-Hant.i18n.json | 2 +- .../controller/tim_uikit_chat_controller.dart | 38 +- lib/ui/utils/time_ago.dart | 2 +- ..._uikit_chat_history_message_list_item.dart | 4 +- .../tim_uikit_chat_message_tooltip.dart | 64 ++- .../TIMUIKitAppBar/tim_uikit_appbar.dart | 1 - .../tim_uikit_appbar_title.dart | 2 +- .../tim_uikit_chat_file_elem.dart | 326 +++++++------ .../tim_uikit_chat_image_elem.dart | 219 +++++---- .../tim_uikit_chat_video_elem.dart | 45 +- .../tim_uikit_more_panel.dart | 9 +- .../tim_uikit_text_field.dart | 84 +++- .../tim_uikit_text_field_layout/wide.dart | 29 +- lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart | 355 +++++++------- .../TIMUIKitChat/tim_uikit_chat_config.dart | 8 + .../TIMUIKitChat/tim_uikit_send_file.dart | 50 +- lib/ui/widgets/forward_message_screen.dart | 35 +- lib/ui/widgets/image_screen.dart | 211 ++++----- lib/ui/widgets/merger_message_screen.dart | 18 +- lib/ui/widgets/video_screen.dart | 228 +++++---- lib/ui/widgets/wide_popup.dart | 150 +++++- pubspec.lock | 358 ++++++++------ pubspec.yaml | 10 +- 45 files changed, 2010 insertions(+), 1328 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 737c29b..34b6624 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +## 2.1.3+1 + +### New Features + +* Introduced [a new custom internationalization language scheme](https://www.tencentcloud.com/document/product/1047/52154?from=pub) that supports adding language packs, adding or modifying entries, and makes customizing i18n more accessible. This feature helps your app achieve a more convenient globalization process and easier customer acquisition worldwide. +* Provided a seamless experience for previewing large images and playing videos within desktop environments (applications and web) by avoiding frequent page transitions. Enhanced the user experience for image previews and video playback. Please note that video playback is currently supported only on the web and not in desktop applications. +* Supported to integrate with the new online customer service plugin (tencent_cloud_chat_customer_service_plugin). +* Added two new life cycle hooks, `messageDidSend` and `messageShouldMount` to `ChatLifeCycle`. + +### Improvements + +* Optimized the usage, interface, and interaction of the sticker panel. +* Enhanced mobile video playback interaction and UI. +* Refined the error prompt when sending a 0 KB file fails. +* Enabled users to close modals on desktop by clicking the bottom gray overlay area. +* Improved the UI and interaction of image and video messages in the message list. +* Added the ability to open self-sent file messages without downloading. +* Optimized the download status animation of file messages on the web. + +### Bug Fixes + +* Fixed an issue preventing mobile image previews from being dragged after zooming. +* Resolved an issue that might cause the message selection status not to be removed after canceling a message forward action. +* Addressed an issue that might cause the microphone usage not to end after sending a voice message, which means the microphone was not released. + ## 2.1.2 ### New Features diff --git a/README.md b/README.md index 86273a6..56e2d57 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,41 @@ +
diff --git a/example/linux/flutter/generated_plugin_registrant.cc b/example/linux/flutter/generated_plugin_registrant.cc index 2e68889..681dc9c 100644 --- a/example/linux/flutter/generated_plugin_registrant.cc +++ b/example/linux/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -18,6 +19,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) desktop_drop_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin"); desktop_drop_plugin_register_with_registrar(desktop_drop_registrar); + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) pasteboard_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); pasteboard_plugin_register_with_registrar(pasteboard_registrar); diff --git a/example/linux/flutter/generated_plugins.cmake b/example/linux/flutter/generated_plugins.cmake index fa2eba0..2c433ef 100644 --- a/example/linux/flutter/generated_plugins.cmake +++ b/example/linux/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux desktop_drop + file_selector_linux pasteboard url_launcher_linux ) diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 05deca4..7913e42 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,6 +9,7 @@ import audioplayers_darwin import desktop_drop import device_info_plus import fc_native_video_thumbnail +import file_selector_macos import package_info_plus import pasteboard import path_provider_foundation @@ -22,6 +23,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FcNativeVideoThumbnailPlugin.register(with: registry.registrar(forPlugin: "FcNativeVideoThumbnailPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/example/pubspec.lock b/example/pubspec.lock index fcb29e1..88fe6bd 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0c80aeab9bc807ab10022cd3b2f4cf2ecdf231949dc1ddd9442406a003f19201" + sha256: "0816708f5fbcacca324d811297153fe3c8e047beb5c6752e12292d2974c17045" url: "https://pub.dev" source: hosted - version: "52.0.0" + version: "62.0.0" adaptive_action_sheet: dependency: transitive description: @@ -21,26 +21,26 @@ packages: dependency: transitive description: name: analyzer - sha256: cd8ee83568a77f3ae6b913a36093a1c9b1264e7cb7f834d9ddd2311dade9c1f4 + sha256: "21862995c9932cd082f89d72ae5f5e2c110d1a0204ad06e4ebaee8307b76b834" url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "6.0.0" archive: dependency: "direct main" description: name: archive - sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" url: "https://pub.dev" source: hosted - version: "3.3.6" + version: "3.3.7" args: dependency: transitive description: name: args - sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611" + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.2" async: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: build - sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.1" cached_network_image: dependency: transitive description: @@ -157,42 +157,42 @@ packages: dependency: transitive description: name: camera - sha256: e7ac55af24a890d20276821eb3c95857074d03b7de6f9892b99a205ee30bd179 + sha256: ebebead3d5ec3d148249331d751d462d7e8c98102b8830a9b45ec96a2bd4333f url: "https://pub.dev" source: hosted - version: "0.10.3" + version: "0.10.5+2" camera_android: dependency: transitive description: name: camera_android - sha256: "4cef01e8e78fe27c809a429bf74352ab94ab76b0c980e3ec708f1414614e3d9f" + sha256: f43d07f9d7228ea1ca87d22e30881bd68da4b78484a1fbd1f1408b412a41cefb url: "https://pub.dev" source: hosted - version: "0.10.3" + version: "0.10.8+3" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "6a68c20593d4cd58974d555f74a48b244f9db28cc9156de57781122d11b8754b" + sha256: "1a416e452b30955b392f4efbf23291d3f2ba3660a85e1628859eb62d2a2bab26" url: "https://pub.dev" source: hosted - version: "0.9.11" + version: "0.9.13+2" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: "0eedd642d905ca24f1c483fe9ea0d0e7287b86a402845c28d24df28cc7b0ee6e" + sha256: "60fa0bb62a4f3bf3a7c413e31e4cd01b69c779ccc8e4668904a24581b86c316b" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.5.1" camera_web: dependency: transitive description: name: camera_web - sha256: "496de93c5d462738ce991dbfe91fb19026f115ed36406700a20a380fb0018299" + sha256: bcbd775fb3a9d51cc3ece899d54ad66f6306410556bac5759f78e13f9228841f url: "https://pub.dev" source: hosted - version: "0.3.1+1" + version: "0.3.1+4" characters: dependency: transitive description: @@ -253,10 +253,10 @@ packages: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" csslib: dependency: transitive description: @@ -269,10 +269,10 @@ packages: dependency: transitive description: name: csv - sha256: "18aef53ab72181a0b5384562d18c8cbd57e941e24cb8e54eb41409d3d8abdc6d" + sha256: "016b31a51a913744a0a1655c74ff13c9379e1200e246a03d96c81c5d9ed297b5" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "5.0.2" cupertino_icons: dependency: "direct main" description: @@ -281,6 +281,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + dart_internal: + dependency: transitive + description: + name: dart_internal + sha256: dae3976f383beddcfcd07ad5291a422df2c8c0a8a03c52cda63ac7b4f26e0f4e + url: "https://pub.dev" + source: hosted + version: "0.2.8" desktop_drop: dependency: transitive description: @@ -333,34 +341,34 @@ packages: dependency: transitive description: name: extended_image_library - sha256: b1de389378589e4dffb3564d782373238f19064037458092c49b3043b2791b2b + sha256: af3ff1c09c23ca7663f94272313d63499a6bd19121e99378e375e0cf2ac7a3e4 url: "https://pub.dev" source: hosted - version: "3.4.1" + version: "3.5.2" extended_text: dependency: transitive description: name: extended_text - sha256: "75ddf28ce7d5be33a050ff2179b6567b4b98e6225ad3e61e4c3748f7448c25f7" + sha256: dec14c9b36d9bbaaf007da5998f5dc72a2dbd5b877601d7b7970bb42524b3ced url: "https://pub.dev" source: hosted - version: "11.0.0" + version: "11.0.1" extended_text_field: dependency: transitive description: name: extended_text_field - sha256: "6cf8c090de4dc1e309cf3b24cb9448d7463c6c17926b628cf0954631bf4e56db" + sha256: e93248bb9b04a3e6c5e88a6a96e1c08cc765097657ab25aabe409e06a4f6760a url: "https://pub.dev" source: hosted - version: "12.0.0" + version: "12.0.1" extended_text_library: dependency: transitive description: name: extended_text_library - sha256: "308b50cfcc8e3accf46a09cb692715fbd1097333817c15b0f7527de1766bc1ff" + sha256: c06fbd8e3b6eedadf50cd6c109bbbd80921a6c43e4422d3b4ec9d4cb36ce4555 url: "https://pub.dev" source: hosted - version: "11.0.1" + version: "11.0.2" fake_async: dependency: transitive description: @@ -389,10 +397,10 @@ packages: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" file: dependency: transitive description: @@ -405,10 +413,42 @@ packages: dependency: transitive description: name: file_picker - sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf" + sha256: b1729fc96627dd44012d0a901558177418818d6bd428df59dcfeb594e5f66432 url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "5.3.2" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046" + url: "https://pub.dev" + source: hosted + version: "0.9.2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "7a6f1ae6107265664f3f7f89a66074882c4d506aef1441c9af313c1f7e6f41ce" + url: "https://pub.dev" + source: hosted + version: "0.9.3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26" + url: "https://pub.dev" + source: hosted + version: "0.9.3" file_utils: dependency: transitive description: @@ -434,10 +474,10 @@ packages: dependency: transitive description: name: flutter_cache_manager - sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3" + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.3.1" flutter_easyrefresh: dependency: transitive description: @@ -466,10 +506,10 @@ packages: dependency: transitive description: name: flutter_markdown - sha256: dc6d5258653f6857135b32896ccda7f7af0c54dcec832495ad6835154c6c77c0 + sha256: "4b1bfbb802d76320a1a46d9ce984106135093efd9d969765d07c2125af107bdf" url: "https://pub.dev" source: hosted - version: "0.6.15" + version: "0.6.17" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -498,10 +538,10 @@ packages: dependency: transitive description: name: flutter_svg - sha256: "6ff8c902c8056af9736de2689f63f81c42e2d642b9f4c79dbf8790ae48b63012" + sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.0.7" flutter_test: dependency: "direct dev" description: flutter @@ -516,18 +556,18 @@ packages: dependency: transitive description: name: get_it - sha256: "290fde3a86072e4b37dbb03c07bec6126f0ecc28dad403c12ffe2e5a2d751ab7" + sha256: "529de303c739fca98cd7ece5fca500d8ff89649f1bb4b4e94fb20954abcd7468" url: "https://pub.dev" source: hosted - version: "7.2.0" + version: "7.6.0" glob: dependency: transitive description: name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" globbing: dependency: transitive description: @@ -540,26 +580,26 @@ packages: dependency: transitive description: name: html - sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" url: "https://pub.dev" source: hosted - version: "0.15.1" + version: "0.15.4" http: dependency: transitive description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "0.13.6" http_client_helper: dependency: transitive description: name: http_client_helper - sha256: "1f32359bd07a064ad256d1f84ae5f973f69bc972e7287223fa198abe1d969c28" + sha256: "14c6e756644339f561321dab021215475ba4779aa962466f59ccb3ecf66b36c3" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" http_parser: dependency: transitive description: @@ -572,50 +612,74 @@ packages: dependency: transitive description: name: image_gallery_saver - sha256: "009b7722cd8507fd72c7f2cb7cbc46d6e15ad0895469cfcc39a10f86e3556979" + sha256: "0aba74216a4d9b0561510cb968015d56b701ba1bd94aace26aacdd8ae5761816" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" image_picker: dependency: transitive description: name: image_picker - sha256: f98d76672d309c8b7030c323b3394669e122d52b307d2bbd8d06bd70f5b2aabe + sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c url: "https://pub.dev" source: hosted - version: "0.8.6+1" + version: "0.8.9" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: b1cbfec0f5aef427a18eb573f5445af8c9c568626bf3388553e40c263d3f7368 + sha256: d2bab152deb2547ea6f53d82ebca9b7e77386bb706e5789e815d37e08ea475bb url: "https://pub.dev" source: hosted - version: "0.8.5+5" + version: "0.8.7+3" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "7d319fb74955ca46d9bf7011497860e3923bb67feebcf068f489311065863899" + sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" url: "https://pub.dev" source: hosted - version: "2.1.10" + version: "2.2.0" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "39c013200046d14c58b71dc4fa3d00e425fc9c699d589136cd3ca018727c0493" + sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b url: "https://pub.dev" source: hosted - version: "0.8.6+6" + version: "0.8.8" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4 + url: "https://pub.dev" + source: hosted + version: "0.2.1" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "7cef2f28f4f2fef99180f636c3d446b4ccbafd6ba0fad2adc9a80c4040f656b8" + sha256: "7c7b96bb9413a9c28229e717e6fd1e3edd1cc5569c1778fcca060ecf729b65ee" url: "https://pub.dev" source: hosted - version: "2.6.2" + version: "2.8.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952 + url: "https://pub.dev" + source: hosted + version: "0.2.1" intl: dependency: transitive description: @@ -636,10 +700,10 @@ packages: dependency: transitive description: name: json_annotation - sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.8.1" link_preview_generator: dependency: transitive description: @@ -668,10 +732,10 @@ packages: dependency: transitive description: name: logging - sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" lpinyin: dependency: transitive description: @@ -712,6 +776,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + mime: + dependency: transitive + description: + name: mime + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + url: "https://pub.dev" + source: hosted + version: "1.0.4" mime_type: dependency: transitive description: @@ -796,98 +868,90 @@ packages: dependency: transitive description: name: path_provider - sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.0.15" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" url: "https://pub.dev" source: hosted - version: "2.0.22" + version: "2.0.27" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" + sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.3" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.11" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.6" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" url: "https://pub.dev" source: hosted - version: "2.1.6" - pedantic: - dependency: transitive - description: - name: pedantic - sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" - url: "https://pub.dev" - source: hosted - version: "1.11.1" + version: "2.1.7" permission_handler: dependency: transitive description: name: permission_handler - sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" + sha256: "415af30ba76a84faccfe1eb251fe1e4fdc790f876924c65ad7d6ed7a1404bcd6" url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.4.2" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2" + sha256: "3b61f3da3b1c83bc3fb6a2b431e8dab01d0e5b45f6a3d9c7609770ec88b2a89e" url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.3.0" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163" + sha256: "7a187b671a39919462af2b5e813148365b71a615979165a119868d667fe90c03" url: "https://pub.dev" source: hosted - version: "9.0.7" + version: "9.1.3" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + sha256: "463a07cb7cc6c758a7a1c7da36ce666bb80a0b4b5e92df0fa36872e0ed456993" url: "https://pub.dev" source: hosted - version: "3.9.0" + version: "3.11.1" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b + sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098 url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "0.1.3" petitparser: dependency: transitive description: @@ -924,10 +988,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" url: "https://pub.dev" source: hosted - version: "3.6.2" + version: "3.7.3" process: dependency: transitive description: @@ -948,10 +1012,10 @@ packages: dependency: transitive description: name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" quiver: dependency: transitive description: @@ -988,58 +1052,58 @@ packages: dependency: transitive description: name: shared_preferences - sha256: "5949029e70abe87f75cfe59d17bf5c397619c4b74a099b10116baeb34786fad9" + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.2.0" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "955e9736a12ba776bdd261cf030232b30eadfcd9c79b32a3250dd4a494e8c8f7" + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.2.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "2b55c18636a4edc529fa5cd44c03d3f3100c00513f518c5127c951978efcccd0" + sha256: b046999bf0ff58f04c364491bb803dcfa8f42e47b19c75478f53d323684a8cc1 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: f8ea038aa6da37090093974ebdcf4397010605fd2ff65c37a66f9d28394cb874 + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: da9431745ede5ece47bc26d5d73a9d3c6936ef6945c101a5aca46f62e52c1cf3 + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.3.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: a4b5bc37fe1b368bbc81f953197d55e12f49d0296e7e412dfe2d2d77d6929958 + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" url: "https://pub.dev" source: hosted - version: "2.0.4" + version: "2.2.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "5eaf05ae77658d3521d0e993ede1af962d4b326cd2153d312df716dc250f00c9" + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.0" shell: dependency: transitive description: @@ -1065,18 +1129,18 @@ packages: dependency: transitive description: name: sqflite - sha256: "78324387dc81df14f78df06019175a86a2ee0437624166c382e145d0a7fd9a4f" + sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9 url: "https://pub.dev" source: hosted - version: "2.2.4+1" + version: "2.2.8+4" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: bfd6973aaeeb93475bc0d875ac9aefddf7965ef22ce09790eb963992ffc5183f + sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f" url: "https://pub.dev" source: hosted - version: "2.4.2+2" + version: "2.4.5+1" stack_trace: dependency: transitive description: @@ -1113,10 +1177,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b" + sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.1.0" system_info2: dependency: transitive description: @@ -1125,6 +1189,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.4" + tencent_chat_i18n_tool: + dependency: transitive + description: + name: tencent_chat_i18n_tool + sha256: ac8171d2574ed18babedd0cb67e937e255bf02fcb72f55408d033f74d4b11949 + url: "https://pub.dev" + source: hosted + version: "2.1.3+2" tencent_cloud_chat_sdk: dependency: transitive description: @@ -1139,23 +1211,23 @@ packages: path: ".." relative: true source: path - version: "2.1.2" + version: "2.1.3-preview.16" tencent_cloud_uikit_core: dependency: transitive description: name: tencent_cloud_uikit_core - sha256: "517d760b0d497ea291d70fe6a021508e5b66f0754c72679f19ee16c0bb354e91" + sha256: "0a0f43e4c4241b25d12a9e9f0ee91922ac800a42229d97e3d21d16041ace3104" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.8" tencent_im_base: dependency: transitive description: name: tencent_im_base - sha256: "9b8e712bf27ffae9b686ec532ee8417b8263eba8bab04f105e28a95de1807322" + sha256: "0db83050452486571ee4ac07280a2fb4bbc07d297a54235b5cf12e46e79267d0" url: "https://pub.dev" source: hosted - version: "1.0.57" + version: "2.0.1" tencent_im_sdk_plugin_desktop: dependency: "direct main" description: @@ -1168,18 +1240,18 @@ packages: dependency: transitive description: name: tencent_im_sdk_plugin_platform_interface - sha256: "53263e4acd7179871aad2a67ec4964bc8fae861f54384fba2c60bd2c16d2867c" + sha256: "6a1f053567246148ad40667f2ab71d82bcee0d5d0c12e587340d2796c342b87e" url: "https://pub.dev" source: hosted - version: "0.3.20" + version: "0.3.21" tencent_im_sdk_plugin_web: dependency: "direct main" description: name: tencent_im_sdk_plugin_web - sha256: "6ddf543c6fb4a2c220c5cec3b9247b4353c3dc0f276e76b81c800ad4c92f9bb5" + sha256: "291082df8b447191dc2dcafca3e1dbcb5385e02a3936e1f108b9434356481832" url: "https://pub.dev" source: hosted - version: "0.3.9" + version: "0.3.11" tencent_keyboard_visibility: dependency: transitive description: @@ -1192,10 +1264,10 @@ packages: dependency: transitive description: name: tencent_open_file - sha256: "01f94f618da42e5593bbad0657fcd13cfc1c2360cca805d8cdfefe898cbe5429" + sha256: bb92d2f052c150a45942c564fba13d150a1b7b47525e6fdd74ccc58058ba5dcf url: "https://pub.dev" source: hosted - version: "4.0.10" + version: "4.0.11" tencent_super_tooltip: dependency: transitive description: @@ -1224,34 +1296,34 @@ packages: dependency: transitive description: name: tim_ui_kit_sticker_plugin - sha256: "2a825d33076f319f6c1c87d58e2b0d650c9284ae4afd8efdc206f3e6f3582e64" + sha256: c9b0c1261bb51a5dee54bb50c6a106061b1bb10731b9c815fc5175afa60175e2 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.2.1" transparent_image: dependency: transitive description: name: transparent_image - sha256: e566a616922a781489f4d91cc939b1b3203b6e4a093317805f2f82f0bb0f8dec + sha256: e8991d955a2094e197ca24c645efec2faf4285772a4746126ca12875e54ca02f url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" tuple: dependency: transitive description: name: tuple - sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa" + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" universal_html: dependency: transitive description: @@ -1264,74 +1336,74 @@ packages: dependency: transitive description: name: universal_io - sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d" + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.2" url_launcher: dependency: transitive description: name: url_launcher - sha256: "698fa0b4392effdc73e9e184403b627362eb5fbf904483ac9defbb1c2191d809" + sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" url: "https://pub.dev" source: hosted - version: "6.1.8" + version: "6.1.12" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" + sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03" url: "https://pub.dev" source: hosted - version: "6.0.23" + version: "6.0.36" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: bb328b24d3bccc20bdf1024a0990ac4f869d57663660de9c936fb8c043edefe3 + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" url: "https://pub.dev" source: hosted - version: "6.0.18" + version: "6.1.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" + sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.5" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.3" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" + sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 url: "https://pub.dev" source: hosted - version: "2.0.14" + version: "2.0.18" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: b6217370f8eb1fd85c8890c539f5a639a01ab209a36db82c921ebeacefc7a615 + sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.7" uuid: dependency: transitive description: @@ -1344,26 +1416,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: b96f10cbdfcbd03a65758633a43e7d04574438f059b1043104b5d61b23d38a4f + sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f" url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "1.1.7" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: "57a8e6e24662a3bdfe3b3d61257db91768700c0b8f844e235877b56480f31c69" + sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f" url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "1.1.7" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: "7430f5d834d0db4560d7b19863362cd892f1e52b43838553a3c5cdfc9ab28e5b" + sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e" url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "1.1.7" vector_math: dependency: transitive description: @@ -1376,50 +1448,50 @@ packages: dependency: transitive description: name: video_player - sha256: "868a139229acb5018d22aded3eb9cb4767ff43a8216573c086b6c535a4957481" + sha256: "3fd106c74da32f336dc7feb65021da9b0207cb3124392935f1552834f7cce822" url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" video_player_android: dependency: transitive description: name: video_player_android - sha256: "984388511230bac63feb53b2911a70e829fe0976b6b2213f5c579c4e0a882db3" + sha256: f338a5a396c845f4632959511cad3542cdf3167e1b2a1a948ef07f7123c03608 url: "https://pub.dev" source: hosted - version: "2.3.10" + version: "2.4.9" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: d9f7a46d6a77680adb03ec05a381025d6e890ebe636637c6c3014cc3926b97e9 + sha256: "4c274e439f349a0ee5cb3c42978393ede173a443b98f50de6ffe6900eaa19216" url: "https://pub.dev" source: hosted - version: "2.3.8" + version: "2.4.6" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - sha256: "42bb75de5e9b79e1f20f1d95f688fac0f95beac4d89c6eb2cd421724d4432dae" + sha256: a8c4dcae2a7a6e7cc1d7f9808294d968eca1993af34a98e95b9bdfa959bec684 url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.1.0" video_player_web: dependency: transitive description: name: video_player_web - sha256: b649b07b8f8f553bee4a97a0a53d0fe78a70b115eafaf0105b612b32b05ddb99 + sha256: "44ce41424d104dfb7cf6982cc6b84af2b007a24d126406025bf40de5d481c74c" url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.0.16" wakelock_for_us: dependency: transitive description: name: wakelock_for_us - sha256: b73bfa90e5e764f41155063ae92fbd1e3a04ee6372e65ff7d288d2c3057f9498 + sha256: a5bdd445e51a617f7c24be8165230391447301f622aacd050038cee7b41989b4 url: "https://pub.dev" source: hosted - version: "0.6.3" + version: "0.6.3+1" wakelock_platform_interface: dependency: transitive description: @@ -1432,10 +1504,10 @@ packages: dependency: transitive description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" wechat_assets_picker: dependency: transitive description: @@ -1456,26 +1528,26 @@ packages: dependency: transitive description: name: win32 - sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee url: "https://pub.dev" source: hosted - version: "4.1.4" + version: "5.0.5" win32_registry: dependency: transitive description: name: win32_registry - sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae" + sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 url: "https://pub.dev" source: hosted - version: "0.2.0+3" + version: "1.0.0" xml: dependency: transitive description: @@ -1488,10 +1560,10 @@ packages: dependency: transitive description: name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.0.0 <3.2.0" flutter: ">=3.10.0" diff --git a/example/windows/flutter/generated_plugin_registrant.cc b/example/windows/flutter/generated_plugin_registrant.cc index 18fd67a..f81340b 100644 --- a/example/windows/flutter/generated_plugin_registrant.cc +++ b/example/windows/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("DesktopDropPlugin")); FcNativeVideoThumbnailPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FcNativeVideoThumbnailPluginCApi")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); PasteboardPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PasteboardPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( diff --git a/example/windows/flutter/generated_plugins.cmake b/example/windows/flutter/generated_plugins.cmake index f381b9a..c350c7b 100644 --- a/example/windows/flutter/generated_plugins.cmake +++ b/example/windows/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows desktop_drop fc_native_video_thumbnail + file_selector_windows pasteboard permission_handler_windows url_launcher_windows diff --git a/lib/business_logic/life_cycle/base_life_cycle.dart b/lib/business_logic/life_cycle/base_life_cycle.dart index 47bb87b..ef1f7f4 100644 --- a/lib/business_logic/life_cycle/base_life_cycle.dart +++ b/lib/business_logic/life_cycle/base_life_cycle.dart @@ -4,6 +4,8 @@ import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_class.dart'; typedef MessageFunction = Future Function(V2TimMessage message); +typedef MessageFunctionNullCallback = Function(V2TimValueCallback res); + typedef MessageFunctionOptional = Future Function( V2TimMessage message); @@ -46,10 +48,17 @@ abstract class DefaultLifeCycle { return list; } - static Future defaultBooleanSolution(dynamic) async { + static Future defaultAsyncBooleanSolution(dynamic) async { return true; } + static bool defaultBooleanSolution(dynamic) { + return true; + } + + static defaultNullCallbackSolution(dynamic) { + } + static Future defaultAddFriend( String userID, String? remark, String? friendGroup, String? addWording, [BuildContext? context]) async { diff --git a/lib/business_logic/life_cycle/block_list_life_cycle.dart b/lib/business_logic/life_cycle/block_list_life_cycle.dart index 44029e4..6c2baa5 100644 --- a/lib/business_logic/life_cycle/block_list_life_cycle.dart +++ b/lib/business_logic/life_cycle/block_list_life_cycle.dart @@ -7,6 +7,6 @@ class BlockListLifeCycle { FutureBool Function(List userIDList) shouldDeleteFromBlockList; BlockListLifeCycle({ - this.shouldDeleteFromBlockList = DefaultLifeCycle.defaultBooleanSolution, + this.shouldDeleteFromBlockList = DefaultLifeCycle.defaultAsyncBooleanSolution, }); } diff --git a/lib/business_logic/life_cycle/chat_life_cycle.dart b/lib/business_logic/life_cycle/chat_life_cycle.dart index 90a0c9b..1a2d1d0 100644 --- a/lib/business_logic/life_cycle/chat_life_cycle.dart +++ b/lib/business_logic/life_cycle/chat_life_cycle.dart @@ -1,4 +1,5 @@ import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/base_life_cycle.dart'; +import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; class ChatLifeCycle { /// Before a new message will be added to historical message list from long connection. @@ -12,6 +13,9 @@ class ChatLifeCycle { /// Returns null can block the message from sending. MessageFunction messageWillSend; + /// After a new message been sent. + MessageFunctionNullCallback messageDidSend; + /// After getting the latest message list from API, /// and before historical message list will be rendered. /// You may add or delete some messages here. @@ -27,14 +31,20 @@ class ChatLifeCycle { /// You can make a second confirmation here by a modal, etc. FutureBool Function(String conversationID) shouldClearHistoricalMessageList; + + /// Before rendering a message to message list. + bool Function(V2TimMessage msgID) messageShouldMount; + ChatLifeCycle({ this.shouldClearHistoricalMessageList = - DefaultLifeCycle.defaultBooleanSolution, - this.shouldDeleteMessage = DefaultLifeCycle.defaultBooleanSolution, + DefaultLifeCycle.defaultAsyncBooleanSolution, + this.shouldDeleteMessage = DefaultLifeCycle.defaultAsyncBooleanSolution, + this.messageDidSend = DefaultLifeCycle.defaultNullCallbackSolution, this.didGetHistoricalMessageList = DefaultLifeCycle.defaultMessageListSolution, this.messageWillSend = DefaultLifeCycle.defaultMessageSolution, this.modifiedMessageWillMount = DefaultLifeCycle.defaultMessageSolution, this.newMessageWillMount = DefaultLifeCycle.defaultMessageSolution, + this.messageShouldMount = DefaultLifeCycle.defaultBooleanSolution, }); } diff --git a/lib/business_logic/life_cycle/conversation_life_cycle.dart b/lib/business_logic/life_cycle/conversation_life_cycle.dart index 289d5c3..4f8612b 100644 --- a/lib/business_logic/life_cycle/conversation_life_cycle.dart +++ b/lib/business_logic/life_cycle/conversation_life_cycle.dart @@ -19,7 +19,7 @@ class ConversationLifeCycle { this.conversationListWillMount = DefaultLifeCycle.defaultConversationListSolution, this.shouldClearHistoricalMessageForConversation = - DefaultLifeCycle.defaultBooleanSolution, - this.shouldDeleteConversation = DefaultLifeCycle.defaultBooleanSolution, + DefaultLifeCycle.defaultAsyncBooleanSolution, + this.shouldDeleteConversation = DefaultLifeCycle.defaultAsyncBooleanSolution, }); } diff --git a/lib/business_logic/life_cycle/new_contact_life_cycle.dart b/lib/business_logic/life_cycle/new_contact_life_cycle.dart index b754a37..34d4714 100644 --- a/lib/business_logic/life_cycle/new_contact_life_cycle.dart +++ b/lib/business_logic/life_cycle/new_contact_life_cycle.dart @@ -13,8 +13,8 @@ class NewContactLifeCycle { NewContactLifeCycle({ this.shouldAcceptContactApplication = - DefaultLifeCycle.defaultBooleanSolution, + DefaultLifeCycle.defaultAsyncBooleanSolution, this.shouldRefuseContactApplication = - DefaultLifeCycle.defaultBooleanSolution, + DefaultLifeCycle.defaultAsyncBooleanSolution, }); } diff --git a/lib/business_logic/life_cycle/profile_life_cycle.dart b/lib/business_logic/life_cycle/profile_life_cycle.dart index b46fa2c..80b6850 100644 --- a/lib/business_logic/life_cycle/profile_life_cycle.dart +++ b/lib/business_logic/life_cycle/profile_life_cycle.dart @@ -24,10 +24,10 @@ class ProfileLifeCycle { FutureBool Function(String userID) didRemarkUpdated; ProfileLifeCycle({ - this.didRemarkUpdated = DefaultLifeCycle.defaultBooleanSolution, + this.didRemarkUpdated = DefaultLifeCycle.defaultAsyncBooleanSolution, this.didGetFriendInfo = DefaultLifeCycle.defaultFriendInfoSolution, - this.shouldAddToBlockList = DefaultLifeCycle.defaultBooleanSolution, - this.shouldAddFriend = DefaultLifeCycle.defaultBooleanSolution, - this.shouldDeleteFriend = DefaultLifeCycle.defaultBooleanSolution, + this.shouldAddToBlockList = DefaultLifeCycle.defaultAsyncBooleanSolution, + this.shouldAddFriend = DefaultLifeCycle.defaultAsyncBooleanSolution, + this.shouldDeleteFriend = DefaultLifeCycle.defaultAsyncBooleanSolution, }); } diff --git a/lib/business_logic/separate_models/tui_chat_model_tools.dart b/lib/business_logic/separate_models/tui_chat_model_tools.dart index 624b8ab..97040e8 100644 --- a/lib/business_logic/separate_models/tui_chat_model_tools.dart +++ b/lib/business_logic/separate_models/tui_chat_model_tools.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_cloud_custom_data.dart'; import 'package:tencent_im_base/tencent_im_base.dart'; @@ -173,4 +174,14 @@ class TUIChatModelTools { return null; } } + + Future hasZeroSize(String filePath) async { + try { + final file = File(filePath); + final fileSize = await file.length(); + return fileSize == 0; + } catch (e) { + return false; + } + } } diff --git a/lib/business_logic/separate_models/tui_chat_separate_view_model.dart b/lib/business_logic/separate_models/tui_chat_separate_view_model.dart index 6cfeeae..040df7c 100644 --- a/lib/business_logic/separate_models/tui_chat_separate_view_model.dart +++ b/lib/business_logic/separate_models/tui_chat_separate_view_model.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; +import 'package:collection/collection.dart'; import 'package:flutter/cupertino.dart'; // ignore: unnecessary_import @@ -177,16 +178,18 @@ class TUIChatSeparateViewModel extends ChangeNotifier { setInputField = onChangeInputField; conversationType = convType; conversationID = convID; + + _groupType = null; + isGroupExist = true; + _groupInfo = null; + groupMemberList?.clear(); + selfMemberInfo = null; + if (conversationType == ConvType.group) { globalModel.refreshGroupApplicationList(); - getGroupInfo(groupID ?? convID); + loadGroupInfo(groupID ?? convID); loadGroupMemberList(groupID: groupID ?? convID); } else { - _groupType = null; - isGroupExist = true; - _groupInfo = null; - groupMemberList?.clear(); - selfMemberInfo = null; notifyListeners(); } if (conversationType == ConvType.c2c) { @@ -482,18 +485,6 @@ class TUIChatSeparateViewModel extends ChangeNotifier { } } - loadGroupInfo(String groupID) async { - final groupInfo = - await _groupServices.getGroupsInfo(groupIDList: [groupID]); - if (groupInfo != null) { - final groupRes = groupInfo.first; - if (groupRes.resultCode == 0) { - _groupInfo = groupRes.groupInfo; - } - } - notifyListeners(); - } - Future loadGroupMemberList( {required String groupID, int count = 100, String? seq}) async { final String? nextSeq = await _loadGroupMemberListFunction( @@ -503,7 +494,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier { groupID: groupID, count: count, seq: nextSeq); } else { selfMemberInfo = groupMemberList - ?.firstWhere((e) => e?.userID == selfModel.loginInfo?.userID); + ?.firstWhereOrNull((e) => e?.userID == selfModel.loginInfo?.userID); notifyListeners(); } } @@ -513,38 +504,49 @@ class TUIChatSeparateViewModel extends ChangeNotifier { if (seq == null || seq == "" || seq == "0") { groupMemberList?.clear(); } - final res = await _groupServices.getGroupMemberList( - groupID: groupID, - filter: GroupMemberFilterTypeEnum.V2TIM_GROUP_MEMBER_FILTER_ALL, - count: count, - nextSeq: seq ?? groupMemberListSeq); - final groupMemberListRes = res.data; - if (res.code == 0 && groupMemberListRes != null) { - final groupMemberListTemp = groupMemberListRes.memberInfoList ?? []; - groupMemberList = [...?groupMemberList, ...groupMemberListTemp]; - groupMemberListSeq = groupMemberListRes.nextSeq ?? "0"; - } else if (res.code == 10010) { - isGroupExist = false; - } else if (res.code == 10007) { - isNotAMember = true; + try { + final res = await _groupServices.getGroupMemberList( + groupID: groupID, + filter: GroupMemberFilterTypeEnum.V2TIM_GROUP_MEMBER_FILTER_ALL, + count: count, + nextSeq: seq ?? groupMemberListSeq); + final groupMemberListRes = res.data; + if (res.code == 0 && groupMemberListRes != null) { + final groupMemberListTemp = groupMemberListRes.memberInfoList ?? []; + groupMemberList = [...?groupMemberList, ...groupMemberListTemp]; + groupMemberListSeq = groupMemberListRes.nextSeq ?? "0"; + } else if (res.code == 10010) { + isGroupExist = false; + } else if (res.code == 10007) { + isNotAMember = true; + } + return groupMemberListRes?.nextSeq; + } catch (e) { + return ""; } - return groupMemberListRes?.nextSeq; } - getGroupInfo(String groupID) async { - final res = await _groupServices.getGroupsInfo(groupIDList: [groupID]); - if (res != null) { - final groupRes = res.first; + Future<(V2TimGroupInfo?, GroupReceiptAllowType?)> loadGroupInfo( + String groupID) async { + final groupInfoList = + await _groupServices.getGroupsInfo(groupIDList: [groupID]); + if (groupInfoList != null && groupInfoList.isNotEmpty) { + final groupRes = groupInfoList.first; if (groupRes.resultCode == 0) { + _groupInfo = groupRes.groupInfo; + const groupTypeMap = { "Meeting": GroupReceiptAllowType.meeting, "Public": GroupReceiptAllowType.public, "Work": GroupReceiptAllowType.work }; - _groupInfo = groupRes.groupInfo; _groupType = groupTypeMap[groupRes.groupInfo?.groupType]; + + notifyListeners(); + return (_groupInfo, _groupType); } } + return (null, null); } Future updateMessageFromController( @@ -584,6 +586,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier { }) async { String receiver = convType == ConvType.c2c ? convID : ''; String groupID = convType == ConvType.group ? convID : ''; + if (convType == ConvType.group && _groupType == null) { + await loadGroupInfo(groupID); + } final oldGroupType = _groupType != null ? GroupReceptAllowType.values[_groupType!.index] : null; @@ -624,6 +629,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier { globalModel.updateMessage( sendMsgRes, convID, id, convType, groupType, setInputField); } + if(lifeCycle?.messageDidSend != null){ + lifeCycle!.messageDidSend(sendMsgRes); + } return sendMsgRes; } @@ -875,6 +883,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier { notifyListeners(); globalModel.updateMessage(sendMsgRes, convID, messageInfoWithSender.id ?? "", convType, groupType, setInputField); + if(lifeCycle?.messageDidSend != null){ + lifeCycle!.messageDidSend(sendMsgRes); + } return sendMsgRes; } } @@ -1017,6 +1028,14 @@ class TUIChatSeparateViewModel extends ChangeNotifier { dynamic inputElement, required String convID, required ConvType convType}) async { + if (await tools.hasZeroSize(filePath ?? "")) { + final CoreServicesImpl _coreServices = serviceLocator(); + _coreServices.callOnCallback(TIMCallback( + type: TIMCallbackType.INFO, + infoRecommendText: "不支持 0KB 文件的传输", + infoCode: 6660417)); + return null; + } final fileMessageInfo = await _messageService.createFileMessage( inputElement: inputElement, fileName: fileName ?? filePath?.split('/').last ?? "", diff --git a/lib/business_logic/view_models/tui_chat_global_model.dart b/lib/business_logic/view_models/tui_chat_global_model.dart index 006a67c..f0d5766 100644 --- a/lib/business_logic/view_models/tui_chat_global_model.dart +++ b/lib/business_logic/view_models/tui_chat_global_model.dart @@ -48,7 +48,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { ChatLifeCycle? _lifeCycle; bool _isDownloading = false; final List> _waitingDownloadList = - List.empty(growable: true); // example {"savePath":"","url":"",msgId:""} + List.empty(growable: true); // example {"savePath":"","url":"",msgId:""} int _totalUnreadCount = 0; String localKeyPrefix = "TUIKit_conversation_stored_"; String localMsgIDListKey = "TUIKit_conversation_list"; @@ -62,7 +62,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { List? _groupApplicationList; String Function(V2TimMessage message)? _abstractMessageBuilder; final Map _c2cMessageEditStatusMap = - Map.from({}); // 0 normal 1 sending + Map.from({}); // 0 normal 1 sending final Map _c2cMessageFromUserActiveMap = Map.from({}); final Map _c2cMessageActiveTimer = Map.from({}); bool _showC2cMessageEditStatus = true; @@ -102,6 +102,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { Map get currentDownLoad => _waitingDownloadList.first; + int getWaitingListLength() { + return _waitingDownloadList.length; + } + void addWaitingList(String msgID) { print("add to waiting list success"); bool contains = false; @@ -191,15 +195,17 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { Map get messageReadReceiptMap => _messageReadReceiptMap; - String get currentSelectedConv => _currentConversationList.isNotEmpty - ? _currentConversationList[_currentConversationList.length - 1] + String get currentSelectedConv => + _currentConversationList.isNotEmpty + ? _currentConversationList[_currentConversationList.length - 1] .conversationID - : ""; + : ""; - ConvType? get currentSelectedConvType => _currentConversationList.isNotEmpty - ? _currentConversationList[_currentConversationList.length - 1] + ConvType? get currentSelectedConvType => + _currentConversationList.isNotEmpty + ? _currentConversationList[_currentConversationList.length - 1] .conversationType - : null; + : null; setCurrentConversation(CurrentConversation value) { _currentConversationList.add(value); @@ -235,13 +241,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { } _c2cMessageStatusShowTimer[userID] = Timer.periodic(const Duration(seconds: 5), (timer) { - _c2cMessageEditStatusMap[userID] = 0; - Timer? t = _c2cMessageStatusShowTimer[userID]; - if (t != null && t.isActive) { - // 取消当前的定时器 - t.cancel(); - } - }); + _c2cMessageEditStatusMap[userID] = 0; + Timer? t = _c2cMessageStatusShowTimer[userID]; + if (t != null && t.isActive) { + // 取消当前的定时器 + t.cancel(); + } + }); } notifyListeners(); } @@ -326,10 +332,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { prefs.remove(localMsgIDListKey); } - Future updateMessageFromController( - {required String msgID, - required String conversationID, - required ConvType conversationType}) async { + Future updateMessageFromController({required String msgID, + required String conversationID, + required ConvType conversationType}) async { final TUIChatModelTools tools = serviceLocator(); V2TimMessage? newMessage = await tools.getExistingMessageByID( msgID: msgID, @@ -343,11 +348,11 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { Future refreshCurrentHistoryListForConversation( {HistoryMsgGetTypeEnum getType = HistoryMsgGetTypeEnum.V2TIM_GET_CLOUD_OLDER_MSG, - int lastMsgSeq = -1, - required int count, - String? lastMsgID, - required String convID, - required ConvType convType}) async { + int lastMsgSeq = -1, + required int count, + String? lastMsgID, + required String convID, + required ConvType convType}) async { final currentHistoryMsgList = messageListMap[convID]; final response = await _messageService.getHistoryMessageList( count: count, @@ -389,7 +394,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { _preLoadImage(List msgList) { List needPreViewList = - msgList.sublist(0, max(0, min(5, msgList.length - 1))); + msgList.sublist(0, max(0, min(5, msgList.length - 1))); for (var msgItem in needPreViewList) { V2TimImage? getImageFromList(V2TimImageTypesEnum imgType) { V2TimImage? img = MessageUtils.getImageFromImgList( @@ -407,12 +412,12 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { image.resolve(configuration).addListener( ImageStreamListener((ImageInfo image, bool synchronousCall) { - final tempImg = image.image; - _preloadImageMap[msgItem.seq! + - msgItem.timestamp.toString() + - (msgItem.msgID ?? "")] = tempImg; - print("cacheImage ${msgItem.msgID}"); - })); + final tempImg = image.image; + _preloadImageMap[msgItem.seq! + + msgItem.timestamp.toString() + + (msgItem.msgID ?? "")] = tempImg; + print("cacheImage ${msgItem.msgID}"); + })); } catch (e) { print("cacheImage error ${msgItem.msgID}"); } @@ -513,13 +518,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { } _c2cMessageActiveTimer[msg.sender ?? ""] = Timer.periodic(const Duration(seconds: 30), (timer) { - _c2cMessageFromUserActiveMap[msg.sender ?? ""] = false; - Timer? t = _c2cMessageActiveTimer[msg.sender ?? ""]; - if (t != null && t.isActive) { - // 取消当前的定时器 - t.cancel(); - } - }); + _c2cMessageFromUserActiveMap[msg.sender ?? ""] = false; + Timer? t = _c2cMessageActiveTimer[msg.sender ?? ""]; + if (t != null && t.isActive) { + // 取消当前的定时器 + t.cancel(); + } + }); } } } catch (err) { @@ -537,14 +542,14 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { } V2TimMsgCreateInfoResult? res = await _messageService.createCustomMessage( data: json.encode({ - "businessID": "user_typing_status", - "typingStatus": isEditing == true ? 1 : 0, - "userAction": 14, - "version": 0, - "actionParam": isEditing == true - ? "EIMAMSG_InputStatus_Ing" - : "EIMAMSG_InputStatus_End" - })); + "businessID": "user_typing_status", + "typingStatus": isEditing == true ? 1 : 0, + "userAction": 14, + "version": 0, + "actionParam": isEditing == true + ? "EIMAMSG_InputStatus_Ing" + : "EIMAMSG_InputStatus_End" + })); if (res != null) { _sendMessage( id: res.id!, @@ -559,9 +564,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { void refreshGroupApplicationList() async { final res = await _groupServices.getGroupApplicationList(); _groupApplicationList = res.data?.groupApplicationList?.map((item) { - final V2TimGroupApplication applicationItem = item!; - return applicationItem; - }).toList() ?? + final V2TimGroupApplication applicationItem = item!; + return applicationItem; + }).toList() ?? []; notifyListeners(); } @@ -657,14 +662,17 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { final activeMessageList = _messageListMap[convID ?? currentSelectedConv]; if (activeMessageList != null) { final findeIndex = - activeMessageList.indexWhere((element) => element.msgID == msgID); + activeMessageList.indexWhere((element) => element.msgID == msgID); if (findeIndex != -1) { final findeIndex = - activeMessageList.indexWhere((element) => element.msgID == msgID); + activeMessageList.indexWhere((element) => element.msgID == msgID); if (findeIndex != -1) { final targetItem = activeMessageList[findeIndex]; targetItem.status = MessageStatus.V2TIM_MSG_STATUS_LOCAL_REVOKED; - targetItem.id = DateTime.now().millisecondsSinceEpoch.toString(); + targetItem.id = DateTime + .now() + .millisecondsSinceEpoch + .toString(); activeMessageList[findeIndex] = targetItem; } } @@ -674,7 +682,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { } onMessageModified(V2TimMessage modifiedMessage, [String? convID]) async { - modifiedMessage.id = DateTime.now().millisecondsSinceEpoch.toString(); + modifiedMessage.id = DateTime + .now() + .millisecondsSinceEpoch + .toString(); final String? exactId = TencentUtils.checkString(modifiedMessage.userID) ?? TencentUtils.checkString(modifiedMessage.groupID); final activeMessageList = _messageListMap[convID ?? exactId]; @@ -729,33 +740,78 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { print("message progress: $progress"); } - onMessageDownloadProgressCallback( + Future onMessageDownloadProgressCallback( V2TimMessageDownloadProgress messageProgress) async { - if (messageProgress.isFinish) { - setMessageProgress(messageProgress.msgID, 100); - setFileMessageLocation(messageProgress.msgID, messageProgress.path); - downloadFile(); - if (messageProgress.type == 0) { - final messages = await _messageService - .findMessages(messageIDList: [messageProgress.msgID]); - final V2TimMessage? message = messages?.first; - if (message != null) { - updateAsyncMessage( - message, - TencentUtils.checkString(message.userID) ?? - TencentUtils.checkString(message.groupID) ?? - ""); - } - } + print(messageProgress.toJson()); + final currentProgress = getMessageProgress(messageProgress.msgID); + + if (messageProgress.isFinish && currentProgress < 100) { + V2TimMessage? message = await _findAndRetrieveMessage( + messageProgress.msgID); + _handleFinishedDownload(messageProgress, message); return; } - if (messageProgress.totalSize != -1) { - int progress = - (messageProgress.currentSize / messageProgress.totalSize * 100) - .ceil(); - if (progress > 1) { - setMessageProgress(messageProgress.msgID, progress); + + _updateProgressIfNeeded(messageProgress, currentProgress); + } + + Future _findAndRetrieveMessage(String messageId) async { + final messages = await _messageService.findMessages( + messageIDList: [messageId]); + return messages?.first; + } + + void _handleFinishedDownload(V2TimMessageDownloadProgress messageProgress, + V2TimMessage? message) { + if (message != null) { + bool isImageType = message.elemType == + MessageElemType.V2TIM_ELEM_TYPE_IMAGE; + bool isVideoType = message.elemType == + MessageElemType.V2TIM_ELEM_TYPE_VIDEO; + if (!isImageType && !isVideoType) { + _updateMessageLocationAndDownloadFile(messageProgress); + } else if ((isImageType && messageProgress.type == 0) || isVideoType) { + Future.delayed(const Duration(seconds: 1), () => + _updateMessageAndDownloadFile(message, messageProgress)); + } else { + return; } + } else { + _updateMessageLocationAndDownloadFile(messageProgress); + } + } + + void _updateMessageAndDownloadFile(V2TimMessage message, + V2TimMessageDownloadProgress messageProgress) { + updateAsyncMessage( + message, + TencentUtils.checkString(message.userID) ?? + TencentUtils.checkString(message.groupID) ?? + ""); + + _updateMessageLocationAndDownloadFile(messageProgress); + } + + void _updateMessageLocationAndDownloadFile( + V2TimMessageDownloadProgress messageProgress) { + setFileMessageLocation(messageProgress.msgID, messageProgress.path); + setMessageProgress(messageProgress.msgID, 100); + downloadFile(); + } + + void _updateProgressIfNeeded(V2TimMessageDownloadProgress messageProgress, + int currentProgress) { + try{ + if (messageProgress.totalSize != -1 && !messageProgress.isFinish) { + int progress = min(99, + (messageProgress.currentSize / messageProgress.totalSize * 100) + .floor()); + if (progress > 1 && progress > currentProgress) { + setMessageProgress(messageProgress.msgID, progress); + } + } + }catch(e){ + print("calculate error: ${messageProgress.toJson()}"); } } @@ -842,11 +898,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { final TUIChatModelTools tools = serviceLocator(); List currentHistoryMsgList = _messageListMap[convID] ?? []; V2TimMsgCreateInfoResult? textMessageInfo = - await _messageService.createTextMessage(text: text); + await _messageService.createTextMessage(text: text); textMessageInfo = await _messageService.createTextAtMessage( text: text + - " @${TencentUtils.checkString(messageBeenReplied.nickName) ?? TencentUtils.checkString(messageBeenReplied.sender) ?? TencentUtils.checkString(messageBeenReplied.userID)}", + "\n@${TencentUtils.checkString(messageBeenReplied.nickName) ?? + TencentUtils.checkString(messageBeenReplied.sender) ?? + TencentUtils.checkString(messageBeenReplied.userID)}", atUserList: [ TencentUtils.checkString(messageBeenReplied.sender) ?? TencentUtils.checkString(messageBeenReplied.userID) ?? @@ -857,7 +915,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { if (messageInfo != null) { final messageInfoWithSender = messageInfo.sender == null - ? tools.setUserInfoForMessage(messageInfo, messageInfo.id ?? textMessageInfo.id ?? "") + ? tools.setUserInfoForMessage( + messageInfo, messageInfo.id ?? textMessageInfo.id ?? "") : messageInfo; final hasNickName = messageBeenReplied.nickName != null && @@ -898,8 +957,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { return null; } - Future setLocalCustomData( - String msgID, String localCustomData, String conversationID) async { + Future setLocalCustomData(String msgID, String localCustomData, + String conversationID) async { final res = await _messageService.setLocalCustomData( msgID: msgID, localCustomData: localCustomData); List messageList = _messageListMap[conversationID] ?? []; @@ -918,8 +977,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { return false; } - Future setLocalCustomInt( - String msgID, int localCustomInt, String conversationID) async { + Future setLocalCustomInt(String msgID, int localCustomInt, + String conversationID) async { final res = await _messageService.setLocalCustomInt( msgID: msgID, localCustomInt: localCustomInt); List messageList = _messageListMap[conversationID] ?? []; @@ -956,7 +1015,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { String receiver = convType == ConvType.c2c ? convID : ''; String groupID = convType == ConvType.group ? convID : ''; final oldGroupType = - groupType != null ? GroupReceptAllowType.values[groupType.index] : null; + groupType != null ? GroupReceptAllowType.values[groupType.index] : null; final sendMsgRes = await _messageService.sendMessage( id: id, receiver: receiver, @@ -964,8 +1023,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { chatConfig.isShowGroupReadingStatus && convType == ConvType.group && ((chatConfig.groupReadReceiptPermissionList != null && - chatConfig.groupReadReceiptPermissionList! - .contains(groupType)) || + chatConfig.groupReadReceiptPermissionList! + .contains(groupType)) || (chatConfig.groupReadReceiptPermisionList != null && chatConfig.groupReadReceiptPermisionList! .contains(oldGroupType))), @@ -985,6 +1044,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { if (isEditStatusMessage == false) { updateMessage(sendMsgRes, convID, id, convType, groupType, setInputField); } + if(_lifeCycle?.messageDidSend != null){ + _lifeCycle!.messageDidSend(sendMsgRes); + } return sendMsgRes; } @@ -998,8 +1060,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { notifyListeners(); } - updateMessage( - V2TimValueCallback sendMsgRes, + updateMessage(V2TimValueCallback sendMsgRes, String convID, String id, ConvType convType, @@ -1014,10 +1075,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { } final findIdIndex = - currentHistoryMsgList.indexWhere((element) => element.id == id); + currentHistoryMsgList.indexWhere((element) => element.id == id); final targetIndex = findIdIndex == -1 ? currentHistoryMsgList - .indexWhere((element) => element.msgID == sendMsgResData.msgID) + .indexWhere((element) => element.msgID == sendMsgResData.msgID) : findIdIndex; if (targetIndex != -1) { currentHistoryMsgList[targetIndex] = sendMsgResData; @@ -1028,13 +1089,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { loadingMessage[convID]!.removeWhere((element) => element.id == id); } final oldGroupType = - groupType != null ? GroupReceptAllowType.values[groupType.index] : null; + groupType != null ? GroupReceptAllowType.values[groupType.index] : null; if (chatConfig.isShowGroupReadingStatus && convType == ConvType.group && sendMsgRes.data?.msgID != null && ((chatConfig.groupReadReceiptPermissionList != null && - chatConfig.groupReadReceiptPermissionList! - .contains(groupType)) || + chatConfig.groupReadReceiptPermissionList! + .contains(groupType)) || (chatConfig.groupReadReceiptPermisionList != null && chatConfig.groupReadReceiptPermisionList! .contains(oldGroupType)))) { @@ -1045,11 +1106,12 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { notifyListeners(); } - void updateAsyncMessage( - V2TimMessage message, - String convID, - ) { - message.id = DateTime.now().millisecondsSinceEpoch.toString(); + void updateAsyncMessage(V2TimMessage message, + String convID,) { + message.id = DateTime + .now() + .millisecondsSinceEpoch + .toString(); final activeMessageList = _messageListMap[convID]; if (activeMessageList == null || activeMessageList.isEmpty) { @@ -1068,18 +1130,19 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { } List? getMessageList(String conversationID) { - final list = messageListMap[conversationID]?.reversed.toList() ?? []; + final list = (messageListMap[conversationID]?.reversed.toList() ?? []) + .where((element) => _lifeCycle?.messageShouldMount(element) ?? true); final List listWithTimestamp = []; final interval = chatConfig.timeDividerConfig?.timeInterval ?? 300; for (var item in list) { { if (listWithTimestamp.isEmpty || (listWithTimestamp[listWithTimestamp.length - 1].timestamp != - null && + null && item.timestamp != null && (item.timestamp! - - listWithTimestamp[listWithTimestamp.length - 1] - .timestamp! > + listWithTimestamp[listWithTimestamp.length - 1] + .timestamp! > interval))) { listWithTimestamp.add(V2TimMessage( userID: '', @@ -1098,7 +1161,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { HistoryMessagePosition getMessageListPosition(String? conversationID) { final HistoryMessagePosition? position = - _historyMessagePositionMap[conversationID]; + _historyMessagePositionMap[conversationID]; if (position == null) { _historyMessagePositionMap[conversationID ?? currentSelectedConv] = HistoryMessagePosition.bottom; @@ -1108,8 +1171,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { } } - void setMessageListPosition( - String conversationID, HistoryMessagePosition position) { + void setMessageListPosition(String conversationID, + HistoryMessagePosition position) { _historyMessagePositionMap[conversationID] = position; notifyListeners(); } diff --git a/lib/business_logic/view_models/tui_conversation_view_model.dart b/lib/business_logic/view_models/tui_conversation_view_model.dart index e7add7f..acdcde7 100644 --- a/lib/business_logic/view_models/tui_conversation_view_model.dart +++ b/lib/business_logic/view_models/tui_conversation_view_model.dart @@ -151,8 +151,8 @@ class TUIConversationViewModel extends ChangeNotifier { final isRefresh = _nextSeq == "0"; final conversationResult = await _conversationService.getConversationList( nextSeq: _nextSeq, count: count); - _nextSeq = conversationResult!.nextSeq ?? ""; - final conversationList = conversationResult.conversationList; + _nextSeq = conversationResult?.nextSeq ?? ""; + final conversationList = conversationResult?.conversationList; if (conversationList != null) { if (conversationList.isEmpty || conversationList.length < count) { _haveMoreData = false; diff --git a/lib/data_services/core/core_services_implements.dart b/lib/data_services/core/core_services_implements.dart index 97fc281..82a5293 100644 --- a/lib/data_services/core/core_services_implements.dart +++ b/lib/data_services/core/core_services_implements.dart @@ -1,7 +1,9 @@ // ignore_for_file: avoid_print +import 'package:collection/collection.dart'; import 'package:flutter/cupertino.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart'; +import 'package:tencent_cloud_chat_uikit/ui/utils/common_utils.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; import 'package:tencent_im_base/tencent_im_base.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart'; @@ -14,7 +16,7 @@ import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_config.dar import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; import 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support.dart' - if (dart.library.html) 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support_implement.dart'; +if (dart.library.html) 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support_implement.dart'; typedef EmptyAvatarBuilder = Widget Function(BuildContext context); @@ -61,7 +63,7 @@ class CoreServicesImpl implements CoreServices { setGlobalConfig(TIMUIKitConfig? config) { final TUISelfInfoViewModel selfInfoViewModel = - serviceLocator(); + serviceLocator(); final TUISettingModel settingModel = serviceLocator(); selfInfoViewModel.globalConfig = config; settingModel.init(); @@ -73,21 +75,20 @@ class CoreServicesImpl implements CoreServices { } @override - Future init( - { - /// Callback from TUIKit invoke, includes IM SDK API error, notify information, Flutter error. - ValueChanged? onTUIKitCallbackListener, - required int sdkAppID, - required LogLevelEnum loglevel, - required V2TimSDKListener listener, - LanguageEnum? language, - String? extraLanguage, - TIMUIKitConfig? config, + Future init({ + /// Callback from TUIKit invoke, includes IM SDK API error, notify information, Flutter error. + ValueChanged? onTUIKitCallbackListener, + required int sdkAppID, + required LogLevelEnum loglevel, + required V2TimSDKListener listener, + LanguageEnum? language, + String? extraLanguage, + TIMUIKitConfig? config, - /// Specify the current device platform, mobile or desktop, based on your needs. - /// TUIKit will automatically determine the platform if no specification is provided. DeviceType? platform, - DeviceType? platform, - VoidCallback? onWebLoginSuccess}) async { + /// Specify the current device platform, mobile or desktop, based on your needs. + /// TUIKit will automatically determine the platform if no specification is provided. DeviceType? platform, + DeviceType? platform, + VoidCallback? onWebLoginSuccess}) async { if (platform != null) { TUIKitScreenUtils.deviceType = platform; } @@ -166,13 +167,13 @@ class CoreServicesImpl implements CoreServices { void addInitListener() { final TUIFriendShipViewModel tuiFriendShipViewModel = - serviceLocator(); + serviceLocator(); final TUIConversationViewModel tuiConversationViewModel = - serviceLocator(); + serviceLocator(); final TUIChatGlobalModel tuiChatViewModel = - serviceLocator(); + serviceLocator(); final TUIGroupListenerModel tuiGroupListenerModel = - serviceLocator(); + serviceLocator(); tuiFriendShipViewModel.addFriendListener(); tuiConversationViewModel.setConversationListener(); @@ -182,13 +183,13 @@ class CoreServicesImpl implements CoreServices { void removeListener() { final TUIFriendShipViewModel tuiFriendShipViewModel = - serviceLocator(); + serviceLocator(); final TUIConversationViewModel tuiConversationViewModel = - serviceLocator(); + serviceLocator(); final TUIChatGlobalModel tuiChatViewModel = - serviceLocator(); + serviceLocator(); final TUIGroupListenerModel tuiGroupListenerModel = - serviceLocator(); + serviceLocator(); tuiFriendShipViewModel.removeFriendshipListener(); tuiConversationViewModel.removeConversationListener(); @@ -203,15 +204,16 @@ class CoreServicesImpl implements CoreServices { }); } else { print( - "TUIKit Callback: ${callbackValue.type} - ${callbackValue.stackTrace}"); + "TUIKit Callback: ${callbackValue.type} - ${callbackValue + .stackTrace}"); } } initDataModel() { final TUIFriendShipViewModel tuiFriendShipViewModel = - serviceLocator(); + serviceLocator(); final TUIConversationViewModel tuiConversationViewModel = - serviceLocator(); + serviceLocator(); tuiFriendShipViewModel.initFriendShipModel(); tuiConversationViewModel.initConversation(); @@ -219,11 +221,11 @@ class CoreServicesImpl implements CoreServices { clearData() { final TUIFriendShipViewModel tuiFriendShipViewModel = - serviceLocator(); + serviceLocator(); final TUIConversationViewModel tuiConversationViewModel = - serviceLocator(); + serviceLocator(); final TUIChatGlobalModel tuiChatViewModel = - serviceLocator(); + serviceLocator(); tuiFriendShipViewModel.clearData(); tuiConversationViewModel.clearData(); @@ -233,18 +235,18 @@ class CoreServicesImpl implements CoreServices { updateUserStatusList(List newUserStatusList) { try { final TUISelfInfoViewModel selfInfoViewModel = - serviceLocator(); + serviceLocator(); if (selfInfoViewModel.globalConfig?.isShowOnlineStatus == false) { return; } final TUIFriendShipViewModel tuiFriendShipViewModel = - serviceLocator(); + serviceLocator(); final currentUserStatusList = tuiFriendShipViewModel.userStatusList; for (int i = 0; i < newUserStatusList.length; i++) { final int indexInCurrentUserList = currentUserStatusList.indexWhere( - (element) => element.userID == newUserStatusList[i].userID); + (element) => element.userID == newUserStatusList[i].userID); if (indexInCurrentUserList == -1) { currentUserStatusList.add(newUserStatusList[i]); } else { @@ -285,28 +287,50 @@ class CoreServicesImpl implements CoreServices { isLoginSuccess = true; addInitListener(); initDataModel(); + + if (TencentUtils.checkString(_userID) == null) { + V2TimValueCallback getLoginUserRes = + await TencentImSDKPlugin.v2TIMManager.getLoginUser(); + if (getLoginUserRes.code == 0) { + _userID = getLoginUserRes.data ?? ""; + } + } + + getUsersInfoWithRetry(); + } + + void getUsersInfoWithRetry() async { + V2TimValueCallback>? res; + bool success = false; + + while (!success) { + res = await getUsersInfo(userIDList: [_userID]); + if (res.code == 0 && + res.data != null && + res.data!.isNotEmpty && + res.data!.firstWhereOrNull((element) => element.userID == _userID) != + null) { + success = true; + } else { + await Future.delayed(const Duration(seconds: 2)); + } + } + + _loginInfo = + res?.data!.firstWhereOrNull((element) => element.userID == _userID); final TUISelfInfoViewModel selfInfoViewModel = - serviceLocator(); - getUsersInfo(userIDList: [_userID]).then((res) => { - if (res.code == 0) - { - _loginInfo = res.data![0], - selfInfoViewModel.setLoginInfo(_loginInfo!) - } - }); + serviceLocator(); + if (_loginInfo != null) { + selfInfoViewModel.setLoginInfo(_loginInfo); + } } // Deprecated void didLoginOut() { removeListener(); clearData(); - getUsersInfo(userIDList: [_userID]).then((res) => { - if (res.code == 0) - { - _loginInfo = res.data![0], - serviceLocator().setLoginInfo(_loginInfo!) - } - }); + _loginInfo = null; + serviceLocator().setLoginInfo(_loginInfo); } @override @@ -350,10 +374,10 @@ class CoreServicesImpl implements CoreServices { return TencentImSDKPlugin.v2TIMManager .getOfflinePushManager() .setOfflinePushConfig( - businessID: businessID?.toDouble() ?? 0, - token: token, - isTPNSToken: isTPNSToken, - ); + businessID: businessID?.toDouble() ?? 0, + token: token, + isTPNSToken: isTPNSToken, + ); } @override diff --git a/lib/data_services/group/group_services_implement.dart b/lib/data_services/group/group_services_implement.dart index 89c3b2d..986d58e 100644 --- a/lib/data_services/group/group_services_implement.dart +++ b/lib/data_services/group/group_services_implement.dart @@ -105,7 +105,6 @@ class GroupServicesImpl extends GroupServices { count: count, offset: offset); if (res.code != 0) { - _coreService.callOnCallback(TIMCallback( type: TIMCallbackType.API_ERROR, errorMsg: res.desc, diff --git a/lib/i18n/strings.i18n.json b/lib/i18n/strings.i18n.json index a757905..2d3609f 100644 --- a/lib/i18n/strings.i18n.json +++ b/lib/i18n/strings.i18n.json @@ -1 +1 @@ -{"k_1fdhj9g":"This version does not support the message","k_06pujtm":"Accept all friend requests","k_0gyhkp5":"Require approval for friend requests","k_121ruco":"Reject all friend requests","k_05nspni":"Custom field","k_03fchyy":"Group profile photo","k_03i9mfe":"Group introduction","k_03agq58":"Group name","k_039xqny":"Group notification","k_003tr0a":"Group owner","k_002wddw":"Mute","k_0got6f7":"Unmute","k_1uaqed6":"[Custom]","k_0z2z7rx":"[Voice]","k_0y39ngu":"[Emoji]","k_0y1a2my":"[Image]","k_0z4fib8":"[Video]","k_0y24mcg":"[Location]","k_0pewpd1":"[Chat history]","k_13s8d9p":"Unknown message","k_003qkx2":"Calendar","k_003n2pz":"Camera","k_03idjo0":"Contact","k_003ltgm":"Location","k_02k3k86":"Mic","k_003pm7l":"Album","k_15ao57x":"Album write","k_164m3jd":"Local storage","k_03r6qyx":"We need your approval to get information.","k_02noktt":"Reject","k_00043x4":"Agree","k_003qzac":"Yesterday","k_003r39d":"2 days ago","k_03fqp9o":"Sun","k_03ibg5h":"Mon","k_03i7hu1":"Tue","k_03iaiks":"Wed","k_03el9pa":"Thu","k_03i7ok1":"Fri","k_03efxyg":"Sat","k_003q7ba":"Afternoon","k_003q7bb":"Morning","k_003pu3h":"Now","k_002rflt":"Delete","k_1don84v":"Failed to locate the original message","k_003q5fi":"Copy","k_003prq0":"Forward","k_002r1h2":"Multiple-choice","k_003j708":"Reference","k_003pqpr":"Recall","k_03ezhho":"Copied","k_11ctfsz":"Not implemented","k_1hbjg5g":"[Group system message]","k_03tvswb":"[Unknown message]","k_155cj23":"You've recalled a message.","k_0gapun3":"Edit it again","k_0003z7x":"You","k_002wfe4":"Read","k_002wjlg":"Unread","k_003nevv":"Cancel","k_001nmhu":"Open with another app","k_105682d":"Failed to load the image","k_0pytyeu":"Image saved successfully","k_0akceel":"Failed to save the image","k_003rk1s":"Save","k_04a0awq":"[Voice message]","k_105c3y3":"Failed to load the video","k_176rzr7":"Chat history","k_002r305":"Send","k_003n8b0":"Shoot","k_003tnp0":"File","k_0ylosxn":"Custom message","k_0jhdhtp":"Sending failed. The video cannot exceed 100 MB.","k_0am7r68":"Slide up to cancel","k_13dsw4l":"Release to cancel","k_15jl6qw":"Too short","k_0gx7vl6":"Press and hold to talk","k_15dlafd":"One-by-one forward","k_15dryxy":"Combine and forward","k_1eyhieh":"Are you sure you want to delete the selected message?","k_118prbn":"Search globally","k_003kv3v":"Search","k_17fmlyf":"Clear chat","k_0dhesoz":"Unpin from top","k_002sk7x":"Pin to top","k_003ll77":"Draft","k_003kfai":"Unknown","k_13dq4an":"Automatic approval","k_0l13cde":"Admin approval","k_11y8c6a":"Disallow group joining","k_1kvyskd":"Modification failed due to network disconnection","k_16payqf":"Group joining mode","k_0vzvn8r":"Modify group name","k_003rzap":"OK","k_038lh6u":"Group management","k_0k5wyiy":"Set admin","k_0goiuwk":"Mute all","k_1g889xx":"If you mute all, only the group owner and admin can speak.","k_0wlrefq":"Add group members to mute","k_0goox5g":"Mute","k_08daijh":"Admin role canceled successfully","k_0k5u935":"Add admin","k_003ngex":"Complete","k_03enyx5":"Group member","k_03erpei":"Admin","k_0qi9tno":"Group owner and admin","k_0uj7208":"Failed to view the group members due to network disconnection","k_0ef2a12":"Modify my nickname in group","k_1aajych":"2–20 characters, including digits, letters, and underscores","k_137pab5":"My nickname in group","k_0ivim6d":"No group notice","k_03eq6cn":"Group notice","k_002vxya":"Modify","k_03gu05e":"Chat room","k_03b4f3p":"Meeting group","k_03avj1p":"Public group","k_03asq2g":"Work group","k_03b3hbi":"Unknown group","k_03es1ox":"Group type","k_003mz1i":"Agree","k_003lpre":"Reject","k_003qk66":"Profile photo","k_003lhvk":"Nickname","k_003ps50":"Account","k_15lx52z":"Status","k_003qgkp":"Gender","k_003m6hr":"Date of birth","k_0003v6a":"Male","k_00043x2":"Female","k_03bcjkv":"Not set","k_11s0gdz":"Modify nickname","k_0p3j4sd":"Allows only letters, digits, and underscores","k_15lyvdt":"Modify status","k_0vylzjp":"None","k_1hs7ese":"Modify it later","k_03exjk7":"Remarks","k_0s3skfd":"Add to blocklist","k_17fpl3y":"Pin chat to top","k_0p3b31s":"Modify remarks","k_0003y9x":"None","k_11zgnfs":"Profile","k_1tez2xl":"No status","k_0vjj2kp":"Group chat history","k_003n2rp":"Select","k_1m9exwh":"Recent contacts","k_119nwqr":"The input cannot be empty","k_0pzwbmg":"Video saved successfully","k_0aktupv":"Failed to save the video","k_1yemzyd":"Received a message","k_13sajrj":"Emoji message","k_13sjeb7":"File message","k_0yd2ft8":"Group notification","k_13s7mxn":"Image message","k_13satlt":"Location message","k_00bbtsx":"Combined message","k_13sqwu4":"Voice message","k_13sqjjp":"Video message","k_03iqsh4":" $s to ","k_191t5n4":"$opUserNickName changed ","k_1pg6aoj":"$opUserNickName quit group chat","k_1f6zt3v":"Invite $invitedMemberString to the group","k_0y7zd07":"Remove $invitedMemberString from the group","k_1d5mshh":"User $joinedMemberString joined the group","k_0yenqf0":"$userName was","k_0spotql":"Set $adminMember as admin","k_0pg5zzj":"System message: $operationType","k_1c7z88n":"[File] $fileName","k_1c3us5n":"The current group does not support @all","k_11k579v":"Invalid statements detected","k_0qba4ns":" attempted to access your $yoursItem","k_0oozw9x":"$diffMinutes minutes ago","k_13hzn00":"$yesterday, yesterday","k_0n9pyxz":"The user does not exist","k_1bjwemh":"Search by user ID","k_02owlq8":"My user ID: $userID","k_1wu8h4x":"Me: $showName","k_16758qw":"Add friend","k_1shx4d9":"Status: $selfSignature","k_0i553x0":"Enter verification information","k_031ocwx":"Enter remarks and list","k_003ojje":"Remarks","k_003lsav":"List","k_167bdvq":"My friends","k_156b4ut":"Friend request sent","k_1loix7s":"Group type: $groupType","k_1lqbsib":"The group chat does not exist","k_03h153m":"Search by group ID","k_0oxak3r":"Group request sent","k_1uh417q":"$displayName recalled a message","k_1aszp2k":"Are you sure you want to send the message again?","k_0h1ygf8":"Call initiated","k_0h169j0":"Call canceled","k_0h13jjk":"Call accepted","k_0h19hfx":"Call rejected","k_0obi9lh":"No answer","k_0ohzb9l":"Call duration: $callTime","k_0y9u662":"$appName currently does not support this file type. You can use another app to open and preview the file.","k_1ht1b80":"Receiving","k_0d5z4m5":"Select reminder receiver","k_1665ltg":"Initiate call","k_003kthh":"Photo","k_119ucng":"The image cannot be empty","k_0w9x8gw":"Selected successfully: $successPath","k_1np495n":"$messageString[Someone@me]","k_1m797yi":"$messageString[@all]","k_1uaov41":"Search for chat content","k_0bxm97s":"Admin ($adminNum/10)","k_0jayw3z":"Group members ($groupMemberNum members)","k_0h1svv1":"Delete group member","k_0h1g636":"Add group member","k_01yfa4o":"$memberCount members","k_0hpukyx":"View more group members","k_0qtsar0":"Mute notifications","k_03xd79d":"Status: $signature","k_1m9dftc":"All contacts","k_0em4gyz":"All group chats","k_002twmj":"Group chat","k_09kga0d":"More chat history","k_1ui5lzi":"$count messages are found","k_09khmso":"Related chat records","k_1kevf4k":"Chat history with $receiver","k_03ignw6":"All","k_03icaxo":"Custom","k_1969986":"[Voice Call]:$callingLastMsgShow","k_1960dlr":"[Video Call]:$callingLastMsgShow","k_1qbg9xc":"$option8 to ","k_1wq5ubm":"$option7 changed ","k_0y5pu80":"$option6 quit group chat","k_0nl7cmd":"Invite $option5 to the group","k_1ju5iqw":"Remove $option4 from the group","k_1ovt677":"User $option3 joined the group","k_0k05b8b":"$option2 was ","k_0wm4xeb":"System message: $option2","k_0nbq9v3":"Call duration: $option2","k_0i1kf53":"[File] $option2","k_1gnnby6":" attempted to access your $option2","k_1wh4atg":"$option2 minutes ago","k_07sh7g1":"$option2, yesterday","k_1pj8xzh":"My user ID: $option2","k_0py1evo":"Status: $option2","k_1kvj4i2":"$option2 recalled a message","k_1v0lbpp":"$option2 currently does not support this file type. You can use another app to open and preview the file.","k_0torwfz":"Selected successfully: $option2","k_0i1bjah":"$option1 recalled a message","k_1qzxh9q":"Call duration: $option3","k_0wrgmom":"[Voice Call]:$option1","k_06ix2f0":"[Video Call]:$option2","k_08o3z5w":"[File] $option1","k_0ezbepg":"$option2[Someone@me]","k_1ccnht1":"$option2[@all]","k_1k3arsw":"Admin ($option2/10)","k_1d4golg":"Group members ($option1 members)","k_1bg69nt":"$option1 members","k_00gjqxj":"Status: $option1","k_0c29cxr":"$option1 messages are found","k_1twk5rz":"Chat history with $option1","k_18o68ro":"Allow ","k_1onpf8u":" to access your camera to take photos, record videos, and make video calls.","k_17irga5":" to access your microphone to send voice messages, record videos, and make voice/video calls.","k_0572kc4":" to access your photos to send images and videos.","k_0slykws":" to access your album to save images and videos.","k_119pkcd":" to access your files to view, select and send files in a chat.","k_03c49qt":"Authorize now","k_0nt2uyg":"Back to the bottom","k_04l16at":"$option1 new messages","k_13p3w93":"Someone @ me","k_18w5uk6":"@ all","k_0jmujgh":"You are receiving other files","k_12s5ept":"Message details","k_0mxa4f4":"$option1 read","k_061tue3":"$option2 unread","k_1vn4xq1":"remove $adminMember from admin","k_0e35hsw":"Please allow us to use your camera to capture photos and videos sending to your friends and make video calls.","k_0dj6yr7":"Please allow us to use your microphone for sending voice message, make video/audio calls.","k_003qnsl":"Save","k_0s3rtpw":"Please allow us to access the media and files on your devices, in order to select and send to your friend, or save from them.","k_0tezv85":" Would like to access $option2","k_002rety":" permission. ","k_0gqewd3":"Later","k_03eq4s1":"Authorize Now","k_18qjstb":"Transfer Group","k_0on1aj2":"$option2 messages @ me","k_09j4izl":"[Someone @ me] ","k_1oqtjw0":"[@ all] ","k_1x5a9vb":"This is: $option1","k_14n31e7":"Add Group","k_08nc5j1":"Group type: $option1","k_1josu12":"$option1 group joining request(s)","k_0n2x5s0":"Verification message: $option2","k_03c1nx0":"Agreed","k_03aw9w8":"Rejected","k_038ryos":"Handle now","k_0gw8pum":"Add Group","k_1gcvfrj":"Please fill in the remarks","k_002v9zj":"确认","k_10oqrki":"轻触拍照","k_0f8b3ws":"加载失败","k_11cm5lm":"手动聚焦","k_002uzrd":"预览","k_003qkn3":"录像","k_003k6a7":"拍照","k_0bqpqco":"拍照按钮","k_1626ozl":"停止录像","k_003lvmu":"前置","k_003lued":"后置","k_003lwzh":"外置","k_002qzi3":"关闭","k_003pufb":"自动","k_0apm0ze":"拍照时闪光","k_157zog5":"始终闪光","k_0cfyqhy":"$option1 画面预览","k_0phctlz":"闪光模式: $option2","k_02vfqe0":"切换至 $option3 摄像头","k_0f0y9ex":"说话时间太短","k_0ln70tk":"无法打开URL","k_11a3jdv":"轻触拍照,长按摄像","k_1k18miv":"请传入离开群组生命周期函数,提供返回首页或其他页面的导航方法。","k_1fu9ahv":"全员禁言状态","k_0gmwbnd":"全员禁言中","k_0got2zr":"您被禁言","k_0y9jck8":"你必须自定义search bar,并处理点击跳转","k_0yum3tv":"如使用自定义区域,请在profileWidgetBuilder传入对应组件","k_09kalj0":"清空聊天记录","k_14j5iul":"删除并退出","k_125ru1w":"解散该群","k_0jtutmw":"退出后不会接收到此群聊消息","k_0jtzmqa":"解散后不会接收到此群聊消息","k_0r8fi93":"好友添加成功","k_02qw14e":"好友申请已发出","k_0n3md5x":"当前用户在黑名单","k_094phq4":"好友添加失败","k_129scag":"好友删除成功","k_129uzfn":"好友删除失败","k_1666isy":"清除好友","k_1679vrd":"加为好友","k_1ualc52":"看看对方带来的数据是啥","k_0szluvp":"设置对方在线状态","k_0f4rnf8":"该用户已是好友","k_1tdkom4":"您已是群成员","k_1p2lyuz":"对方正在输入中...","k_1g8wfpy":"...共$option1人","k_12rv9vw":"回应详情","k_0havgi0":"[查看详情 >>](${linkMessage.link})","k_0n9p7g8":"群组不存在","k_1tdh5vn":"您不是群成员","k_0h1q57v":"暂无群成员","k_0y5drq1":"[查看详情 >>]($option1)","k_03pjp61":"[表情消息]","k_1jpvzul":"[自定义消息]","k_03u3bh1":"[文件消息]","k_1odsnsw":"[群消息]","k_03sel4t":"[图片消息]","k_03sfw3r":"[位置消息]","k_03xpuwq":"[合并消息]","k_07ycxwo":"[没有元素]","k_03rc9vz":"[文本消息]","k_046uopf":"[视频消息]","k_0ehmsun":"设备存储空间不足,建议清理,以获得更好使用体验","k_003kmos":"图片","k_002s86q":"视频","k_06bk5ei":"视频消息仅限 mp4 格式","k_13opfxf":"Web网页端不支持搜索","k_1i0o0y2":"暂时仅限 Android/iOS 端","k_045dtzl":"$option1的聊天记录","k_0t0131u":"群资料信息","k_18ok8xz":"消息接收方式","k_03ax3ks":"群资料","k_0sqvoqo":"将 $option1 设置为管理员","k_1gbg1v8":"将 $option1 取消管理员","k_17k64g4":"群聊创建成功!","k_05mn217":"暂未安装表情包插件,如需使用表情相关功能,请根据本文档安装:https://cloud.tencent.com/document/product/269/70746","k_14j17nz":"暂无表情包","k_0fvjexh":"正在下载中","k_1cdagzz":"已加入待下载队列,其他文件下载中","k_0g4vojc":"开始下载","k_1g32es3":"[调皮]@2x.png","k_1g8qorz":"[爱你]@2x.png","k_1g4hmx6":"[爱情]@2x.png","k_1g6b558":"[爱心]@2x.png","k_1g3m4su":"[傲慢]@2x.png","k_1g2jym7":"[白眼]@2x.png","k_0cgkxuw":"[棒棒糖]@2x.png","k_1g48br2":"[抱抱]@2x.png","k_1g49ol8":"[抱拳]@2x.png","k_1g0ras3":"[爆筋]@2x.png","k_1ghy881":"[鄙视]@2x.png","k_1g86bmv":"[闭嘴]@2x.png","k_1g1xs1p":"[鞭炮]@2x.png","k_1g8i6ri":"[便便]@2x.png","k_1g2u5kf":"[擦汗]@2x.png","k_1g60uwh":"[彩带]@2x.png","k_1g1o0d0":"[彩球]@2x.png","k_1g6a6yq":"[菜刀]@2x.png","k_1g6vqo2":"[差劲]@2x.png","k_1g0kvjc":"[钞票]@2x.png","k_1g65x7e":"[车厢]@2x.png","k_0e1tjol":"[打哈欠]@2x.png","k_1g65n58":"[大兵]@2x.png","k_1g7se7o":"[大哭]@2x.png","k_1g03868":"[蛋糕]@2x.png","k_1h8nm66":"[刀]@2x.png","k_1g3dlpi":"[得意]@2x.png","k_1g3u434":"[灯泡]@2x.png","k_1giuqs7":"[凋谢]@2x.png","k_1g8r0r9":"[多云]@2x.png","k_1g7k6i1":"[发呆]@2x.png","k_1g44zsp":"[发抖]@2x.png","k_1g5l96i":"[飞机]@2x.png","k_1g7wsqj":"[飞吻]@2x.png","k_1g49luq":"[奋斗]@2x.png","k_1gixbsm":"[风车]@2x.png","k_1g6cqbq":"[尴尬]@2x.png","k_1g6jbw5":"[勾引]@2x.png","k_1g3lwo1":"[鼓掌]@2x.png","k_1g13nkj":"[害羞]@2x.png","k_1g0mt47":"[憨笑]@2x.png","k_0bxujkf":"[红灯笼]@2x.png","k_0hhaeh8":"[红双喜]@2x.png","k_1g0jnts":"[坏笑]@2x.png","k_1g46g9c":"[挥手]@2x.png","k_1g4vi9g":"[回头]@2x.png","k_1gf7hes":"[饥饿]@2x.png","k_1g6mvsm":"[激动]@2x.png","k_1gku5mf":"[街舞]@2x.png","k_1g4hidg":"[惊恐]@2x.png","k_1gjbrtu":"[惊讶]@2x.png","k_1g6sand":"[咖啡]@2x.png","k_1g4s8rj":"[磕头]@2x.png","k_1g1wn34":"[可爱]@2x.png","k_1g3l0wd":"[可怜]@2x.png","k_1ggaon9":"[抠鼻]@2x.png","k_1ggvcb0":"[骷髅]@2x.png","k_1h8yqjt":"[酷]@2x.png","k_0jac97i":"[快哭了]@2x.png","k_1h8oiby":"[困]@2x.png","k_1g0s5hg":"[蜡烛]@2x.png","k_1g1iuer":"[篮球]@2x.png","k_1g2xjfi":"[冷汗]@2x.png","k_0s5oyqw":"[礼品袋]@2x.png","k_1g1qqvf":"[礼物]@2x.png","k_1g2slew":"[流汗]@2x.png","k_1g3z9xx":"[流泪]@2x.png","k_1g6pabn":"[麻将]@2x.png","k_0pkaxul":"[麦克风]@2x.png","k_1g7m0zj":"[猫咪]@2x.png","k_0ibvtpo":"[么么哒]@2x.png","k_1g1hoh1":"[玫瑰]@2x.png","k_1gfzeow":"[米饭]@2x.png","k_1g5l15p":"[面条]@2x.png","k_1g2hfa6":"[奶瓶]@2x.png","k_1gix9pj":"[难过]@2x.png","k_1giqn6g":"[闹钟]@2x.png","k_1h8kd64":"[怒]@2x.png","k_1g0vui9":"[怄火]@2x.png","k_1g1jsj7":"[皮球]@2x.png","k_1ghdluw":"[啤酒]@2x.png","k_1gl6ec7":"[瓢虫]@2x.png","k_1g7gg5p":"[撇嘴]@2x.png","k_1g8psin":"[乒乓]@2x.png","k_1gjzu3p":"[汽车]@2x.png","k_1h8mr0k":"[强]@2x.png","k_1g45y2n":"[敲打]@2x.png","k_1gkaxsl":"[青蛙]@2x.png","k_0jcfnoo":"[糗大了]@2x.png","k_1g4njy1":"[拳头]@2x.png","k_1h8mqr3":"[弱]@2x.png","k_1h926fg":"[色]@2x.png","k_1g6rtbq":"[沙发]@2x.png","k_1giirh6":"[删除]@2x.png","k_1g14ny9":"[闪电]@2x.png","k_1g6bmsr":"[胜利]@2x.png","k_1g1rytx":"[示爱]@2x.png","k_1g52fbz":"[手枪]@2x.png","k_1h90dam":"[衰]@2x.png","k_1gigiae":"[睡觉]@2x.png","k_1gijchz":"[太阳]@2x.png","k_1g1sgji":"[跳绳]@2x.png","k_1gjwuri":"[跳跳]@2x.png","k_1g0juhk":"[偷笑]@2x.png","k_1h8nzla":"[吐]@2x.png","k_1g6cv0i":"[委屈]@2x.png","k_1g46l5g":"[握手]@2x.png","k_1g2pgkd":"[西瓜]@2x.png","k_1ging9p":"[下雨]@2x.png","k_1h8nzil":"[吓]@2x.png","k_1g7q7wr":"[献吻]@2x.png","k_1gl6uum":"[香蕉]@2x.png","k_1g23fys":"[象棋]@2x.png","k_0j75rdh":"[心碎了]@2x.png","k_1g6ajj2":"[信封]@2x.png","k_1g21prz":"[熊猫]@2x.png","k_1h8octi":"[嘘]@2x.png","k_1h91zox":"[药]@2x.png","k_1ghttfl":"[疑问]@2x.png","k_1ghk7sz":"[阴险]@2x.png","k_0gl37zz":"[右车头]@2x.png","k_0ifkj1p":"[右哼哼]@2x.png","k_0g1yh2e":"[右太极]@2x.png","k_1g9dkfc":"[雨伞]@2x.png","k_1g8jl88":"[月亮]@2x.png","k_1h8lhqj":"[晕]@2x.png","k_1gi9x2q":"[再见]@2x.png","k_1g6dwwv":"[炸弹]@2x.png","k_1fzmkfi":"[折磨]@2x.png","k_1g6jbiw":"[纸巾]@2x.png","k_1ggjnwu":"[咒骂]@2x.png","k_1g4qlq8":"[猪头]@2x.png","k_1g1lqzz":"[抓狂]@2x.png","k_1g80j3u":"[转圈]@2x.png","k_1g0z55s":"[龇牙]@2x.png","k_1g3ju6v":"[钻戒]@2x.png","k_0gl51l6":"[左车头]@2x.png","k_0iflllk":"[左哼哼]@2x.png","k_0g1y3ir":"[左太极]@2x.png","k_026hiq5":"消息列表加载中","k_003tu8k":"爱你","k_003myvp":"傲慢","k_003kddw":"白眼","k_039yfhv":"棒棒糖","k_003nu3p":"抱抱","k_003nijr":"抱拳","k_003mg88":"爆筋","k_002v17e":"鄙视","k_003qhy4":"闭嘴","k_003l5fq":"鞭炮","k_003uacl":"便便","k_003oq1g":"擦汗","k_003qvey":"彩带","k_003jci7":"彩球","k_003pyu1":"菜刀","k_003q97d":"差劲","k_003po5d":"车厢","k_03eadb2":"打哈欠","k_003pnuf":"大兵","k_003kg57":"蛋糕","k_003mxkt":"得意","k_003onu3":"灯泡","k_002uv8s":"凋谢","k_003kqy0":"调皮","k_003tyum":"多云","k_003pv9u":"发呆","k_036o6mu":"发抖t","k_003nogx":"飞机","k_003q7wg":"飞吻","k_003m0jd":"奋斗","k_002ult9":"风车","k_003r8gt":"尴尬","k_003qy4u":"勾引","k_003mnoa":"鼓掌","k_003lmw8":"害羞","k_003mb30":"憨笑","k_03bj41g":"红灯笼","k_03dxw2f":"红双喜","k_003mk57":"坏笑","k_003nmvf":"挥手","k_003r2i7":"回头","k_002s6f3":"饥饿","k_003qd0t":"激动","k_002vgi4":"街舞","k_003nz33":"惊恐","k_002wh4p":"惊讶","k_003ozpu":"咖啡","k_003qvs4":"磕头","k_003l3wb":"可爱","k_003nuwm":"可怜","k_002rw1q":"抠鼻","k_002tujb":"骷髅","k_00030eq":"酷","k_03i8ath":"快哭了","k_000421h":"困","k_003l5i7":"蜡烛","k_003j72g":"篮球","k_003ofwl":"冷汗","k_02mw65v":"礼品袋","k_003ku40":"礼物","k_003ookz":"流汗","k_003on72":"流泪","k_003rjy0":"麻将","k_003q2f8":"猫咪","k_03et393":"么么哒","k_003j7j2":"玫瑰","k_002sr0b":"米饭","k_003nnza":"面条","k_003jef9":"奶瓶","k_002umn0":"难过","k_002rjib":"闹钟","k_0003zcn":"怒","k_003jzwq":"怄火","k_003j4js":"皮球","k_002r5ir":"啤酒","k_002ubu4":"瓢虫","k_003ppo6":"撇嘴","k_003ty3o":"乒乓","k_002vxwe":"汽车","k_00043hb":"强","k_003nmbo":"敲打","k_002tfhq":"青蛙","k_03i7lrn":"糗大了","k_003r03m":"拳头","k_00043h0":"弱","k_000345z":"色","k_003qmp9":"沙发","k_003it8a":"闪电","k_003pxow":"胜利","k_003kw8e":"示爱","k_003n99g":"手枪","k_00035cl":"衰","k_002vl3h":"睡觉","k_002rgqk":"太阳","k_003m9d1":"跳绳","k_002vobp":"跳跳","k_003mkoz":"偷笑","k_00041px":"吐","k_003rjh5":"委屈","k_003j36u":"西瓜","k_002re92":"下雨","k_00041py":"吓","k_003q06o":"献吻","k_002ubjp":"香蕉","k_003o2tr":"象棋","k_03ie6pa":"心碎了","k_003rao5":"信封","k_003l3us":"熊猫","k_000424d":"嘘","k_00033yi":"药","k_002qtyy":"疑问","k_002qe0o":"阴险","k_03gu7us":"右车头","k_03ere8m":"右哼哼","k_003uqk3":"雨伞","k_003tzdv":"月亮","k_0003z00":"晕","k_002vdrd":"再见","k_003ra1w":"炸弹","k_003lcad":"折磨","k_003q7sz":"纸巾","k_002thn9":"咒骂","k_003qx7f":"猪头","k_003l044":"抓狂","k_003qg4h":"转圈","k_003kb97":"龇牙","k_03gu53l":"左车头","k_03erd1f":"左哼哼","k_003nyvl":"爱情","k_003r85z":"爱心","k_003mk8j":"钞票","k_003pwfj":"大哭","k_00042w5":"刀","k_003nmtr":"握手","k_03c529p":"右太极","k_003n4mk":"钻戒","k_03c5488":"左太极","k_1llp7tu":"该用户不存在","k_0tbyqyb":"加载中…","k_0td1p3f":"保存中…","k_1klqdh1":"仅限汉字、英文、数字和下划线","k_03el5lp":"未填写","k_1ui0gai":"搜索指定内容","k_003nvk2":"消息","k_03agld7":"群提示","k_0elt0kw":"添加群聊","k_0s3sgel":"移出黑名单","k_1qqgjra":"$option3条未读消息","k_0uubyjr":"以下为未读消息","k_16as7eq":"表情回应","k_003s12u":"回复","k_003s38r":"更多","k_002wkr3":"翻译","k_13g4hxv":"翻译完成","k_003molk":"表情","k_165bbw6":"消息历史","k_13sqc0z":"清除消息","k_0glns86":"删除会话","k_13s99rx":"清空消息","k_11vsa3j":"退出群组","k_11vvszp":"解散群组","k_15i9w72":"群管理员","k_0p3espj":"设置备注名","k_118sw9v":"立即搜索","k_0h20hg5":"视频通话","k_0h22snw":"语音通话","k_003lz6t":"对方","k_1xf4yre":"发送给$option1","k_003por5":"截图","k_1rw7s82":" 访问相册中视频权限,以正常使用发送视频等功能。","k_003rcwm":"打开","k_1698c42":"在访达中打开","k_066fxsz":"查看文件夹","k_0k432y2":"无法发送,包含文件夹","k_002wb4y":"会话","k_0od4qyh":"视频文件异常"} \ No newline at end of file +{"k_1fdhj9g":"This version does not support the message","k_06pujtm":"Accept all friend requests","k_0gyhkp5":"Require approval for friend requests","k_121ruco":"Reject all friend requests","k_05nspni":"Custom field","k_03fchyy":"Group profile photo","k_03i9mfe":"Group introduction","k_03agq58":"Group name","k_039xqny":"Group notification","k_003tr0a":"Group owner","k_002wddw":"Mute","k_0got6f7":"Unmute","k_1uaqed6":"[Custom]","k_0z2z7rx":"[Voice]","k_0y39ngu":"[Emoji]","k_0y1a2my":"[Image]","k_0z4fib8":"[Video]","k_0y24mcg":"[Location]","k_0pewpd1":"[Chat history]","k_13s8d9p":"Unknown message","k_003qkx2":"Calendar","k_003n2pz":"Camera","k_03idjo0":"Contact","k_003ltgm":"Location","k_02k3k86":"Mic","k_003pm7l":"Album","k_15ao57x":"Album write","k_164m3jd":"Local storage","k_03r6qyx":"We need your approval to get information.","k_02noktt":"Reject","k_00043x4":"Agree","k_003qzac":"Yesterday","k_003r39d":"2 days ago","k_03fqp9o":"Sun","k_03ibg5h":"Mon","k_03i7hu1":"Tue","k_03iaiks":"Wed","k_03el9pa":"Thu","k_03i7ok1":"Fri","k_03efxyg":"Sat","k_003q7ba":"Afternoon","k_003q7bb":"Morning","k_003pu3h":"Now","k_002rflt":"Delete","k_1don84v":"Failed to locate the original message","k_003q5fi":"Copy","k_003prq0":"Forward","k_002r1h2":"Multiple-choice","k_003j708":"Reference","k_003pqpr":"Recall","k_03ezhho":"Copied","k_11ctfsz":"Not implemented","k_1hbjg5g":"[Group system message]","k_03tvswb":"[Unknown message]","k_155cj23":"You've recalled a message.","k_0gapun3":"Edit it again","k_0003z7x":"You","k_002wfe4":"Read","k_002wjlg":"Unread","k_003nevv":"Cancel","k_001nmhu":"Open with another app","k_105682d":"Failed to load the image","k_0pytyeu":"Image saved successfully","k_0akceel":"Failed to save the image","k_003rk1s":"Save","k_04a0awq":"[Voice message]","k_105c3y3":"Failed to load the video","k_176rzr7":"Chat history","k_002r305":"Send","k_003n8b0":"Shoot","k_003tnp0":"File","k_0ylosxn":"Custom message","k_0jhdhtp":"Sending failed. The video cannot exceed 100 MB.","k_0am7r68":"Slide up to cancel","k_13dsw4l":"Release to cancel","k_15jl6qw":"Too short","k_0gx7vl6":"Press and hold to talk","k_15dlafd":"One-by-one forward","k_15dryxy":"Combine and forward","k_1eyhieh":"Are you sure you want to delete the selected message?","k_118prbn":"Search globally","k_003kv3v":"Search","k_17fmlyf":"Clear chat","k_0dhesoz":"Unpin from top","k_002sk7x":"Pin to top","k_003ll77":"Draft","k_003kfai":"Unknown","k_13dq4an":"Automatic approval","k_0l13cde":"Admin approval","k_11y8c6a":"Disallow group joining","k_1kvyskd":"Modification failed due to network disconnection","k_16payqf":"Group joining mode","k_0vzvn8r":"Modify group name","k_003rzap":"OK","k_038lh6u":"Group management","k_0k5wyiy":"Set admin","k_0goiuwk":"Mute all","k_1g889xx":"If you mute all, only the group owner and admin can speak.","k_0wlrefq":"Add group members to mute","k_0goox5g":"Mute","k_08daijh":"Admin role canceled successfully","k_0k5u935":"Add admin","k_003ngex":"Complete","k_03enyx5":"Group member","k_03erpei":"Admin","k_0qi9tno":"Group owner and admin","k_0uj7208":"Failed to view the group members due to network disconnection","k_0ef2a12":"Modify my nickname in group","k_1aajych":"2–20 characters, including digits, letters, and underscores","k_137pab5":"My nickname in group","k_0ivim6d":"No group notice","k_03eq6cn":"Group notice","k_002vxya":"Modify","k_03gu05e":"Chat room","k_03b4f3p":"Meeting group","k_03avj1p":"Public group","k_03asq2g":"Work group","k_03b3hbi":"Unknown group","k_03es1ox":"Group type","k_003mz1i":"Agree","k_003lpre":"Reject","k_003qk66":"Profile photo","k_003lhvk":"Nickname","k_003ps50":"Account","k_15lx52z":"Status","k_003qgkp":"Gender","k_003m6hr":"Date of birth","k_0003v6a":"Male","k_00043x2":"Female","k_03bcjkv":"Not set","k_11s0gdz":"Modify nickname","k_0p3j4sd":"Allows only letters, digits, and underscores","k_15lyvdt":"Modify status","k_0vylzjp":"None","k_1hs7ese":"Modify it later","k_03exjk7":"Remarks","k_0s3skfd":"Add to blocklist","k_17fpl3y":"Pin chat to top","k_0p3b31s":"Modify remarks","k_0003y9x":"None","k_11zgnfs":"Profile","k_1tez2xl":"No status","k_0vjj2kp":"Group chat history","k_003n2rp":"Select","k_1m9exwh":"Recent contacts","k_119nwqr":"The input cannot be empty","k_0pzwbmg":"Video saved successfully","k_0aktupv":"Failed to save the video","k_1yemzyd":"Received a message","k_13sajrj":"Emoji message","k_13sjeb7":"File message","k_0yd2ft8":"Group notification","k_13s7mxn":"Image message","k_13satlt":"Location message","k_00bbtsx":"Combined message","k_13sqwu4":"Voice message","k_13sqjjp":"Video message","k_03iqsh4":" $s to ","k_191t5n4":"$opUserNickName changed ","k_1pg6aoj":"$opUserNickName quit group chat","k_1f6zt3v":"Invite $invitedMemberString to the group","k_0y7zd07":"Remove $invitedMemberString from the group","k_1d5mshh":"User $joinedMemberString joined the group","k_0yenqf0":"$userName was","k_0spotql":"Set $adminMember as admin","k_0pg5zzj":"System message: $operationType","k_1c7z88n":"[File] $fileName","k_1c3us5n":"The current group does not support @all","k_11k579v":"Invalid statements detected","k_0qba4ns":" attempted to access your $yoursItem","k_0oozw9x":"$diffMinutes minutes ago","k_13hzn00":"$yesterday, yesterday","k_0n9pyxz":"The user does not exist","k_1bjwemh":"Search by user ID","k_02owlq8":"My user ID: $userID","k_1wu8h4x":"Me: $showName","k_16758qw":"Add friend","k_1shx4d9":"Status: $selfSignature","k_0i553x0":"Enter verification information","k_031ocwx":"Enter remarks and list","k_003ojje":"Remarks","k_003lsav":"List","k_167bdvq":"My friends","k_156b4ut":"Friend request sent","k_1loix7s":"Group type: $groupType","k_1lqbsib":"The group chat does not exist","k_03h153m":"Search by group ID","k_0oxak3r":"Group request sent","k_1uh417q":"$displayName recalled a message","k_1aszp2k":"Are you sure you want to send the message again?","k_0h1ygf8":"Call initiated","k_0h169j0":"Call canceled","k_0h13jjk":"Call accepted","k_0h19hfx":"Call rejected","k_0obi9lh":"No answer","k_0ohzb9l":"Call duration: $callTime","k_0y9u662":"$appName currently does not support this file type. You can use another app to open and preview the file.","k_1ht1b80":"Receiving","k_0d5z4m5":"Select reminder receiver","k_1665ltg":"Initiate call","k_003kthh":"Photo","k_119ucng":"The image cannot be empty","k_0w9x8gw":"Selected successfully: $successPath","k_1np495n":"$messageString[Someone@me]","k_1m797yi":"$messageString[@all]","k_1uaov41":"Search for chat content","k_0bxm97s":"Admin ($adminNum/10)","k_0jayw3z":"Group members ($groupMemberNum members)","k_0h1svv1":"Delete group member","k_0h1g636":"Add group member","k_01yfa4o":"$memberCount members","k_0hpukyx":"View more group members","k_0qtsar0":"Mute notifications","k_03xd79d":"Status: $signature","k_1m9dftc":"All contacts","k_0em4gyz":"All group chats","k_002twmj":"Group chat","k_09kga0d":"More chat history","k_1ui5lzi":"$count messages are found","k_09khmso":"Related chat records","k_1kevf4k":"Chat history with $receiver","k_03ignw6":"All","k_03icaxo":"Custom","k_1969986":"[Voice Call]:$callingLastMsgShow","k_1960dlr":"[Video Call]:$callingLastMsgShow","k_1qbg9xc":"$option8 to ","k_1wq5ubm":"$option7 changed ","k_0y5pu80":"$option6 quit group chat","k_0nl7cmd":"Invite $option5 to the group","k_1ju5iqw":"Remove $option4 from the group","k_1ovt677":"User $option3 joined the group","k_0k05b8b":"$option2 was ","k_0wm4xeb":"System message: $option2","k_0nbq9v3":"Call duration: $option2","k_0i1kf53":"[File] $option2","k_1gnnby6":" attempted to access your $option2","k_1wh4atg":"$option2 minutes ago","k_07sh7g1":"$option2, yesterday","k_1pj8xzh":"My user ID: $option2","k_0py1evo":"Status: $option2","k_1kvj4i2":"$option2 recalled a message","k_1v0lbpp":"$option2 currently does not support this file type. You can use another app to open and preview the file.","k_0torwfz":"Selected successfully: $option2","k_0i1bjah":"$option1 recalled a message","k_1qzxh9q":"Call duration: $option3","k_0wrgmom":"[Voice Call]:$option1","k_06ix2f0":"[Video Call]:$option2","k_08o3z5w":"[File] $option1","k_0ezbepg":"$option2[Someone@me]","k_1ccnht1":"$option2[@all]","k_1k3arsw":"Admin ($option2/10)","k_1d4golg":"Group members ($option1 members)","k_1bg69nt":"$option1 members","k_00gjqxj":"Status: $option1","k_0c29cxr":"$option1 messages are found","k_1twk5rz":"Chat history with $option1","k_18o68ro":"Allow ","k_1onpf8u":" to access your camera to take photos, record videos, and make video calls.","k_17irga5":" to access your microphone to send voice messages, record videos, and make voice/video calls.","k_0572kc4":" to access your photos to send images and videos.","k_0slykws":" to access your album to save images and videos.","k_119pkcd":" to access your files to view, select and send files in a chat.","k_03c49qt":"Authorize now","k_0nt2uyg":"Back to the bottom","k_04l16at":"$option1 new messages","k_13p3w93":"Someone @ me","k_18w5uk6":"@ all","k_0jmujgh":"You are receiving other files","k_12s5ept":"Message details","k_0mxa4f4":"$option1 read","k_061tue3":"$option2 unread","k_1vn4xq1":"remove $adminMember from admin","k_0e35hsw":"Please allow us to use your camera to capture photos and videos sending to your friends and make video calls.","k_0dj6yr7":"Please allow us to use your microphone for sending voice message, make video/audio calls.","k_003qnsl":"Save","k_0s3rtpw":"Please allow us to access the media and files on your devices, in order to select and send to your friend, or save from them.","k_0tezv85":" Would like to access $option2","k_002rety":" permission. ","k_0gqewd3":"Later","k_03eq4s1":"Authorize Now","k_18qjstb":"Transfer Group","k_0on1aj2":"$option2 messages @ me","k_09j4izl":"[Someone @ me] ","k_1oqtjw0":"[@ all] ","k_1x5a9vb":"This is: $option1","k_14n31e7":"Add Group","k_08nc5j1":"Group type: $option1","k_1josu12":"$option1 group joining request(s)","k_0n2x5s0":"Verification message: $option2","k_03c1nx0":"Agreed","k_03aw9w8":"Rejected","k_038ryos":"Handle now","k_0gw8pum":"Add Group","k_1gcvfrj":"Please fill in the remarks","k_002v9zj":"确认","k_10oqrki":"轻触拍照","k_0f8b3ws":"加载失败","k_11cm5lm":"手动聚焦","k_002uzrd":"预览","k_003qkn3":"录像","k_003k6a7":"拍照","k_0bqpqco":"拍照按钮","k_1626ozl":"停止录像","k_003lvmu":"前置","k_003lued":"后置","k_003lwzh":"外置","k_002qzi3":"关闭","k_003pufb":"自动","k_0apm0ze":"拍照时闪光","k_157zog5":"始终闪光","k_0cfyqhy":"$option1 画面预览","k_0phctlz":"闪光模式: $option2","k_02vfqe0":"切换至 $option3 摄像头","k_0f0y9ex":"说话时间太短","k_0ln70tk":"无法打开URL","k_11a3jdv":"轻触拍照,长按摄像","k_1k18miv":"请传入离开群组生命周期函数,提供返回首页或其他页面的导航方法。","k_1fu9ahv":"全员禁言状态","k_0gmwbnd":"全员禁言中","k_0got2zr":"您被禁言","k_0y9jck8":"你必须自定义search bar,并处理点击跳转","k_0yum3tv":"如使用自定义区域,请在profileWidgetBuilder传入对应组件","k_09kalj0":"清空聊天记录","k_14j5iul":"删除并退出","k_125ru1w":"解散该群","k_0jtutmw":"退出后不会接收到此群聊消息","k_0jtzmqa":"解散后不会接收到此群聊消息","k_0r8fi93":"好友添加成功","k_02qw14e":"好友申请已发出","k_0n3md5x":"当前用户在黑名单","k_094phq4":"好友添加失败","k_129scag":"好友删除成功","k_129uzfn":"好友删除失败","k_1666isy":"清除好友","k_1679vrd":"加为好友","k_1ualc52":"看看对方带来的数据是啥","k_0szluvp":"设置对方在线状态","k_0f4rnf8":"该用户已是好友","k_1tdkom4":"您已是群成员","k_1p2lyuz":"对方正在输入中...","k_1g8wfpy":"...共$option1人","k_12rv9vw":"回应详情","k_0havgi0":"[查看详情 >>](${linkMessage.link})","k_0n9p7g8":"群组不存在","k_1tdh5vn":"您不是群成员","k_0h1q57v":"暂无群成员","k_0y5drq1":"[查看详情 >>]($option1)","k_03pjp61":"[表情消息]","k_1jpvzul":"[自定义消息]","k_03u3bh1":"[文件消息]","k_1odsnsw":"[群消息]","k_03sel4t":"[图片消息]","k_03sfw3r":"[位置消息]","k_03xpuwq":"[合并消息]","k_07ycxwo":"[没有元素]","k_03rc9vz":"[文本消息]","k_046uopf":"[视频消息]","k_0ehmsun":"设备存储空间不足,建议清理,以获得更好使用体验","k_003kmos":"图片","k_002s86q":"视频","k_06bk5ei":"视频消息仅限 mp4 格式","k_13opfxf":"Web网页端不支持搜索","k_1i0o0y2":"暂时仅限 Android/iOS 端","k_045dtzl":"$option1的聊天记录","k_0t0131u":"群资料信息","k_18ok8xz":"消息接收方式","k_03ax3ks":"群资料","k_0sqvoqo":"将 $option1 设置为管理员","k_1gbg1v8":"将 $option1 取消管理员","k_17k64g4":"群聊创建成功!","k_05mn217":"暂未安装表情包插件,如需使用表情相关功能,请根据本文档安装:https://cloud.tencent.com/document/product/269/70746","k_14j17nz":"暂无表情包","k_0fvjexh":"正在下载中","k_1cdagzz":"已加入待下载队列,其他文件下载中","k_0g4vojc":"开始下载","k_1g32es3":"[调皮]@2x.png","k_1g8qorz":"[爱你]@2x.png","k_1g4hmx6":"[爱情]@2x.png","k_1g6b558":"[爱心]@2x.png","k_1g3m4su":"[傲慢]@2x.png","k_1g2jym7":"[白眼]@2x.png","k_0cgkxuw":"[棒棒糖]@2x.png","k_1g48br2":"[抱抱]@2x.png","k_1g49ol8":"[抱拳]@2x.png","k_1g0ras3":"[爆筋]@2x.png","k_1ghy881":"[鄙视]@2x.png","k_1g86bmv":"[闭嘴]@2x.png","k_1g1xs1p":"[鞭炮]@2x.png","k_1g8i6ri":"[便便]@2x.png","k_1g2u5kf":"[擦汗]@2x.png","k_1g60uwh":"[彩带]@2x.png","k_1g1o0d0":"[彩球]@2x.png","k_1g6a6yq":"[菜刀]@2x.png","k_1g6vqo2":"[差劲]@2x.png","k_1g0kvjc":"[钞票]@2x.png","k_1g65x7e":"[车厢]@2x.png","k_0e1tjol":"[打哈欠]@2x.png","k_1g65n58":"[大兵]@2x.png","k_1g7se7o":"[大哭]@2x.png","k_1g03868":"[蛋糕]@2x.png","k_1h8nm66":"[刀]@2x.png","k_1g3dlpi":"[得意]@2x.png","k_1g3u434":"[灯泡]@2x.png","k_1giuqs7":"[凋谢]@2x.png","k_1g8r0r9":"[多云]@2x.png","k_1g7k6i1":"[发呆]@2x.png","k_1g44zsp":"[发抖]@2x.png","k_1g5l96i":"[飞机]@2x.png","k_1g7wsqj":"[飞吻]@2x.png","k_1g49luq":"[奋斗]@2x.png","k_1gixbsm":"[风车]@2x.png","k_1g6cqbq":"[尴尬]@2x.png","k_1g6jbw5":"[勾引]@2x.png","k_1g3lwo1":"[鼓掌]@2x.png","k_1g13nkj":"[害羞]@2x.png","k_1g0mt47":"[憨笑]@2x.png","k_0bxujkf":"[红灯笼]@2x.png","k_0hhaeh8":"[红双喜]@2x.png","k_1g0jnts":"[坏笑]@2x.png","k_1g46g9c":"[挥手]@2x.png","k_1g4vi9g":"[回头]@2x.png","k_1gf7hes":"[饥饿]@2x.png","k_1g6mvsm":"[激动]@2x.png","k_1gku5mf":"[街舞]@2x.png","k_1g4hidg":"[惊恐]@2x.png","k_1gjbrtu":"[惊讶]@2x.png","k_1g6sand":"[咖啡]@2x.png","k_1g4s8rj":"[磕头]@2x.png","k_1g1wn34":"[可爱]@2x.png","k_1g3l0wd":"[可怜]@2x.png","k_1ggaon9":"[抠鼻]@2x.png","k_1ggvcb0":"[骷髅]@2x.png","k_1h8yqjt":"[酷]@2x.png","k_0jac97i":"[快哭了]@2x.png","k_1h8oiby":"[困]@2x.png","k_1g0s5hg":"[蜡烛]@2x.png","k_1g1iuer":"[篮球]@2x.png","k_1g2xjfi":"[冷汗]@2x.png","k_0s5oyqw":"[礼品袋]@2x.png","k_1g1qqvf":"[礼物]@2x.png","k_1g2slew":"[流汗]@2x.png","k_1g3z9xx":"[流泪]@2x.png","k_1g6pabn":"[麻将]@2x.png","k_0pkaxul":"[麦克风]@2x.png","k_1g7m0zj":"[猫咪]@2x.png","k_0ibvtpo":"[么么哒]@2x.png","k_1g1hoh1":"[玫瑰]@2x.png","k_1gfzeow":"[米饭]@2x.png","k_1g5l15p":"[面条]@2x.png","k_1g2hfa6":"[奶瓶]@2x.png","k_1gix9pj":"[难过]@2x.png","k_1giqn6g":"[闹钟]@2x.png","k_1h8kd64":"[怒]@2x.png","k_1g0vui9":"[怄火]@2x.png","k_1g1jsj7":"[皮球]@2x.png","k_1ghdluw":"[啤酒]@2x.png","k_1gl6ec7":"[瓢虫]@2x.png","k_1g7gg5p":"[撇嘴]@2x.png","k_1g8psin":"[乒乓]@2x.png","k_1gjzu3p":"[汽车]@2x.png","k_1h8mr0k":"[强]@2x.png","k_1g45y2n":"[敲打]@2x.png","k_1gkaxsl":"[青蛙]@2x.png","k_0jcfnoo":"[糗大了]@2x.png","k_1g4njy1":"[拳头]@2x.png","k_1h8mqr3":"[弱]@2x.png","k_1h926fg":"[色]@2x.png","k_1g6rtbq":"[沙发]@2x.png","k_1giirh6":"[删除]@2x.png","k_1g14ny9":"[闪电]@2x.png","k_1g6bmsr":"[胜利]@2x.png","k_1g1rytx":"[示爱]@2x.png","k_1g52fbz":"[手枪]@2x.png","k_1h90dam":"[衰]@2x.png","k_1gigiae":"[睡觉]@2x.png","k_1gijchz":"[太阳]@2x.png","k_1g1sgji":"[跳绳]@2x.png","k_1gjwuri":"[跳跳]@2x.png","k_1g0juhk":"[偷笑]@2x.png","k_1h8nzla":"[吐]@2x.png","k_1g6cv0i":"[委屈]@2x.png","k_1g46l5g":"[握手]@2x.png","k_1g2pgkd":"[西瓜]@2x.png","k_1ging9p":"[下雨]@2x.png","k_1h8nzil":"[吓]@2x.png","k_1g7q7wr":"[献吻]@2x.png","k_1gl6uum":"[香蕉]@2x.png","k_1g23fys":"[象棋]@2x.png","k_0j75rdh":"[心碎了]@2x.png","k_1g6ajj2":"[信封]@2x.png","k_1g21prz":"[熊猫]@2x.png","k_1h8octi":"[嘘]@2x.png","k_1h91zox":"[药]@2x.png","k_1ghttfl":"[疑问]@2x.png","k_1ghk7sz":"[阴险]@2x.png","k_0gl37zz":"[右车头]@2x.png","k_0ifkj1p":"[右哼哼]@2x.png","k_0g1yh2e":"[右太极]@2x.png","k_1g9dkfc":"[雨伞]@2x.png","k_1g8jl88":"[月亮]@2x.png","k_1h8lhqj":"[晕]@2x.png","k_1gi9x2q":"[再见]@2x.png","k_1g6dwwv":"[炸弹]@2x.png","k_1fzmkfi":"[折磨]@2x.png","k_1g6jbiw":"[纸巾]@2x.png","k_1ggjnwu":"[咒骂]@2x.png","k_1g4qlq8":"[猪头]@2x.png","k_1g1lqzz":"[抓狂]@2x.png","k_1g80j3u":"[转圈]@2x.png","k_1g0z55s":"[龇牙]@2x.png","k_1g3ju6v":"[钻戒]@2x.png","k_0gl51l6":"[左车头]@2x.png","k_0iflllk":"[左哼哼]@2x.png","k_0g1y3ir":"[左太极]@2x.png","k_026hiq5":"消息列表加载中","k_003tu8k":"爱你","k_003myvp":"傲慢","k_003kddw":"白眼","k_039yfhv":"棒棒糖","k_003nu3p":"抱抱","k_003nijr":"抱拳","k_003mg88":"爆筋","k_002v17e":"鄙视","k_003qhy4":"闭嘴","k_003l5fq":"鞭炮","k_003uacl":"便便","k_003oq1g":"擦汗","k_003qvey":"彩带","k_003jci7":"彩球","k_003pyu1":"菜刀","k_003q97d":"差劲","k_003po5d":"车厢","k_03eadb2":"打哈欠","k_003pnuf":"大兵","k_003kg57":"蛋糕","k_003mxkt":"得意","k_003onu3":"灯泡","k_002uv8s":"凋谢","k_003kqy0":"调皮","k_003tyum":"多云","k_003pv9u":"发呆","k_036o6mu":"发抖t","k_003nogx":"飞机","k_003q7wg":"飞吻","k_003m0jd":"奋斗","k_002ult9":"风车","k_003r8gt":"尴尬","k_003qy4u":"勾引","k_003mnoa":"鼓掌","k_003lmw8":"害羞","k_003mb30":"憨笑","k_03bj41g":"红灯笼","k_03dxw2f":"红双喜","k_003mk57":"坏笑","k_003nmvf":"挥手","k_003r2i7":"回头","k_002s6f3":"饥饿","k_003qd0t":"激动","k_002vgi4":"街舞","k_003nz33":"惊恐","k_002wh4p":"惊讶","k_003ozpu":"咖啡","k_003qvs4":"磕头","k_003l3wb":"可爱","k_003nuwm":"可怜","k_002rw1q":"抠鼻","k_002tujb":"骷髅","k_00030eq":"酷","k_03i8ath":"快哭了","k_000421h":"困","k_003l5i7":"蜡烛","k_003j72g":"篮球","k_003ofwl":"冷汗","k_02mw65v":"礼品袋","k_003ku40":"礼物","k_003ookz":"流汗","k_003on72":"流泪","k_003rjy0":"麻将","k_003q2f8":"猫咪","k_03et393":"么么哒","k_003j7j2":"玫瑰","k_002sr0b":"米饭","k_003nnza":"面条","k_003jef9":"奶瓶","k_002umn0":"难过","k_002rjib":"闹钟","k_0003zcn":"怒","k_003jzwq":"怄火","k_003j4js":"皮球","k_002r5ir":"啤酒","k_002ubu4":"瓢虫","k_003ppo6":"撇嘴","k_003ty3o":"乒乓","k_002vxwe":"汽车","k_00043hb":"强","k_003nmbo":"敲打","k_002tfhq":"青蛙","k_03i7lrn":"糗大了","k_003r03m":"拳头","k_00043h0":"弱","k_000345z":"色","k_003qmp9":"沙发","k_003it8a":"闪电","k_003pxow":"胜利","k_003kw8e":"示爱","k_003n99g":"手枪","k_00035cl":"衰","k_002vl3h":"睡觉","k_002rgqk":"太阳","k_003m9d1":"跳绳","k_002vobp":"跳跳","k_003mkoz":"偷笑","k_00041px":"吐","k_003rjh5":"委屈","k_003j36u":"西瓜","k_002re92":"下雨","k_00041py":"吓","k_003q06o":"献吻","k_002ubjp":"香蕉","k_003o2tr":"象棋","k_03ie6pa":"心碎了","k_003rao5":"信封","k_003l3us":"熊猫","k_000424d":"嘘","k_00033yi":"药","k_002qtyy":"疑问","k_002qe0o":"阴险","k_03gu7us":"右车头","k_03ere8m":"右哼哼","k_003uqk3":"雨伞","k_003tzdv":"月亮","k_0003z00":"晕","k_002vdrd":"再见","k_003ra1w":"炸弹","k_003lcad":"折磨","k_003q7sz":"纸巾","k_002thn9":"咒骂","k_003qx7f":"猪头","k_003l044":"抓狂","k_003qg4h":"转圈","k_003kb97":"龇牙","k_03gu53l":"左车头","k_03erd1f":"左哼哼","k_003nyvl":"爱情","k_003r85z":"爱心","k_003mk8j":"钞票","k_003pwfj":"大哭","k_00042w5":"刀","k_003nmtr":"握手","k_03c529p":"右太极","k_003n4mk":"钻戒","k_03c5488":"左太极","k_1llp7tu":"该用户不存在","k_0tbyqyb":"加载中…","k_0td1p3f":"保存中…","k_1klqdh1":"仅限汉字、英文、数字和下划线","k_03el5lp":"未填写","k_1ui0gai":"搜索指定内容","k_003nvk2":"消息","k_03agld7":"群提示","k_0elt0kw":"添加群聊","k_0s3sgel":"移出黑名单","k_1qqgjra":"$option3条未读消息","k_0uubyjr":"以下为未读消息","k_16as7eq":"表情回应","k_003s12u":"回复","k_003s38r":"更多","k_002wkr3":"翻译","k_13g4hxv":"翻译完成","k_003molk":"表情","k_165bbw6":"消息历史","k_13sqc0z":"清除消息","k_0glns86":"删除会话","k_13s99rx":"清空消息","k_11vsa3j":"退出群组","k_11vvszp":"解散群组","k_15i9w72":"群管理员","k_0p3espj":"设置备注名","k_118sw9v":"立即搜索","k_0h20hg5":"视频通话","k_0h22snw":"语音通话","k_003lz6t":"对方","k_1xf4yre":"发送给$option1","k_003por5":"截图","k_1rw7s82":" 访问相册中视频权限,以正常使用发送视频等功能。","k_003rcwm":"打开","k_1698c42":"在访达中打开","k_066fxsz":"查看文件夹","k_0k432y2":"无法发送,包含文件夹","k_002wb4y":"会话","k_0od4qyh":"视频文件异常","k_1bfkxg9":"不支持 0KB 文件的传输","k_0vvsw7g":"文件处理异常","k_06e224q":"[消息被管理员撤回]","k_1u1mjcl":"[消息被撤回]","k_1qcqxea":"选择多个会话","k_1qgmc20":"选择一个会话","k_1d8nx6f":"在新窗口中打开","k_1hz05ax":"正在下载原始资源,请稍候..."} \ No newline at end of file diff --git a/lib/i18n/strings_zh-Hans.i18n.json b/lib/i18n/strings_zh-Hans.i18n.json index cab5bb7..eac5acd 100644 --- a/lib/i18n/strings_zh-Hans.i18n.json +++ b/lib/i18n/strings_zh-Hans.i18n.json @@ -689,5 +689,13 @@ "k_066fxsz": "查看文件夹", "k_0k432y2": "无法发送,包含文件夹", "k_002wb4y": "会话", - "k_0od4qyh": "视频文件异常" + "k_0od4qyh": "视频文件异常", + "k_1bfkxg9": "不支持 0KB 文件的传输", + "k_0vvsw7g": "文件处理异常", + "k_06e224q": "[消息被管理员撤回]", + "k_1u1mjcl": "[消息被撤回]", + "k_1qcqxea": "选择多个会话", + "k_1qgmc20": "选择一个会话", + "k_1d8nx6f": "在新窗口中打开", + "k_1hz05ax": "正在下载原始资源,请稍候..." } \ No newline at end of file diff --git a/lib/i18n/strings_zh-Hant.i18n.json b/lib/i18n/strings_zh-Hant.i18n.json index 46b286f..3128188 100644 --- a/lib/i18n/strings_zh-Hant.i18n.json +++ b/lib/i18n/strings_zh-Hant.i18n.json @@ -1 +1 @@ -{"k_1yemzyd":"收到一條訊息","k_0ylosxn":"自定義訊息","k_13sajrj":"貼圖訊息","k_13sjeb7":"檔案訊息","k_0yd2ft8":"群提示訊息","k_13s7mxn":"圖片訊息","k_13satlt":"位置訊息","k_00bbtsx":"合並轉發訊息","k_13sqwu4":"語音訊息","k_13sqjjp":"影片","k_1fdhj9g":"該版本不支持此訊息","k_06pujtm":"同意任何用戶添加好友","k_0gyhkp5":"需要驗證","k_121ruco":"拒絕任何人加好友","k_05nspni":"自定義字段","k_03fchyy":"群頭像","k_03i9mfe":"群簡介","k_03agq58":"群名稱","k_039xqny":"群通知","k_003tr0a":"群主","k_03iqsh4":"$s為 ","k_191t5n4":"$opUserNickName修改","k_1pg6aoj":"$opUserNickName退出群組","k_1f6zt3v":"邀請$invitedMemberString加入群組","k_0y7zd07":"將$invitedMemberString踢出群組","k_03c49qt":"去授權","k_1d5mshh":"用戶$joinedMemberString加入了群組","k_002wddw":"禁言","k_0got6f7":"解除禁言","k_0yenqf0":"$userName 被","k_0spotql":"將 $adminMember 設置為管理員","k_0pg5zzj":"系統訊息 $operationType","k_0ohzb9l":"通話時間:$callTime","k_1uaqed6":"[自定義]","k_0z2z7rx":"[語音]","k_0y39ngu":"[貼圖]","k_1c7z88n":"[檔案] $fileName","k_0y1a2my":"[圖片]","k_0z4fib8":"[影片]","k_0y24mcg":"[位置]","k_0pewpd1":"[聊天記錄]","k_13s8d9p":"未知訊息","k_1c3us5n":"當前群組不支持@全體成員","k_11k579v":"發言中有非法語句","k_003qkx2":"日歷","k_003n2pz":"相機","k_03idjo0":"聯絡人","k_003ltgm":"位置","k_02k3k86":"咪高風","k_003pm7l":"相冊","k_15ao57x":"相冊寫入","k_164m3jd":"本地存儲","k_0qba4ns":"想訪問您的$yoursItem","k_03r6qyx":"我們需要您的同意才能獲取信息","k_02noktt":"不允許","k_00043x4":"好","k_003qzac":"昨天","k_003r39d":"前天","k_03fqp9o":"星期天","k_03ibg5h":"星期一","k_03i7hu1":"星期二","k_03iaiks":"星期三","k_03el9pa":"星期四","k_03i7ok1":"星期五","k_03efxyg":"星期六","k_0oozw9x":"$diffMinutes 分鐘前","k_003q7ba":"下午","k_003q7bb":"上午","k_003pu3h":"現在","k_13hzn00":"昨天 $yesterday","k_0n9pyxz":"用戶不存在","k_1bjwemh":"搜尋用戶 ID","k_003kv3v":"搜尋","k_02owlq8":"我的用戶ID: $userID","k_1wu8h4x":"我是: $showName","k_16758qw":"添加好友","k_1shx4d9":"個性簽名: $selfSignature","k_0i553x0":"填寫驗證信息","k_031ocwx":"請填寫備註和分組","k_003ojje":"備註","k_003lsav":"分組","k_167bdvq":"我的好友","k_156b4ut":"好友申請已發送","k_002r305":"發送","k_03gu05e":"聊天室","k_03b4f3p":"會議群","k_03avj1p":"公開群","k_03asq2g":"工作群","k_03b3hbi":"未知群","k_1loix7s":"群類型: $groupType","k_1lqbsib":"該群組不存在","k_03h153m":"搜尋群ID","k_0oxak3r":"群申請已發送","k_002rflt":"刪除","k_1don84v":"無法定位到原訊息","k_003q5fi":"復製","k_003prq0":"轉發","k_002r1h2":"多選","k_003j708":"引用","k_003pqpr":"回收","k_03ezhho":"已復製","k_11ctfsz":"暫未實現","k_1hbjg5g":"[群系統訊息]","k_03tvswb":"[未知訊息]","k_155cj23":"您回收了一條訊息,","k_0gapun3":"重新編輯","k_1uh417q":"$displayName回收了一條訊息","k_1aszp2k":"您確定要重發這條訊息麽?","k_003rzap":"確定","k_003nevv":"取消","k_0003z7x":"您","k_002wfe4":"已讀","k_002wjlg":"未讀","k_0h1ygf8":"發起通話","k_0h169j0":"取消通話","k_0h13jjk":"接受通話","k_0h19hfx":"拒絕通話","k_0obi9lh":"超時未接聽","k_0y9u662":"「$appName」暫不可以開啟此類檔案,你可以使用其他應用開啟並預覽","k_001nmhu":"用其他應用開啟","k_1ht1b80":"正在接收中","k_105682d":"圖片載入失敗","k_0pytyeu":"圖片保存成功","k_0akceel":"圖片保存失敗","k_003rk1s":"保存","k_04a0awq":"[語音訊息]","k_105c3y3":"影片載入失敗","k_176rzr7":"聊天記錄","k_0d5z4m5":"選擇提醒人","k_003ngex":"完成","k_1665ltg":"發起呼叫","k_003n8b0":"拍攝","k_003kthh":"照片","k_003tnp0":"檔案","k_0jhdhtp":"發送失敗,影片不能大於100MB","k_119ucng":"圖片不能為空","k_0w9x8gw":"選擇成功$successPath","k_13dsw4l":"松開取消","k_0am7r68":"手指上滑,取消發送","k_15jl6qw":"說話時間太短!","k_0gx7vl6":"按住說話","k_15dlafd":"逐條轉發","k_15dryxy":"合並轉發","k_1eyhieh":"確定刪除已選訊息","k_17fmlyf":"清除聊天","k_0dhesoz":"取消置頂","k_002sk7x":"置頂","k_003ll77":"草稿","k_03icaxo":"自定義","k_1969986":"[語音通話]:$callingLastMsgShow","k_1960dlr":"[視訊通話]:$callingLastMsgShow","k_1np495n":"$messageString[有人@我]","k_1m797yi":"$messageString[@所有人]","k_1uaov41":"查找聊天內容","k_003kfai":"未知","k_13dq4an":"自動審批","k_0l13cde":"管理員審批","k_11y8c6a":"禁止加群","k_1kvyskd":"無網絡連接,無法修改","k_16payqf":"加群方式","k_0vzvn8r":"修改群名稱","k_038lh6u":"群管理","k_0k5wyiy":"設置管理員","k_0goiuwk":"全員禁言","k_1g889xx":"全員禁言開啟後,只允許群主和管理員發言。","k_0wlrefq":"添加需要禁言的群成員","k_0goox5g":"設置禁言","k_08daijh":"成功取消管理員身份","k_0bxm97s":"管理員 ($adminNum/10)","k_0k5u935":"添加管理員","k_03enyx5":"群成員","k_0jayw3z":"群成員($groupMemberNum人)","k_0h1svv1":"刪除群成員","k_0h1g636":"添加群成員","k_0uj7208":"無網絡連接,無法查看群成員","k_01yfa4o":"$memberCount人","k_0hpukyx":"查看更多群成員","k_0qtsar0":"訊息免打擾","k_0ef2a12":"修改我的群昵稱","k_1aajych":"僅限中文、字母、數字和下劃線,2-20個字","k_137pab5":"我的群昵稱","k_0ivim6d":"暫無群公告","k_03eq6cn":"群公告","k_002vxya":"編輯","k_17fpl3y":"置頂聊天","k_03es1ox":"群類型","k_003mz1i":"同意","k_003lpre":"拒絕","k_003qk66":"頭像","k_003lhvk":"昵稱","k_003ps50":"賬號","k_15lx52z":"個性簽名","k_003qgkp":"性別","k_003m6hr":"生日","k_0003v6a":"男","k_00043x2":"女","k_03bcjkv":"未設置","k_11s0gdz":"修改昵稱","k_0p3j4sd":"僅限中字、字母、數字和下劃線","k_15lyvdt":"修改簽名","k_0vylzjp":"這個人很懶,什麽也沒寫","k_1hs7ese":"等上線再改這個","k_03exjk7":"備註名","k_0s3skfd":"加入黑名單","k_0p3b31s":"修改備註名","k_0003y9x":"無","k_11zgnfs":"個人資料","k_03xd79d":"個性簽名: $signature","k_1tez2xl":"暫無個性簽名","k_118prbn":"全局搜尋","k_1m9dftc":"全部聯絡人","k_0em4gyz":"全部群組","k_002twmj":"群組","k_09kga0d":"更多聊天記錄","k_1ui5lzi":"$count條相關聊天記錄","k_09khmso":"相關聊天記錄","k_1kevf4k":"與$receiver的聊天記錄","k_0vjj2kp":"群組的聊天記錄","k_003n2rp":"選擇","k_03ignw6":"所有人","k_03erpei":"管理員","k_0qi9tno":"群主、管理員","k_1m9exwh":"最近聯絡人","k_119nwqr":"輸入不能為空","k_0pzwbmg":"影片保存成功","k_0aktupv":"影片保存失敗","k_1qbg9xc":"$option8為 ","k_1wq5ubm":"$option7修改","k_0y5pu80":"$option6退出群組","k_0nl7cmd":"邀請$option5加入群組","k_1ju5iqw":"將$option4踢出群組","k_1ovt677":"用戶$option3加入了群組","k_0k05b8b":"$option2 被","k_0wm4xeb":"系統訊息 $option2","k_0nbq9v3":"通話時間:$option2","k_0i1kf53":"[檔案] $option2","k_1gnnby6":"想訪問您的$option2","k_1wh4atg":"$option2 分鐘前","k_07sh7g1":"昨天 $option2","k_1pj8xzh":"我的用戶ID: $option2","k_0py1evo":"個性簽名: $option2","k_1kvj4i2":"$option2回收了一條訊息","k_1v0lbpp":"「$option2」暫不可以開啟此類檔案,你可以使用其他應用開啟並預覽","k_0torwfz":"選擇成功$option2","k_0i1bjah":"$option1回收了一條訊息","k_1qzxh9q":"通話時間:$option3","k_0wrgmom":"[語音通話]:$option1","k_06ix2f0":"[視訊通話]:$option2","k_08o3z5w":"[檔案] $option1","k_0ezbepg":"$option2[有人@我]","k_1ccnht1":"$option2[@所有人]","k_1k3arsw":"管理員 ($option2/10)","k_1d4golg":"群成員($option1人)","k_1bg69nt":"$option1人","k_00gjqxj":"個性簽名: $option1","k_0c29cxr":"$option1條相關聊天記錄","k_1twk5rz":"與$option1的聊天記錄","k_1vn4xq1":"將 $adminMember 取消管理員","k_0e35hsw":"為方便您將所拍攝的照片或影片發送給朋友,以及進行視訊通話,請允許我們訪問攝像頭進行拍攝照片和影片。","k_0dj6yr7":"為方便您發送語音訊息、拍攝影片以及音視訊通話,請允許我們使用咪高風進行錄音。","k_003qnsl":"存儲","k_0s3rtpw":"為方便您查看和選擇相冊裏的圖片影片發送給朋友,以及保存內容到設備,請允許我們訪問您設備上的照片、媒體內容。","k_0tezv85":" 申請獲取$option2","k_002rety":"權限","k_18o68ro":"需要授予","k_1onpf8u":" 相機權限,以正常使用拍攝圖片/影片、視訊通話等功能。","k_17irga5":" 咪高風權限,以正常使用發送語音訊息、拍攝影片、音視訊通話等功能。","k_0572kc4":" 訪問照片權限,以正常使用發送圖片、影片等功能。","k_0slykws":" 訪問相冊寫入權限,以正常使用存儲圖片、影片等功能。","k_119pkcd":" 檔案讀寫權限,以正常使用在聊天功能中的圖片查看、選擇能力和發送檔案的能力。","k_0gqewd3":"以後再說","k_03eq4s1":"去開啟","k_0nt2uyg":"回到最新位置","k_04l16at":"$option1條新訊息","k_13p3w93":"有人@我","k_18w5uk6":"@所有人","k_0jmujgh":"其他檔案正在接收中","k_12s5ept":"訊息詳情","k_0mxa4f4":"$option1人已讀","k_061tue3":"$option2人未讀","k_18qjstb":"轉讓群主","k_0on1aj2":"有$option2條@我訊息","k_09j4izl":"[有人@我] ","k_1oqtjw0":"[@所有人] ","k_1x5a9vb":"我是: $option1","k_14n31e7":"進群請求","k_08nc5j1":"群類型: $option1","k_1josu12":"$option1 條入群請求","k_0n2x5s0":"驗證消息: $option2","k_03c1nx0":"已同意","k_03aw9w8":"已拒絕","k_038ryos":"去處理","k_0gw8pum":"進群申請","k_1gcvfrj":"請填寫備註名","k_002v9zj":"确认","k_10oqrki":"轻触拍照","k_0f8b3ws":"加载失败","k_11cm5lm":"手动聚焦","k_002uzrd":"预览","k_003qkn3":"录像","k_003k6a7":"拍照","k_0bqpqco":"拍照按钮","k_1626ozl":"停止录像","k_003lvmu":"前置","k_003lued":"后置","k_003lwzh":"外置","k_002qzi3":"关闭","k_003pufb":"自动","k_0apm0ze":"拍照时闪光","k_157zog5":"始终闪光","k_0cfyqhy":"$option1 画面预览","k_0phctlz":"闪光模式: $option2","k_02vfqe0":"切换至 $option3 摄像头","k_0f0y9ex":"说话时间太短","k_0ln70tk":"无法打开URL","k_11a3jdv":"轻触拍照,长按摄像","k_1k18miv":"请传入离开群组生命周期函数,提供返回首页或其他页面的导航方法。","k_1fu9ahv":"全员禁言状态","k_0gmwbnd":"全员禁言中","k_0got2zr":"您被禁言","k_0y9jck8":"你必须自定义search bar,并处理点击跳转","k_0yum3tv":"如使用自定义区域,请在profileWidgetBuilder传入对应组件","k_09kalj0":"清空聊天记录","k_14j5iul":"删除并退出","k_125ru1w":"解散该群","k_0jtutmw":"退出后不会接收到此群聊消息","k_0jtzmqa":"解散后不会接收到此群聊消息","k_0r8fi93":"好友添加成功","k_02qw14e":"好友申请已发出","k_0n3md5x":"当前用户在黑名单","k_094phq4":"好友添加失败","k_129scag":"好友删除成功","k_129uzfn":"好友删除失败","k_1666isy":"清除好友","k_1679vrd":"加为好友","k_1ualc52":"看看对方带来的数据是啥","k_0szluvp":"设置对方在线状态","k_0f4rnf8":"该用户已是好友","k_1tdkom4":"您已是群成员","k_1p2lyuz":"对方正在输入中...","k_1g8wfpy":"...共$option1人","k_12rv9vw":"回应详情","k_0havgi0":"[查看详情 >>](${linkMessage.link})","k_0n9p7g8":"群组不存在","k_1tdh5vn":"您不是群成员","k_0h1q57v":"暂无群成员","k_0y5drq1":"[查看详情 >>]($option1)","k_03pjp61":"[表情消息]","k_1jpvzul":"[自定义消息]","k_03u3bh1":"[文件消息]","k_1odsnsw":"[群消息]","k_03sel4t":"[图片消息]","k_03sfw3r":"[位置消息]","k_03xpuwq":"[合并消息]","k_07ycxwo":"[没有元素]","k_03rc9vz":"[文本消息]","k_046uopf":"[视频消息]","k_0ehmsun":"设备存储空间不足,建议清理,以获得更好使用体验","k_003kmos":"图片","k_002s86q":"视频","k_06bk5ei":"视频消息仅限 mp4 格式","k_13opfxf":"Web网页端不支持搜索","k_1i0o0y2":"暂时仅限 Android/iOS 端","k_045dtzl":"$option1的聊天记录","k_0t0131u":"群资料信息","k_18ok8xz":"消息接收方式","k_03ax3ks":"群资料","k_0sqvoqo":"将 $option1 设置为管理员","k_1gbg1v8":"将 $option1 取消管理员","k_17k64g4":"群聊创建成功!","k_05mn217":"暂未安装表情包插件,如需使用表情相关功能,请根据本文档安装:https://cloud.tencent.com/document/product/269/70746","k_14j17nz":"暂无表情包","k_0fvjexh":"正在下载中","k_1cdagzz":"已加入待下载队列,其他文件下载中","k_0g4vojc":"开始下载","k_1g32es3":"[调皮]@2x.png","k_1g8qorz":"[爱你]@2x.png","k_1g4hmx6":"[爱情]@2x.png","k_1g6b558":"[爱心]@2x.png","k_1g3m4su":"[傲慢]@2x.png","k_1g2jym7":"[白眼]@2x.png","k_0cgkxuw":"[棒棒糖]@2x.png","k_1g48br2":"[抱抱]@2x.png","k_1g49ol8":"[抱拳]@2x.png","k_1g0ras3":"[爆筋]@2x.png","k_1ghy881":"[鄙视]@2x.png","k_1g86bmv":"[闭嘴]@2x.png","k_1g1xs1p":"[鞭炮]@2x.png","k_1g8i6ri":"[便便]@2x.png","k_1g2u5kf":"[擦汗]@2x.png","k_1g60uwh":"[彩带]@2x.png","k_1g1o0d0":"[彩球]@2x.png","k_1g6a6yq":"[菜刀]@2x.png","k_1g6vqo2":"[差劲]@2x.png","k_1g0kvjc":"[钞票]@2x.png","k_1g65x7e":"[车厢]@2x.png","k_0e1tjol":"[打哈欠]@2x.png","k_1g65n58":"[大兵]@2x.png","k_1g7se7o":"[大哭]@2x.png","k_1g03868":"[蛋糕]@2x.png","k_1h8nm66":"[刀]@2x.png","k_1g3dlpi":"[得意]@2x.png","k_1g3u434":"[灯泡]@2x.png","k_1giuqs7":"[凋谢]@2x.png","k_1g8r0r9":"[多云]@2x.png","k_1g7k6i1":"[发呆]@2x.png","k_1g44zsp":"[发抖]@2x.png","k_1g5l96i":"[飞机]@2x.png","k_1g7wsqj":"[飞吻]@2x.png","k_1g49luq":"[奋斗]@2x.png","k_1gixbsm":"[风车]@2x.png","k_1g6cqbq":"[尴尬]@2x.png","k_1g6jbw5":"[勾引]@2x.png","k_1g3lwo1":"[鼓掌]@2x.png","k_1g13nkj":"[害羞]@2x.png","k_1g0mt47":"[憨笑]@2x.png","k_0bxujkf":"[红灯笼]@2x.png","k_0hhaeh8":"[红双喜]@2x.png","k_1g0jnts":"[坏笑]@2x.png","k_1g46g9c":"[挥手]@2x.png","k_1g4vi9g":"[回头]@2x.png","k_1gf7hes":"[饥饿]@2x.png","k_1g6mvsm":"[激动]@2x.png","k_1gku5mf":"[街舞]@2x.png","k_1g4hidg":"[惊恐]@2x.png","k_1gjbrtu":"[惊讶]@2x.png","k_1g6sand":"[咖啡]@2x.png","k_1g4s8rj":"[磕头]@2x.png","k_1g1wn34":"[可爱]@2x.png","k_1g3l0wd":"[可怜]@2x.png","k_1ggaon9":"[抠鼻]@2x.png","k_1ggvcb0":"[骷髅]@2x.png","k_1h8yqjt":"[酷]@2x.png","k_0jac97i":"[快哭了]@2x.png","k_1h8oiby":"[困]@2x.png","k_1g0s5hg":"[蜡烛]@2x.png","k_1g1iuer":"[篮球]@2x.png","k_1g2xjfi":"[冷汗]@2x.png","k_0s5oyqw":"[礼品袋]@2x.png","k_1g1qqvf":"[礼物]@2x.png","k_1g2slew":"[流汗]@2x.png","k_1g3z9xx":"[流泪]@2x.png","k_1g6pabn":"[麻将]@2x.png","k_0pkaxul":"[麦克风]@2x.png","k_1g7m0zj":"[猫咪]@2x.png","k_0ibvtpo":"[么么哒]@2x.png","k_1g1hoh1":"[玫瑰]@2x.png","k_1gfzeow":"[米饭]@2x.png","k_1g5l15p":"[面条]@2x.png","k_1g2hfa6":"[奶瓶]@2x.png","k_1gix9pj":"[难过]@2x.png","k_1giqn6g":"[闹钟]@2x.png","k_1h8kd64":"[怒]@2x.png","k_1g0vui9":"[怄火]@2x.png","k_1g1jsj7":"[皮球]@2x.png","k_1ghdluw":"[啤酒]@2x.png","k_1gl6ec7":"[瓢虫]@2x.png","k_1g7gg5p":"[撇嘴]@2x.png","k_1g8psin":"[乒乓]@2x.png","k_1gjzu3p":"[汽车]@2x.png","k_1h8mr0k":"[强]@2x.png","k_1g45y2n":"[敲打]@2x.png","k_1gkaxsl":"[青蛙]@2x.png","k_0jcfnoo":"[糗大了]@2x.png","k_1g4njy1":"[拳头]@2x.png","k_1h8mqr3":"[弱]@2x.png","k_1h926fg":"[色]@2x.png","k_1g6rtbq":"[沙发]@2x.png","k_1giirh6":"[删除]@2x.png","k_1g14ny9":"[闪电]@2x.png","k_1g6bmsr":"[胜利]@2x.png","k_1g1rytx":"[示爱]@2x.png","k_1g52fbz":"[手枪]@2x.png","k_1h90dam":"[衰]@2x.png","k_1gigiae":"[睡觉]@2x.png","k_1gijchz":"[太阳]@2x.png","k_1g1sgji":"[跳绳]@2x.png","k_1gjwuri":"[跳跳]@2x.png","k_1g0juhk":"[偷笑]@2x.png","k_1h8nzla":"[吐]@2x.png","k_1g6cv0i":"[委屈]@2x.png","k_1g46l5g":"[握手]@2x.png","k_1g2pgkd":"[西瓜]@2x.png","k_1ging9p":"[下雨]@2x.png","k_1h8nzil":"[吓]@2x.png","k_1g7q7wr":"[献吻]@2x.png","k_1gl6uum":"[香蕉]@2x.png","k_1g23fys":"[象棋]@2x.png","k_0j75rdh":"[心碎了]@2x.png","k_1g6ajj2":"[信封]@2x.png","k_1g21prz":"[熊猫]@2x.png","k_1h8octi":"[嘘]@2x.png","k_1h91zox":"[药]@2x.png","k_1ghttfl":"[疑问]@2x.png","k_1ghk7sz":"[阴险]@2x.png","k_0gl37zz":"[右车头]@2x.png","k_0ifkj1p":"[右哼哼]@2x.png","k_0g1yh2e":"[右太极]@2x.png","k_1g9dkfc":"[雨伞]@2x.png","k_1g8jl88":"[月亮]@2x.png","k_1h8lhqj":"[晕]@2x.png","k_1gi9x2q":"[再见]@2x.png","k_1g6dwwv":"[炸弹]@2x.png","k_1fzmkfi":"[折磨]@2x.png","k_1g6jbiw":"[纸巾]@2x.png","k_1ggjnwu":"[咒骂]@2x.png","k_1g4qlq8":"[猪头]@2x.png","k_1g1lqzz":"[抓狂]@2x.png","k_1g80j3u":"[转圈]@2x.png","k_1g0z55s":"[龇牙]@2x.png","k_1g3ju6v":"[钻戒]@2x.png","k_0gl51l6":"[左车头]@2x.png","k_0iflllk":"[左哼哼]@2x.png","k_0g1y3ir":"[左太极]@2x.png","k_026hiq5":"消息列表加载中","k_003tu8k":"爱你","k_003myvp":"傲慢","k_003kddw":"白眼","k_039yfhv":"棒棒糖","k_003nu3p":"抱抱","k_003nijr":"抱拳","k_003mg88":"爆筋","k_002v17e":"鄙视","k_003qhy4":"闭嘴","k_003l5fq":"鞭炮","k_003uacl":"便便","k_003oq1g":"擦汗","k_003qvey":"彩带","k_003jci7":"彩球","k_003pyu1":"菜刀","k_003q97d":"差劲","k_003po5d":"车厢","k_03eadb2":"打哈欠","k_003pnuf":"大兵","k_003kg57":"蛋糕","k_003mxkt":"得意","k_003onu3":"灯泡","k_002uv8s":"凋谢","k_003kqy0":"调皮","k_003tyum":"多云","k_003pv9u":"发呆","k_036o6mu":"发抖t","k_003nogx":"飞机","k_003q7wg":"飞吻","k_003m0jd":"奋斗","k_002ult9":"风车","k_003r8gt":"尴尬","k_003qy4u":"勾引","k_003mnoa":"鼓掌","k_003lmw8":"害羞","k_003mb30":"憨笑","k_03bj41g":"红灯笼","k_03dxw2f":"红双喜","k_003mk57":"坏笑","k_003nmvf":"挥手","k_003r2i7":"回头","k_002s6f3":"饥饿","k_003qd0t":"激动","k_002vgi4":"街舞","k_003nz33":"惊恐","k_002wh4p":"惊讶","k_003ozpu":"咖啡","k_003qvs4":"磕头","k_003l3wb":"可爱","k_003nuwm":"可怜","k_002rw1q":"抠鼻","k_002tujb":"骷髅","k_00030eq":"酷","k_03i8ath":"快哭了","k_000421h":"困","k_003l5i7":"蜡烛","k_003j72g":"篮球","k_003ofwl":"冷汗","k_02mw65v":"礼品袋","k_003ku40":"礼物","k_003ookz":"流汗","k_003on72":"流泪","k_003rjy0":"麻将","k_003q2f8":"猫咪","k_03et393":"么么哒","k_003j7j2":"玫瑰","k_002sr0b":"米饭","k_003nnza":"面条","k_003jef9":"奶瓶","k_002umn0":"难过","k_002rjib":"闹钟","k_0003zcn":"怒","k_003jzwq":"怄火","k_003j4js":"皮球","k_002r5ir":"啤酒","k_002ubu4":"瓢虫","k_003ppo6":"撇嘴","k_003ty3o":"乒乓","k_002vxwe":"汽车","k_00043hb":"强","k_003nmbo":"敲打","k_002tfhq":"青蛙","k_03i7lrn":"糗大了","k_003r03m":"拳头","k_00043h0":"弱","k_000345z":"色","k_003qmp9":"沙发","k_003it8a":"闪电","k_003pxow":"胜利","k_003kw8e":"示爱","k_003n99g":"手枪","k_00035cl":"衰","k_002vl3h":"睡觉","k_002rgqk":"太阳","k_003m9d1":"跳绳","k_002vobp":"跳跳","k_003mkoz":"偷笑","k_00041px":"吐","k_003rjh5":"委屈","k_003j36u":"西瓜","k_002re92":"下雨","k_00041py":"吓","k_003q06o":"献吻","k_002ubjp":"香蕉","k_003o2tr":"象棋","k_03ie6pa":"心碎了","k_003rao5":"信封","k_003l3us":"熊猫","k_000424d":"嘘","k_00033yi":"药","k_002qtyy":"疑问","k_002qe0o":"阴险","k_03gu7us":"右车头","k_03ere8m":"右哼哼","k_003uqk3":"雨伞","k_003tzdv":"月亮","k_0003z00":"晕","k_002vdrd":"再见","k_003ra1w":"炸弹","k_003lcad":"折磨","k_003q7sz":"纸巾","k_002thn9":"咒骂","k_003qx7f":"猪头","k_003l044":"抓狂","k_003qg4h":"转圈","k_003kb97":"龇牙","k_03gu53l":"左车头","k_03erd1f":"左哼哼","k_003nyvl":"爱情","k_003r85z":"爱心","k_003mk8j":"钞票","k_003pwfj":"大哭","k_00042w5":"刀","k_003nmtr":"握手","k_03c529p":"右太极","k_003n4mk":"钻戒","k_03c5488":"左太极","k_1llp7tu":"该用户不存在","k_0tbyqyb":"加载中…","k_0td1p3f":"保存中…","k_1klqdh1":"仅限汉字、英文、数字和下划线","k_03el5lp":"未填写","k_1ui0gai":"搜索指定内容","k_003nvk2":"消息","k_03agld7":"群提示","k_0elt0kw":"添加群聊","k_0s3sgel":"移出黑名单","k_1qqgjra":"$option3条未读消息","k_0uubyjr":"以下为未读消息","k_16as7eq":"表情回应","k_003s12u":"回复","k_003s38r":"更多","k_002wkr3":"翻译","k_13g4hxv":"翻译完成","k_003molk":"表情","k_165bbw6":"消息历史","k_13sqc0z":"清除消息","k_0glns86":"删除会话","k_13s99rx":"清空消息","k_11vsa3j":"退出群组","k_11vvszp":"解散群组","k_15i9w72":"群管理员","k_0p3espj":"设置备注名","k_118sw9v":"立即搜索","k_0h20hg5":"视频通话","k_0h22snw":"语音通话","k_003lz6t":"对方","k_1xf4yre":"发送给$option1","k_003por5":"截图","k_1rw7s82":" 访问相册中视频权限,以正常使用发送视频等功能。","k_003rcwm":"打开","k_1698c42":"在访达中打开","k_066fxsz":"查看文件夹","k_0k432y2":"无法发送,包含文件夹","k_002wb4y":"会话","k_0od4qyh":"视频文件异常"} \ No newline at end of file +{"k_1yemzyd":"收到一條訊息","k_0ylosxn":"自定義訊息","k_13sajrj":"貼圖訊息","k_13sjeb7":"檔案訊息","k_0yd2ft8":"群提示訊息","k_13s7mxn":"圖片訊息","k_13satlt":"位置訊息","k_00bbtsx":"合並轉發訊息","k_13sqwu4":"語音訊息","k_13sqjjp":"影片","k_1fdhj9g":"該版本不支持此訊息","k_06pujtm":"同意任何用戶添加好友","k_0gyhkp5":"需要驗證","k_121ruco":"拒絕任何人加好友","k_05nspni":"自定義字段","k_03fchyy":"群頭像","k_03i9mfe":"群簡介","k_03agq58":"群名稱","k_039xqny":"群通知","k_003tr0a":"群主","k_03iqsh4":"$s為 ","k_191t5n4":"$opUserNickName修改","k_1pg6aoj":"$opUserNickName退出群組","k_1f6zt3v":"邀請$invitedMemberString加入群組","k_0y7zd07":"將$invitedMemberString踢出群組","k_03c49qt":"去授權","k_1d5mshh":"用戶$joinedMemberString加入了群組","k_002wddw":"禁言","k_0got6f7":"解除禁言","k_0yenqf0":"$userName 被","k_0spotql":"將 $adminMember 設置為管理員","k_0pg5zzj":"系統訊息 $operationType","k_0ohzb9l":"通話時間:$callTime","k_1uaqed6":"[自定義]","k_0z2z7rx":"[語音]","k_0y39ngu":"[貼圖]","k_1c7z88n":"[檔案] $fileName","k_0y1a2my":"[圖片]","k_0z4fib8":"[影片]","k_0y24mcg":"[位置]","k_0pewpd1":"[聊天記錄]","k_13s8d9p":"未知訊息","k_1c3us5n":"當前群組不支持@全體成員","k_11k579v":"發言中有非法語句","k_003qkx2":"日歷","k_003n2pz":"相機","k_03idjo0":"聯絡人","k_003ltgm":"位置","k_02k3k86":"咪高風","k_003pm7l":"相冊","k_15ao57x":"相冊寫入","k_164m3jd":"本地存儲","k_0qba4ns":"想訪問您的$yoursItem","k_03r6qyx":"我們需要您的同意才能獲取信息","k_02noktt":"不允許","k_00043x4":"好","k_003qzac":"昨天","k_003r39d":"前天","k_03fqp9o":"星期天","k_03ibg5h":"星期一","k_03i7hu1":"星期二","k_03iaiks":"星期三","k_03el9pa":"星期四","k_03i7ok1":"星期五","k_03efxyg":"星期六","k_0oozw9x":"$diffMinutes 分鐘前","k_003q7ba":"下午","k_003q7bb":"上午","k_003pu3h":"現在","k_13hzn00":"昨天 $yesterday","k_0n9pyxz":"用戶不存在","k_1bjwemh":"搜尋用戶 ID","k_003kv3v":"搜尋","k_02owlq8":"我的用戶ID: $userID","k_1wu8h4x":"我是: $showName","k_16758qw":"添加好友","k_1shx4d9":"個性簽名: $selfSignature","k_0i553x0":"填寫驗證信息","k_031ocwx":"請填寫備註和分組","k_003ojje":"備註","k_003lsav":"分組","k_167bdvq":"我的好友","k_156b4ut":"好友申請已發送","k_002r305":"發送","k_03gu05e":"聊天室","k_03b4f3p":"會議群","k_03avj1p":"公開群","k_03asq2g":"工作群","k_03b3hbi":"未知群","k_1loix7s":"群類型: $groupType","k_1lqbsib":"該群組不存在","k_03h153m":"搜尋群ID","k_0oxak3r":"群申請已發送","k_002rflt":"刪除","k_1don84v":"無法定位到原訊息","k_003q5fi":"復製","k_003prq0":"轉發","k_002r1h2":"多選","k_003j708":"引用","k_003pqpr":"回收","k_03ezhho":"已復製","k_11ctfsz":"暫未實現","k_1hbjg5g":"[群系統訊息]","k_03tvswb":"[未知訊息]","k_155cj23":"您回收了一條訊息,","k_0gapun3":"重新編輯","k_1uh417q":"$displayName回收了一條訊息","k_1aszp2k":"您確定要重發這條訊息麽?","k_003rzap":"確定","k_003nevv":"取消","k_0003z7x":"您","k_002wfe4":"已讀","k_002wjlg":"未讀","k_0h1ygf8":"發起通話","k_0h169j0":"取消通話","k_0h13jjk":"接受通話","k_0h19hfx":"拒絕通話","k_0obi9lh":"超時未接聽","k_0y9u662":"「$appName」暫不可以開啟此類檔案,你可以使用其他應用開啟並預覽","k_001nmhu":"用其他應用開啟","k_1ht1b80":"正在接收中","k_105682d":"圖片載入失敗","k_0pytyeu":"圖片保存成功","k_0akceel":"圖片保存失敗","k_003rk1s":"保存","k_04a0awq":"[語音訊息]","k_105c3y3":"影片載入失敗","k_176rzr7":"聊天記錄","k_0d5z4m5":"選擇提醒人","k_003ngex":"完成","k_1665ltg":"發起呼叫","k_003n8b0":"拍攝","k_003kthh":"照片","k_003tnp0":"檔案","k_0jhdhtp":"發送失敗,影片不能大於100MB","k_119ucng":"圖片不能為空","k_0w9x8gw":"選擇成功$successPath","k_13dsw4l":"松開取消","k_0am7r68":"手指上滑,取消發送","k_15jl6qw":"說話時間太短!","k_0gx7vl6":"按住說話","k_15dlafd":"逐條轉發","k_15dryxy":"合並轉發","k_1eyhieh":"確定刪除已選訊息","k_17fmlyf":"清除聊天","k_0dhesoz":"取消置頂","k_002sk7x":"置頂","k_003ll77":"草稿","k_03icaxo":"自定義","k_1969986":"[語音通話]:$callingLastMsgShow","k_1960dlr":"[視訊通話]:$callingLastMsgShow","k_1np495n":"$messageString[有人@我]","k_1m797yi":"$messageString[@所有人]","k_1uaov41":"查找聊天內容","k_003kfai":"未知","k_13dq4an":"自動審批","k_0l13cde":"管理員審批","k_11y8c6a":"禁止加群","k_1kvyskd":"無網絡連接,無法修改","k_16payqf":"加群方式","k_0vzvn8r":"修改群名稱","k_038lh6u":"群管理","k_0k5wyiy":"設置管理員","k_0goiuwk":"全員禁言","k_1g889xx":"全員禁言開啟後,只允許群主和管理員發言。","k_0wlrefq":"添加需要禁言的群成員","k_0goox5g":"設置禁言","k_08daijh":"成功取消管理員身份","k_0bxm97s":"管理員 ($adminNum/10)","k_0k5u935":"添加管理員","k_03enyx5":"群成員","k_0jayw3z":"群成員($groupMemberNum人)","k_0h1svv1":"刪除群成員","k_0h1g636":"添加群成員","k_0uj7208":"無網絡連接,無法查看群成員","k_01yfa4o":"$memberCount人","k_0hpukyx":"查看更多群成員","k_0qtsar0":"訊息免打擾","k_0ef2a12":"修改我的群昵稱","k_1aajych":"僅限中文、字母、數字和下劃線,2-20個字","k_137pab5":"我的群昵稱","k_0ivim6d":"暫無群公告","k_03eq6cn":"群公告","k_002vxya":"編輯","k_17fpl3y":"置頂聊天","k_03es1ox":"群類型","k_003mz1i":"同意","k_003lpre":"拒絕","k_003qk66":"頭像","k_003lhvk":"昵稱","k_003ps50":"賬號","k_15lx52z":"個性簽名","k_003qgkp":"性別","k_003m6hr":"生日","k_0003v6a":"男","k_00043x2":"女","k_03bcjkv":"未設置","k_11s0gdz":"修改昵稱","k_0p3j4sd":"僅限中字、字母、數字和下劃線","k_15lyvdt":"修改簽名","k_0vylzjp":"這個人很懶,什麽也沒寫","k_1hs7ese":"等上線再改這個","k_03exjk7":"備註名","k_0s3skfd":"加入黑名單","k_0p3b31s":"修改備註名","k_0003y9x":"無","k_11zgnfs":"個人資料","k_03xd79d":"個性簽名: $signature","k_1tez2xl":"暫無個性簽名","k_118prbn":"全局搜尋","k_1m9dftc":"全部聯絡人","k_0em4gyz":"全部群組","k_002twmj":"群組","k_09kga0d":"更多聊天記錄","k_1ui5lzi":"$count條相關聊天記錄","k_09khmso":"相關聊天記錄","k_1kevf4k":"與$receiver的聊天記錄","k_0vjj2kp":"群組的聊天記錄","k_003n2rp":"選擇","k_03ignw6":"所有人","k_03erpei":"管理員","k_0qi9tno":"群主、管理員","k_1m9exwh":"最近聯絡人","k_119nwqr":"輸入不能為空","k_0pzwbmg":"影片保存成功","k_0aktupv":"影片保存失敗","k_1qbg9xc":"$option8為 ","k_1wq5ubm":"$option7修改","k_0y5pu80":"$option6退出群組","k_0nl7cmd":"邀請$option5加入群組","k_1ju5iqw":"將$option4踢出群組","k_1ovt677":"用戶$option3加入了群組","k_0k05b8b":"$option2 被","k_0wm4xeb":"系統訊息 $option2","k_0nbq9v3":"通話時間:$option2","k_0i1kf53":"[檔案] $option2","k_1gnnby6":"想訪問您的$option2","k_1wh4atg":"$option2 分鐘前","k_07sh7g1":"昨天 $option2","k_1pj8xzh":"我的用戶ID: $option2","k_0py1evo":"個性簽名: $option2","k_1kvj4i2":"$option2回收了一條訊息","k_1v0lbpp":"「$option2」暫不可以開啟此類檔案,你可以使用其他應用開啟並預覽","k_0torwfz":"選擇成功$option2","k_0i1bjah":"$option1回收了一條訊息","k_1qzxh9q":"通話時間:$option3","k_0wrgmom":"[語音通話]:$option1","k_06ix2f0":"[視訊通話]:$option2","k_08o3z5w":"[檔案] $option1","k_0ezbepg":"$option2[有人@我]","k_1ccnht1":"$option2[@所有人]","k_1k3arsw":"管理員 ($option2/10)","k_1d4golg":"群成員($option1人)","k_1bg69nt":"$option1人","k_00gjqxj":"個性簽名: $option1","k_0c29cxr":"$option1條相關聊天記錄","k_1twk5rz":"與$option1的聊天記錄","k_1vn4xq1":"將 $adminMember 取消管理員","k_0e35hsw":"為方便您將所拍攝的照片或影片發送給朋友,以及進行視訊通話,請允許我們訪問攝像頭進行拍攝照片和影片。","k_0dj6yr7":"為方便您發送語音訊息、拍攝影片以及音視訊通話,請允許我們使用咪高風進行錄音。","k_003qnsl":"存儲","k_0s3rtpw":"為方便您查看和選擇相冊裏的圖片影片發送給朋友,以及保存內容到設備,請允許我們訪問您設備上的照片、媒體內容。","k_0tezv85":" 申請獲取$option2","k_002rety":"權限","k_18o68ro":"需要授予","k_1onpf8u":" 相機權限,以正常使用拍攝圖片/影片、視訊通話等功能。","k_17irga5":" 咪高風權限,以正常使用發送語音訊息、拍攝影片、音視訊通話等功能。","k_0572kc4":" 訪問照片權限,以正常使用發送圖片、影片等功能。","k_0slykws":" 訪問相冊寫入權限,以正常使用存儲圖片、影片等功能。","k_119pkcd":" 檔案讀寫權限,以正常使用在聊天功能中的圖片查看、選擇能力和發送檔案的能力。","k_0gqewd3":"以後再說","k_03eq4s1":"去開啟","k_0nt2uyg":"回到最新位置","k_04l16at":"$option1條新訊息","k_13p3w93":"有人@我","k_18w5uk6":"@所有人","k_0jmujgh":"其他檔案正在接收中","k_12s5ept":"訊息詳情","k_0mxa4f4":"$option1人已讀","k_061tue3":"$option2人未讀","k_18qjstb":"轉讓群主","k_0on1aj2":"有$option2條@我訊息","k_09j4izl":"[有人@我] ","k_1oqtjw0":"[@所有人] ","k_1x5a9vb":"我是: $option1","k_14n31e7":"進群請求","k_08nc5j1":"群類型: $option1","k_1josu12":"$option1 條入群請求","k_0n2x5s0":"驗證消息: $option2","k_03c1nx0":"已同意","k_03aw9w8":"已拒絕","k_038ryos":"去處理","k_0gw8pum":"進群申請","k_1gcvfrj":"請填寫備註名","k_002v9zj":"确认","k_10oqrki":"轻触拍照","k_0f8b3ws":"加载失败","k_11cm5lm":"手动聚焦","k_002uzrd":"预览","k_003qkn3":"录像","k_003k6a7":"拍照","k_0bqpqco":"拍照按钮","k_1626ozl":"停止录像","k_003lvmu":"前置","k_003lued":"后置","k_003lwzh":"外置","k_002qzi3":"关闭","k_003pufb":"自动","k_0apm0ze":"拍照时闪光","k_157zog5":"始终闪光","k_0cfyqhy":"$option1 画面预览","k_0phctlz":"闪光模式: $option2","k_02vfqe0":"切换至 $option3 摄像头","k_0f0y9ex":"说话时间太短","k_0ln70tk":"无法打开URL","k_11a3jdv":"轻触拍照,长按摄像","k_1k18miv":"请传入离开群组生命周期函数,提供返回首页或其他页面的导航方法。","k_1fu9ahv":"全员禁言状态","k_0gmwbnd":"全员禁言中","k_0got2zr":"您被禁言","k_0y9jck8":"你必须自定义search bar,并处理点击跳转","k_0yum3tv":"如使用自定义区域,请在profileWidgetBuilder传入对应组件","k_09kalj0":"清空聊天记录","k_14j5iul":"删除并退出","k_125ru1w":"解散该群","k_0jtutmw":"退出后不会接收到此群聊消息","k_0jtzmqa":"解散后不会接收到此群聊消息","k_0r8fi93":"好友添加成功","k_02qw14e":"好友申请已发出","k_0n3md5x":"当前用户在黑名单","k_094phq4":"好友添加失败","k_129scag":"好友删除成功","k_129uzfn":"好友删除失败","k_1666isy":"清除好友","k_1679vrd":"加为好友","k_1ualc52":"看看对方带来的数据是啥","k_0szluvp":"设置对方在线状态","k_0f4rnf8":"该用户已是好友","k_1tdkom4":"您已是群成员","k_1p2lyuz":"对方正在输入中...","k_1g8wfpy":"...共$option1人","k_12rv9vw":"回应详情","k_0havgi0":"[查看详情 >>](${linkMessage.link})","k_0n9p7g8":"群组不存在","k_1tdh5vn":"您不是群成员","k_0h1q57v":"暂无群成员","k_0y5drq1":"[查看详情 >>]($option1)","k_03pjp61":"[表情消息]","k_1jpvzul":"[自定义消息]","k_03u3bh1":"[文件消息]","k_1odsnsw":"[群消息]","k_03sel4t":"[图片消息]","k_03sfw3r":"[位置消息]","k_03xpuwq":"[合并消息]","k_07ycxwo":"[没有元素]","k_03rc9vz":"[文本消息]","k_046uopf":"[视频消息]","k_0ehmsun":"设备存储空间不足,建议清理,以获得更好使用体验","k_003kmos":"图片","k_002s86q":"视频","k_06bk5ei":"视频消息仅限 mp4 格式","k_13opfxf":"Web网页端不支持搜索","k_1i0o0y2":"暂时仅限 Android/iOS 端","k_045dtzl":"$option1的聊天记录","k_0t0131u":"群资料信息","k_18ok8xz":"消息接收方式","k_03ax3ks":"群资料","k_0sqvoqo":"将 $option1 设置为管理员","k_1gbg1v8":"将 $option1 取消管理员","k_17k64g4":"群聊创建成功!","k_05mn217":"暂未安装表情包插件,如需使用表情相关功能,请根据本文档安装:https://cloud.tencent.com/document/product/269/70746","k_14j17nz":"暂无表情包","k_0fvjexh":"正在下载中","k_1cdagzz":"已加入待下载队列,其他文件下载中","k_0g4vojc":"开始下载","k_1g32es3":"[调皮]@2x.png","k_1g8qorz":"[爱你]@2x.png","k_1g4hmx6":"[爱情]@2x.png","k_1g6b558":"[爱心]@2x.png","k_1g3m4su":"[傲慢]@2x.png","k_1g2jym7":"[白眼]@2x.png","k_0cgkxuw":"[棒棒糖]@2x.png","k_1g48br2":"[抱抱]@2x.png","k_1g49ol8":"[抱拳]@2x.png","k_1g0ras3":"[爆筋]@2x.png","k_1ghy881":"[鄙视]@2x.png","k_1g86bmv":"[闭嘴]@2x.png","k_1g1xs1p":"[鞭炮]@2x.png","k_1g8i6ri":"[便便]@2x.png","k_1g2u5kf":"[擦汗]@2x.png","k_1g60uwh":"[彩带]@2x.png","k_1g1o0d0":"[彩球]@2x.png","k_1g6a6yq":"[菜刀]@2x.png","k_1g6vqo2":"[差劲]@2x.png","k_1g0kvjc":"[钞票]@2x.png","k_1g65x7e":"[车厢]@2x.png","k_0e1tjol":"[打哈欠]@2x.png","k_1g65n58":"[大兵]@2x.png","k_1g7se7o":"[大哭]@2x.png","k_1g03868":"[蛋糕]@2x.png","k_1h8nm66":"[刀]@2x.png","k_1g3dlpi":"[得意]@2x.png","k_1g3u434":"[灯泡]@2x.png","k_1giuqs7":"[凋谢]@2x.png","k_1g8r0r9":"[多云]@2x.png","k_1g7k6i1":"[发呆]@2x.png","k_1g44zsp":"[发抖]@2x.png","k_1g5l96i":"[飞机]@2x.png","k_1g7wsqj":"[飞吻]@2x.png","k_1g49luq":"[奋斗]@2x.png","k_1gixbsm":"[风车]@2x.png","k_1g6cqbq":"[尴尬]@2x.png","k_1g6jbw5":"[勾引]@2x.png","k_1g3lwo1":"[鼓掌]@2x.png","k_1g13nkj":"[害羞]@2x.png","k_1g0mt47":"[憨笑]@2x.png","k_0bxujkf":"[红灯笼]@2x.png","k_0hhaeh8":"[红双喜]@2x.png","k_1g0jnts":"[坏笑]@2x.png","k_1g46g9c":"[挥手]@2x.png","k_1g4vi9g":"[回头]@2x.png","k_1gf7hes":"[饥饿]@2x.png","k_1g6mvsm":"[激动]@2x.png","k_1gku5mf":"[街舞]@2x.png","k_1g4hidg":"[惊恐]@2x.png","k_1gjbrtu":"[惊讶]@2x.png","k_1g6sand":"[咖啡]@2x.png","k_1g4s8rj":"[磕头]@2x.png","k_1g1wn34":"[可爱]@2x.png","k_1g3l0wd":"[可怜]@2x.png","k_1ggaon9":"[抠鼻]@2x.png","k_1ggvcb0":"[骷髅]@2x.png","k_1h8yqjt":"[酷]@2x.png","k_0jac97i":"[快哭了]@2x.png","k_1h8oiby":"[困]@2x.png","k_1g0s5hg":"[蜡烛]@2x.png","k_1g1iuer":"[篮球]@2x.png","k_1g2xjfi":"[冷汗]@2x.png","k_0s5oyqw":"[礼品袋]@2x.png","k_1g1qqvf":"[礼物]@2x.png","k_1g2slew":"[流汗]@2x.png","k_1g3z9xx":"[流泪]@2x.png","k_1g6pabn":"[麻将]@2x.png","k_0pkaxul":"[麦克风]@2x.png","k_1g7m0zj":"[猫咪]@2x.png","k_0ibvtpo":"[么么哒]@2x.png","k_1g1hoh1":"[玫瑰]@2x.png","k_1gfzeow":"[米饭]@2x.png","k_1g5l15p":"[面条]@2x.png","k_1g2hfa6":"[奶瓶]@2x.png","k_1gix9pj":"[难过]@2x.png","k_1giqn6g":"[闹钟]@2x.png","k_1h8kd64":"[怒]@2x.png","k_1g0vui9":"[怄火]@2x.png","k_1g1jsj7":"[皮球]@2x.png","k_1ghdluw":"[啤酒]@2x.png","k_1gl6ec7":"[瓢虫]@2x.png","k_1g7gg5p":"[撇嘴]@2x.png","k_1g8psin":"[乒乓]@2x.png","k_1gjzu3p":"[汽车]@2x.png","k_1h8mr0k":"[强]@2x.png","k_1g45y2n":"[敲打]@2x.png","k_1gkaxsl":"[青蛙]@2x.png","k_0jcfnoo":"[糗大了]@2x.png","k_1g4njy1":"[拳头]@2x.png","k_1h8mqr3":"[弱]@2x.png","k_1h926fg":"[色]@2x.png","k_1g6rtbq":"[沙发]@2x.png","k_1giirh6":"[删除]@2x.png","k_1g14ny9":"[闪电]@2x.png","k_1g6bmsr":"[胜利]@2x.png","k_1g1rytx":"[示爱]@2x.png","k_1g52fbz":"[手枪]@2x.png","k_1h90dam":"[衰]@2x.png","k_1gigiae":"[睡觉]@2x.png","k_1gijchz":"[太阳]@2x.png","k_1g1sgji":"[跳绳]@2x.png","k_1gjwuri":"[跳跳]@2x.png","k_1g0juhk":"[偷笑]@2x.png","k_1h8nzla":"[吐]@2x.png","k_1g6cv0i":"[委屈]@2x.png","k_1g46l5g":"[握手]@2x.png","k_1g2pgkd":"[西瓜]@2x.png","k_1ging9p":"[下雨]@2x.png","k_1h8nzil":"[吓]@2x.png","k_1g7q7wr":"[献吻]@2x.png","k_1gl6uum":"[香蕉]@2x.png","k_1g23fys":"[象棋]@2x.png","k_0j75rdh":"[心碎了]@2x.png","k_1g6ajj2":"[信封]@2x.png","k_1g21prz":"[熊猫]@2x.png","k_1h8octi":"[嘘]@2x.png","k_1h91zox":"[药]@2x.png","k_1ghttfl":"[疑问]@2x.png","k_1ghk7sz":"[阴险]@2x.png","k_0gl37zz":"[右车头]@2x.png","k_0ifkj1p":"[右哼哼]@2x.png","k_0g1yh2e":"[右太极]@2x.png","k_1g9dkfc":"[雨伞]@2x.png","k_1g8jl88":"[月亮]@2x.png","k_1h8lhqj":"[晕]@2x.png","k_1gi9x2q":"[再见]@2x.png","k_1g6dwwv":"[炸弹]@2x.png","k_1fzmkfi":"[折磨]@2x.png","k_1g6jbiw":"[纸巾]@2x.png","k_1ggjnwu":"[咒骂]@2x.png","k_1g4qlq8":"[猪头]@2x.png","k_1g1lqzz":"[抓狂]@2x.png","k_1g80j3u":"[转圈]@2x.png","k_1g0z55s":"[龇牙]@2x.png","k_1g3ju6v":"[钻戒]@2x.png","k_0gl51l6":"[左车头]@2x.png","k_0iflllk":"[左哼哼]@2x.png","k_0g1y3ir":"[左太极]@2x.png","k_026hiq5":"消息列表加载中","k_003tu8k":"爱你","k_003myvp":"傲慢","k_003kddw":"白眼","k_039yfhv":"棒棒糖","k_003nu3p":"抱抱","k_003nijr":"抱拳","k_003mg88":"爆筋","k_002v17e":"鄙视","k_003qhy4":"闭嘴","k_003l5fq":"鞭炮","k_003uacl":"便便","k_003oq1g":"擦汗","k_003qvey":"彩带","k_003jci7":"彩球","k_003pyu1":"菜刀","k_003q97d":"差劲","k_003po5d":"车厢","k_03eadb2":"打哈欠","k_003pnuf":"大兵","k_003kg57":"蛋糕","k_003mxkt":"得意","k_003onu3":"灯泡","k_002uv8s":"凋谢","k_003kqy0":"调皮","k_003tyum":"多云","k_003pv9u":"发呆","k_036o6mu":"发抖t","k_003nogx":"飞机","k_003q7wg":"飞吻","k_003m0jd":"奋斗","k_002ult9":"风车","k_003r8gt":"尴尬","k_003qy4u":"勾引","k_003mnoa":"鼓掌","k_003lmw8":"害羞","k_003mb30":"憨笑","k_03bj41g":"红灯笼","k_03dxw2f":"红双喜","k_003mk57":"坏笑","k_003nmvf":"挥手","k_003r2i7":"回头","k_002s6f3":"饥饿","k_003qd0t":"激动","k_002vgi4":"街舞","k_003nz33":"惊恐","k_002wh4p":"惊讶","k_003ozpu":"咖啡","k_003qvs4":"磕头","k_003l3wb":"可爱","k_003nuwm":"可怜","k_002rw1q":"抠鼻","k_002tujb":"骷髅","k_00030eq":"酷","k_03i8ath":"快哭了","k_000421h":"困","k_003l5i7":"蜡烛","k_003j72g":"篮球","k_003ofwl":"冷汗","k_02mw65v":"礼品袋","k_003ku40":"礼物","k_003ookz":"流汗","k_003on72":"流泪","k_003rjy0":"麻将","k_003q2f8":"猫咪","k_03et393":"么么哒","k_003j7j2":"玫瑰","k_002sr0b":"米饭","k_003nnza":"面条","k_003jef9":"奶瓶","k_002umn0":"难过","k_002rjib":"闹钟","k_0003zcn":"怒","k_003jzwq":"怄火","k_003j4js":"皮球","k_002r5ir":"啤酒","k_002ubu4":"瓢虫","k_003ppo6":"撇嘴","k_003ty3o":"乒乓","k_002vxwe":"汽车","k_00043hb":"强","k_003nmbo":"敲打","k_002tfhq":"青蛙","k_03i7lrn":"糗大了","k_003r03m":"拳头","k_00043h0":"弱","k_000345z":"色","k_003qmp9":"沙发","k_003it8a":"闪电","k_003pxow":"胜利","k_003kw8e":"示爱","k_003n99g":"手枪","k_00035cl":"衰","k_002vl3h":"睡觉","k_002rgqk":"太阳","k_003m9d1":"跳绳","k_002vobp":"跳跳","k_003mkoz":"偷笑","k_00041px":"吐","k_003rjh5":"委屈","k_003j36u":"西瓜","k_002re92":"下雨","k_00041py":"吓","k_003q06o":"献吻","k_002ubjp":"香蕉","k_003o2tr":"象棋","k_03ie6pa":"心碎了","k_003rao5":"信封","k_003l3us":"熊猫","k_000424d":"嘘","k_00033yi":"药","k_002qtyy":"疑问","k_002qe0o":"阴险","k_03gu7us":"右车头","k_03ere8m":"右哼哼","k_003uqk3":"雨伞","k_003tzdv":"月亮","k_0003z00":"晕","k_002vdrd":"再见","k_003ra1w":"炸弹","k_003lcad":"折磨","k_003q7sz":"纸巾","k_002thn9":"咒骂","k_003qx7f":"猪头","k_003l044":"抓狂","k_003qg4h":"转圈","k_003kb97":"龇牙","k_03gu53l":"左车头","k_03erd1f":"左哼哼","k_003nyvl":"爱情","k_003r85z":"爱心","k_003mk8j":"钞票","k_003pwfj":"大哭","k_00042w5":"刀","k_003nmtr":"握手","k_03c529p":"右太极","k_003n4mk":"钻戒","k_03c5488":"左太极","k_1llp7tu":"该用户不存在","k_0tbyqyb":"加载中…","k_0td1p3f":"保存中…","k_1klqdh1":"仅限汉字、英文、数字和下划线","k_03el5lp":"未填写","k_1ui0gai":"搜索指定内容","k_003nvk2":"消息","k_03agld7":"群提示","k_0elt0kw":"添加群聊","k_0s3sgel":"移出黑名单","k_1qqgjra":"$option3条未读消息","k_0uubyjr":"以下为未读消息","k_16as7eq":"表情回应","k_003s12u":"回复","k_003s38r":"更多","k_002wkr3":"翻译","k_13g4hxv":"翻译完成","k_003molk":"表情","k_165bbw6":"消息历史","k_13sqc0z":"清除消息","k_0glns86":"删除会话","k_13s99rx":"清空消息","k_11vsa3j":"退出群组","k_11vvszp":"解散群组","k_15i9w72":"群管理员","k_0p3espj":"设置备注名","k_118sw9v":"立即搜索","k_0h20hg5":"视频通话","k_0h22snw":"语音通话","k_003lz6t":"对方","k_1xf4yre":"发送给$option1","k_003por5":"截图","k_1rw7s82":" 访问相册中视频权限,以正常使用发送视频等功能。","k_003rcwm":"打开","k_1698c42":"在访达中打开","k_066fxsz":"查看文件夹","k_0k432y2":"无法发送,包含文件夹","k_002wb4y":"会话","k_0od4qyh":"视频文件异常","k_1bfkxg9":"不支持 0KB 文件的传输","k_0vvsw7g":"文件处理异常","k_06e224q":"[消息被管理员撤回]","k_1u1mjcl":"[消息被撤回]","k_1qcqxea":"选择多个会话","k_1qgmc20":"选择一个会话","k_1d8nx6f":"在新窗口中打开","k_1hz05ax":"正在下载原始资源,请稍候..."} \ No newline at end of file diff --git a/lib/ui/controller/tim_uikit_chat_controller.dart b/lib/ui/controller/tim_uikit_chat_controller.dart index df19da4..60ada94 100644 --- a/lib/ui/controller/tim_uikit_chat_controller.dart +++ b/lib/ui/controller/tim_uikit_chat_controller.dart @@ -1,4 +1,4 @@ -// ignore_for_file: avoid_print +// ignore_for_file: avoid_print, empty_catches import 'package:flutter/cupertino.dart'; import 'package:scroll_to_index/scroll_to_index.dart'; @@ -139,11 +139,13 @@ class TIMUIKitChatController { assert(groupID != null || convType != ConvType.group); assert(userID != null || convType != ConvType.c2c); if (isNavigateToMessageListBottom && scrollController != null) { - scrollController!.animateTo( - scrollController!.position.minScrollExtent, - duration: const Duration(milliseconds: 200), - curve: Curves.ease, - ); + try{ + scrollController?.animateTo( + scrollController!.position.minScrollExtent, + duration: const Duration(milliseconds: 200), + curve: Curves.ease, + ); + }catch(e){} } return globalChatModel.sendMessageFromController( priority: priority, @@ -160,11 +162,13 @@ class TIMUIKitChatController { } else if (model != null) { /// Sends a message to the current conversation specified on `TIMUIKitChat`. 发送到 `TIMUIKitChat` 中指定的当前对话。 if (isNavigateToMessageListBottom && scrollController != null) { - scrollController?.animateTo( - scrollController!.position.minScrollExtent, - duration: const Duration(milliseconds: 200), - curve: Curves.ease, - ); + try{ + scrollController?.animateTo( + scrollController!.position.minScrollExtent, + duration: const Duration(milliseconds: 200), + curve: Curves.ease, + ); + }catch(e){} } return model!.sendMessageFromController( priority: priority, @@ -230,11 +234,13 @@ class TIMUIKitChatController { assert(groupID != null || convType != ConvType.group); assert(userID != null || convType != ConvType.c2c); if (isNavigateToMessageListBottom && scrollController != null) { - scrollController!.animateTo( - scrollController!.position.minScrollExtent, - duration: const Duration(milliseconds: 200), - curve: Curves.ease, - ); + try{ + scrollController?.animateTo( + scrollController!.position.minScrollExtent, + duration: const Duration(milliseconds: 200), + curve: Curves.ease, + ); + }catch(e){} } return globalChatModel.sendReplyMessageFromController( text: messageText, diff --git a/lib/ui/utils/time_ago.dart b/lib/ui/utils/time_ago.dart index 95cdbcc..ad601a1 100644 --- a/lib/ui/utils/time_ago.dart +++ b/lib/ui/utils/time_ago.dart @@ -1,7 +1,7 @@ // ignore_for_file: prefer_typing_uninitialized_variables import 'package:intl/intl.dart'; -import 'package:tencent_im_base/i18n/i18n_utils.dart'; +import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; class TimeAgo { List dayMap() { diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_history_message_list_item.dart b/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_history_message_list_item.dart index e50f201..535f7aa 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_history_message_list_item.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_history_message_list_item.dart @@ -1413,7 +1413,7 @@ class _TIMUIKItHistoryMessageListItemState widget.message.elemType == 6 && isDownloadWaiting) Container( - margin: const EdgeInsets.only(top: 2), + margin: const EdgeInsets.only(top: 46, right: 10), child: LoadingAnimationWidget.threeArchedCircle( color: theme.weakTextColor ?? Colors.grey, size: 20, @@ -1566,7 +1566,7 @@ class _TIMUIKItHistoryMessageListItemState widget.message.elemType == 6 && isDownloadWaiting) Container( - margin: const EdgeInsets.only(top: 24, left: 6), + margin: const EdgeInsets.only(top: 46, left: 10), child: LoadingAnimationWidget.threeArchedCircle( color: theme.weakTextColor ?? Colors.grey, size: 20, diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_message_tooltip.dart b/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_message_tooltip.dart index 18d7802..af82383 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_message_tooltip.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_message_tooltip.dart @@ -104,24 +104,14 @@ class TIMUIKitMessageTooltipState } if (PlatformUtils().isDesktop) { if (widget.message.fileElem != null) { - if (globalModal.getMessageProgress(widget.message.msgID) == 100) { - String savePath = - TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? - globalModal.getFileMessageLocation(widget.message.msgID); - File f = File(savePath); - if (f.existsSync() && widget.message.msgID != null) { - filePath = savePath; - isShowOpenFile = true; - return; - } - isShowOpenFile = false; - return; - } - String savePath = widget.message.fileElem!.localUrl ?? ''; + String savePath = TencentUtils.checkString( + globalModal.getFileMessageLocation(widget.message.msgID)) ?? + TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? + widget.message.fileElem?.path ?? + ""; File f = File(savePath); if (f.existsSync() && widget.message.msgID != null) { filePath = savePath; - globalModal.setMessageProgress(widget.message.msgID!, 100); isShowOpenFile = true; return; } @@ -399,14 +389,14 @@ class TIMUIKitMessageTooltipState } _onOpenDesktop(String path) { - if (PlatformUtils().isDesktop) { - OpenFile.open(path); - } else { - launchUrl( - Uri.parse(path), - mode: LaunchMode.externalApplication, - ); - } + try { + if (PlatformUtils().isDesktop && !PlatformUtils().isWindows) { + launchUrl(Uri.file(path)); + } else { + OpenFile.open(path); + } + // ignore: empty_catches + } catch (e) {} } _onTap(String operation, TUIChatSeparateViewModel model) async { @@ -415,32 +405,40 @@ class TIMUIKitMessageTooltipState switch (operation) { case "open": if (widget.message.fileElem != null) { - _onOpenDesktop(widget.message.fileElem!.localUrl ?? + _onOpenDesktop(TencentUtils.checkString( + globalModal.getFileMessageLocation(widget.message.msgID)) ?? + TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? widget.message.fileElem?.path ?? ""); } else if (widget.message.imageElem != null) { - _onOpenDesktop(widget.message.imageElem!.imageList?[0]?.localUrl ?? - widget.message.imageElem?.path ?? + _onOpenDesktop(TencentUtils.checkString( + widget.message.imageElem!.imageList?[0]?.localUrl) ?? + TencentUtils.checkString(widget.message.imageElem?.path) ?? ""); } else if (widget.message.videoElem != null) { - _onOpenDesktop(widget.message.videoElem!.localVideoUrl ?? - widget.message.videoElem?.videoPath ?? + _onOpenDesktop(TencentUtils.checkString( + widget.message.videoElem!.localVideoUrl) ?? + TencentUtils.checkString(widget.message.videoElem?.videoPath) ?? ""); } break; case "finder": String savePath = ""; if (widget.message.fileElem != null) { - savePath = (widget.message.fileElem!.localUrl ?? + savePath = (TencentUtils.checkString( + globalModal.getFileMessageLocation(widget.message.msgID)) ?? + TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? widget.message.fileElem?.path ?? ""); } else if (widget.message.imageElem != null) { - savePath = (widget.message.imageElem!.imageList?[0]?.localUrl ?? - widget.message.imageElem?.path ?? + savePath = (TencentUtils.checkString( + widget.message.imageElem!.imageList?[0]?.localUrl) ?? + TencentUtils.checkString(widget.message.imageElem?.path) ?? ""); } else if (widget.message.videoElem != null) { - savePath = (widget.message.videoElem!.localVideoUrl ?? - widget.message.videoElem?.videoPath ?? + savePath = (TencentUtils.checkString( + widget.message.videoElem!.localVideoUrl) ?? + TencentUtils.checkString(widget.message.videoElem?.videoPath) ?? ""); } final String fileDir = path.dirname(savePath); diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar.dart index 0588ea3..f7d2edd 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar.dart @@ -10,7 +10,6 @@ import 'package:tencent_cloud_chat_uikit/data_services/group/group_services.dart import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart'; import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; - import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar_title.dart'; import 'package:tuple/tuple.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar_title.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar_title.dart index 92126d2..97d7108 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar_title.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar_title.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:tencent_im_base/i18n/i18n_utils.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart'; +import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; class TIMUIKitAppBarTitle extends StatelessWidget { final Widget? title; diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_file_elem.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_file_elem.dart index dd27861..446da4a 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_file_elem.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_file_elem.dart @@ -5,6 +5,7 @@ import 'dart:math'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; +import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/permission.dart'; import 'package:tencent_open_file/tencent_open_file.dart'; @@ -49,10 +50,12 @@ class TIMUIKitFileElem extends StatefulWidget { class _TIMUIKitFileElemState extends TIMUIKitState { String filePath = ""; - bool isDownloading = false; + bool isWebDownloading = false; final TUIChatGlobalModel model = serviceLocator(); int downloadProgress = 0; late V2TimAdvancedMsgListener advancedMsgListener; + final GlobalKey containerKey = GlobalKey(); + double? containerHeight; @override void dispose() { @@ -75,18 +78,18 @@ class _TIMUIKitFileElemState extends TIMUIKitState { (V2TimMessageDownloadProgress messageProgress) async { if (messageProgress.msgID == widget.message.msgID) { if (messageProgress.isFinish) { - if(mounted){ + if (mounted) { setState(() { downloadProgress = 100; }); } } else { - if(mounted){ + final currentProgress = + (messageProgress.currentSize / messageProgress.totalSize * 100) + .floor(); + if (mounted && currentProgress > downloadProgress) { setState(() { - downloadProgress = (messageProgress.currentSize / - messageProgress.totalSize * - 100) - .ceil(); + downloadProgress = currentProgress; }); } } @@ -110,30 +113,22 @@ class _TIMUIKitFileElemState extends TIMUIKitState { if (PlatformUtils().isWeb) { return true; } - - if (model.getMessageProgress(widget.messageID) == 100 || - downloadProgress == 100) { - String savePath = - TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? - model.getFileMessageLocation(widget.messageID); - File f = File(savePath); - if (f.existsSync() && widget.messageID != null) { - filePath = savePath; - setState(() { - downloadProgress = 100; - }); - return true; - } - return false; - } - String savePath = widget.message.fileElem!.localUrl ?? ''; + String savePath = TencentUtils.checkString( + model.getFileMessageLocation(widget.messageID)) ?? + TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? + widget.message.fileElem?.path ?? + ''; File f = File(savePath); if (f.existsSync() && widget.messageID != null) { filePath = savePath; - setState(() { - downloadProgress = 100; - }); - model.setMessageProgress(widget.messageID!, 100); + if (downloadProgress != 100) { + setState(() { + downloadProgress = 100; + }); + } + if (model.getMessageProgress(widget.messageID) != 100) { + model.setMessageProgress(widget.messageID!, 100); + } return true; } return false; @@ -151,10 +146,12 @@ class _TIMUIKitFileElemState extends TIMUIKitState { } } - addUrlToWaitingPath() async { + addUrlToWaitingPath(TUITheme theme) async { if (widget.messageID != null) { model.addWaitingList(widget.messageID!); - print("add path success"); + } + if (model.getWaitingListLength() == 1) { + await downloadFile(theme); } } @@ -195,7 +192,25 @@ class _TIMUIKitFileElemState extends TIMUIKitState { await model.downloadFile(); } + Future hasZeroSize(String filePath) async { + try { + final file = File(filePath); + final fileSize = await file.length(); + return fileSize == 0; + } catch (e) { + return false; + } + } + tryOpenFile(context, theme) async { + if (!PlatformUtils().isWeb && + (await hasZeroSize(filePath) || widget.message.status == 3)) { + onTIMCallback(TIMCallback( + type: TIMCallbackType.INFO, + infoRecommendText: "不支持 0KB 文件的传输", + infoCode: 6660417)); + return; + } if (PlatformUtils().isMobile) { if (PlatformUtils().isIOS) { if (!await Permissions.checkPermission( @@ -229,6 +244,11 @@ class _TIMUIKitFileElemState extends TIMUIKitState { } void downloadWebFile(String fileUrl) async { + if (mounted) { + setState(() { + isWebDownloading = true; + }); + } String fileName = Uri.parse(fileUrl).pathSegments.last; try { http.Response response = await http.get( @@ -255,6 +275,11 @@ class _TIMUIKitFileElemState extends TIMUIKitState { ..style.display = "none" ..click(); } + if (mounted) { + setState(() { + isWebDownloading = false; + }); + } } @override @@ -280,111 +305,144 @@ class _TIMUIKitFileElemState extends TIMUIKitState { final String fileName = widget.fileElem!.fileName!; fileFormat = fileName.split(".")[max(fileName.split(".").length - 1, 0)]; } - return TIMUIKitMessageReactionWrapper( - chatModel: widget.chatModel, - isShowJump: widget.isShowJump, - clearJump: widget.clearJump, - isFromSelf: widget.message.isSelf ?? true, - isShowMessageReaction: widget.isShowMessageReaction ?? true, - message: widget.message, - child: GestureDetector( - onTap: () async { - if (PlatformUtils().isWeb) { - downloadWebFile(widget.fileElem?.path ?? ""); - return; - } - if (await hasFile()) { - if (received == 100) { - tryOpenFile(context, theme); - } else { - // 正在下载中,文件可能不完整 - onTIMCallback( - TIMCallback( - type: TIMCallbackType.INFO, - infoRecommendText: TIM_t("正在下载中"), - infoCode: 6660411, - ), - ); - } - return; - } + final RenderBox? containerRenderBox = + containerKey.currentContext?.findRenderObject() as RenderBox?; + if (containerRenderBox != null) { + containerHeight = containerRenderBox.size.height; + } - if (checkIsWaiting()) { - onTIMCallback( - TIMCallback( - type: TIMCallbackType.INFO, - infoRecommendText: TIM_t("已加入待下载队列,其他文件下载中"), - infoCode: 6660413), - ); - return; - } else { - await addUrlToWaitingPath(); - } - await downloadFile(theme); - }, - child: Container( - width: 237, - decoration: BoxDecoration( - border: Border.all( - color: - theme.weakDividerColor ?? CommonColor.weakDividerColor, - ), - borderRadius: borderRadius), - child: Stack(children: [ - ClipRRect( - //剪裁为圆角矩形 - borderRadius: borderRadius, - child: LinearProgressIndicator( - minHeight: 66, - value: (received == 100 ? 0 : received) / 100, - backgroundColor: received == 100 - ? theme.weakBackgroundColor - : Colors.white, - valueColor: AlwaysStoppedAnimation( - theme.lightPrimaryMaterialColor.shade50)), - ), - Padding( - padding: - const EdgeInsets.symmetric(vertical: 8, horizontal: 12), - child: Row( - mainAxisAlignment: widget.isSelf - ? MainAxisAlignment.end - : MainAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - constraints: - const BoxConstraints(maxWidth: 160), - child: LayoutBuilder( - builder: (buildContext, boxConstraints) { - return CustomText( - fileName, - width: boxConstraints.maxWidth, - style: TextStyle( - color: theme.darkTextColor, - fontSize: 16, - ), - ); - }, - ), - ), - if (fileSize != null) - Text( - showFileSize(fileSize), - // "${received > 0 ? (received / 1024).ceil() : (received / 1024).ceil()} KB", - style: TextStyle( - fontSize: 14, color: theme.weakTextColor), - ) - ], - )), - TIMUIKitFileIcon( - fileFormat: fileFormat, + return Row( + key: containerKey, + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.isSelf && isWebDownloading) + Container( + margin: const EdgeInsets.only(top: 2), + child: LoadingAnimationWidget.threeArchedCircle( + color: theme.weakTextColor ?? Colors.grey, + size: 20, + ), + ), + TIMUIKitMessageReactionWrapper( + chatModel: widget.chatModel, + isShowJump: widget.isShowJump, + clearJump: widget.clearJump, + isFromSelf: widget.message.isSelf ?? true, + isShowMessageReaction: widget.isShowMessageReaction ?? true, + message: widget.message, + child: GestureDetector( + onTap: () async { + try { + if (PlatformUtils().isWeb) { + if (!isWebDownloading) { + downloadWebFile(widget.fileElem?.path ?? ""); + } + return; + } + if (await hasFile()) { + if (received == 100) { + tryOpenFile(context, theme); + } else { + onTIMCallback( + TIMCallback( + type: TIMCallbackType.INFO, + infoRecommendText: TIM_t("正在下载中"), + infoCode: 6660411, ), - ])), - ]), - ))); + ); + } + return; + } + if (checkIsWaiting()) { + onTIMCallback( + TIMCallback( + type: TIMCallbackType.INFO, + infoRecommendText: TIM_t("已加入待下载队列,其他文件下载中"), + infoCode: 6660413), + ); + return; + } else { + await addUrlToWaitingPath(theme); + } + } catch (e) { + onTIMCallback(TIMCallback( + type: TIMCallbackType.INFO, + infoRecommendText: "文件处理异常", + infoCode: 6660416)); + } + }, + child: Container( + width: 237, + decoration: BoxDecoration( + border: Border.all( + color: theme.weakDividerColor ?? + CommonColor.weakDividerColor, + ), + borderRadius: borderRadius), + child: Stack(children: [ + ClipRRect( + borderRadius: borderRadius, + child: LinearProgressIndicator( + minHeight: ((containerHeight) ?? 72) - 6, + value: (received == 100 ? 0 : received) / 100, + backgroundColor: received == 100 + ? theme.weakBackgroundColor + : Colors.white, + valueColor: AlwaysStoppedAnimation( + theme.lightPrimaryMaterialColor.shade50)), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, horizontal: 12), + child: Row( + mainAxisAlignment: widget.isSelf + ? MainAxisAlignment.end + : MainAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + constraints: + const BoxConstraints(maxWidth: 160), + child: LayoutBuilder( + builder: (buildContext, boxConstraints) { + return CustomText( + fileName, + width: boxConstraints.maxWidth, + style: TextStyle( + color: theme.darkTextColor, + fontSize: 16, + ), + ); + }, + ), + ), + if (fileSize != null) + Text( + showFileSize(fileSize), + style: TextStyle( + fontSize: 14, + color: theme.weakTextColor), + ) + ], + )), + TIMUIKitFileIcon( + fileFormat: fileFormat, + ), + ])), + ]), + ))), + if (!widget.isSelf && isWebDownloading) + Container( + margin: const EdgeInsets.only(top: 2), + child: LoadingAnimationWidget.threeArchedCircle( + color: theme.weakTextColor ?? Colors.grey, + size: 20, + ), + ), + ], + ); } } diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_image_elem.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_image_elem.dart index 5aef85c..d038522 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_image_elem.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_image_elem.dart @@ -8,6 +8,7 @@ import 'package:http/http.dart' as http; import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart'; import 'package:tencent_cloud_chat_uikit/data_services/message/message_services.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; +import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart'; import 'package:tencent_open_file/tencent_open_file.dart'; import 'package:universal_html/html.dart' as html; import 'dart:io'; @@ -68,7 +69,7 @@ class _TIMUIKitImageElem extends TIMUIKitState { super.didUpdateWidget(oldWidget); } - String getBigPicUrl() { + String getOriginImgURL() { // 实际拿的是原图 V2TimImage? img = MessageUtils.getImageFromImgList( widget.message.imageElem!.imageList, @@ -257,7 +258,7 @@ class _TIMUIKitImageElem extends TIMUIKitState { return await _saveImageToLocal(context, path, isAsset: true, theme: theme); } else { - String imgUrl = getBigPicUrl(); + String imgUrl = getOriginImgURL(); if (widget.message.imageElem!.imageList![0]!.localUrl != '' && widget.message.imageElem!.imageList![0]!.localUrl != null) { File f = File(widget.message.imageElem!.imageList![0]!.localUrl!); @@ -300,6 +301,14 @@ class _TIMUIKitImageElem extends TIMUIKitState { return img; } + void launchDesktopFile(String path) { + if (PlatformUtils().isWindows) { + OpenFile.open(path); + } else { + launchUrl(Uri.file(path)); + } + } + Widget errorPage(theme) => Container( height: MediaQuery.of(context).size.height, color: theme.black, @@ -310,16 +319,85 @@ class _TIMUIKitImageElem extends TIMUIKitState { child: errorDisplay(context, theme), )); + bool checkIfDownloadSuccess() { + final localUrl = TencentUtils.checkString( + model.getFileMessageLocation(widget.message.msgID)) ?? + widget.message.imageElem!.imageList![0]!.localUrl; + return TencentUtils.checkString(localUrl) != null && + File(localUrl!).existsSync(); + } + + _onClickOpenImageInNewWindow() { + final localUrl = TencentUtils.checkString( + model.getFileMessageLocation(widget.message.msgID)) ?? + widget.message.imageElem!.imageList![0]!.localUrl; + Future.delayed(const Duration(milliseconds: 0), () async { + final isDownloaded = checkIfDownloadSuccess(); + if (isDownloaded) { + launchDesktopFile(localUrl ?? ""); + } else { + onTIMCallback(TIMCallback( + infoCode: 6660414, + infoRecommendText: TIM_t("正在下载原始资源,请稍候..."), + type: TIMCallbackType.INFO)); + } + }); + } + + _handleOnTapPreviewImageOnDesktop({ + double? positionRadio, + String? originImgUrl, + }) { + final localUrl = TencentUtils.checkString( + model.getFileMessageLocation(widget.message.msgID)) ?? + widget.message.imageElem!.imageList![0]!.localUrl; + if (checkIfDownloadSuccess()) { + TUIKitWidePopup.showMedia( + aspectRatio: positionRadio, + context: context, + mediaLocalPath: localUrl ?? "", + onClickOrigin: () => _onClickOpenImageInNewWindow()); + } else { + if (TencentUtils.checkString(originImgUrl) != null) { + TUIKitWidePopup.showMedia( + aspectRatio: positionRadio, + context: context, + mediaURL: originImgUrl, + onClickOrigin: () => _onClickOpenImageInNewWindow()); + } else { + onTIMCallback(TIMCallback( + infoCode: 6660414, + infoRecommendText: TIM_t("正在下载中"), + type: TIMCallbackType.INFO)); + } + } + } + Widget _renderNetworkImage( dynamic heroTag, double? positionRadio, TUITheme? theme, {String? path, V2TimImage? originalImg, V2TimImage? smallImg}) { try { - final isDesktopScreen = - TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; - String bigImgUrl = originalImg?.url ?? getBigPicUrl(); - if (bigImgUrl.isEmpty && smallImg?.url != null) { - bigImgUrl = smallImg!.url!; + String originImgUrl = originalImg?.url ?? getOriginImgURL(); + if (originImgUrl.isEmpty && smallImg?.url != null) { + originImgUrl = smallImg!.url!; } + + final imageWidget = Hero( + tag: heroTag, + child: PlatformUtils().isWeb + ? Image.network(path ?? smallImg?.url ?? originalImg!.url!, + fit: BoxFit.contain) + : CachedNetworkImage( + alignment: Alignment.topCenter, + imageUrl: path ?? smallImg?.url ?? originalImg!.url!, + errorWidget: (context, error, stackTrace) => errorPage(theme), + fit: BoxFit.contain, + cacheKey: smallImg?.uuid ?? originalImg!.uuid, + placeholder: (context, url) => + Image(image: MemoryImage(kTransparentImage)), + fadeInDuration: const Duration(milliseconds: 0), + )); + return Stack( alignment: widget.message.isSelf ?? true ? AlignmentDirectional.topEnd @@ -327,40 +405,30 @@ class _TIMUIKitImageElem extends TIMUIKitState { children: [ getImage( GestureDetector( - onTap: () { + onTap: () async { if (PlatformUtils().isWeb) { - launchUrl( - Uri.parse(widget.message.imageElem?.path ?? ""), - mode: LaunchMode.externalApplication, - ); + TUIKitWidePopup.showMedia( + aspectRatio: positionRadio, + context: context, + mediaURL: widget.message.imageElem?.path ?? "", + onClickOrigin: () => launchUrl( + Uri.parse(widget.message.imageElem?.path ?? ""), + mode: LaunchMode.externalApplication, + )); return; } - if (isDesktopScreen) { - if (TencentUtils.checkString(widget - .message.imageElem!.imageList![0]!.localUrl) != - null && - File(widget.message.imageElem!.imageList![0]!.localUrl!) - .existsSync()) { - if (PlatformUtils().isWindows) { - OpenFile.open( - widget.message.imageElem!.imageList![0]!.localUrl); - } else { - launchUrl(Uri.file(widget - .message.imageElem!.imageList![0]!.localUrl!)); - } - }else{ - onTIMCallback(TIMCallback( - infoCode: 6660414, - infoRecommendText: TIM_t("正在下载中"), - type: TIMCallbackType.INFO)); - } + if (PlatformUtils().isDesktop) { + _handleOnTapPreviewImageOnDesktop( + positionRadio: positionRadio, + originImgUrl: originImgUrl, + ); } else { Navigator.of(context).push( PageRouteBuilder( opaque: false, // set to false pageBuilder: (_, __, ___) => ImageScreen( imageProvider: CachedNetworkImageProvider( - path ?? bigImgUrl, + path ?? originImgUrl, cacheKey: widget.message.msgID, ), heroTag: heroTag, @@ -371,32 +439,12 @@ class _TIMUIKitImageElem extends TIMUIKitState { ); } }, - child: Container( - constraints: - const BoxConstraints(minWidth: 20, minHeight: 20), - child: Hero( - tag: heroTag, - child: PlatformUtils().isWeb - ? Image.network( - path ?? smallImg?.url ?? originalImg!.url!, - fit: BoxFit.contain) - : - // Image.network(smallImg?.url ?? ""), - CachedNetworkImage( - // width: double.infinity, - alignment: Alignment.topCenter, - imageUrl: - path ?? smallImg?.url ?? originalImg!.url!, - // use small image in message list as priority - errorWidget: (context, error, stackTrace) => - errorPage(theme), - fit: BoxFit.contain, - cacheKey: smallImg?.uuid ?? originalImg!.uuid, - placeholder: (context, url) => - Image(image: MemoryImage(kTransparentImage)), - fadeInDuration: const Duration(milliseconds: 0), - )), - ), + child: positionRadio != null + ? AspectRatio( + aspectRatio: positionRadio, + child: imageWidget, + ) + : imageWidget, ), imageElem: e) ], @@ -436,6 +484,25 @@ class _TIMUIKitImageElem extends TIMUIKitState { final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; + final imageWidget = Hero( + tag: heroTag, + child: preloadImage != null + ? FittedBox( + fit: BoxFit.contain, + child: RawImage( + image: preloadImage, + fit: BoxFit.contain, + ), + ) + : FittedBox( + fit: BoxFit.contain, + child: Image.file( + File(smallImage), + fit: BoxFit.contain, + ), + ), + ); + return Stack( alignment: AlignmentDirectional.topStart, children: [ @@ -450,11 +517,11 @@ class _TIMUIKitImageElem extends TIMUIKitState { GestureDetector( onTap: () { if (PlatformUtils().isDesktop) { - if (PlatformUtils().isWindows) { - OpenFile.open(showImage); - } else { - launchUrl(Uri.file(showImage)); - } + TUIKitWidePopup.showMedia( + aspectRatio: positionRadio, + mediaLocalPath: showImage, + context: context, + onClickOrigin: () => launchDesktopFile(showImage)); } else { Navigator.of(context).push( PageRouteBuilder( @@ -470,22 +537,12 @@ class _TIMUIKitImageElem extends TIMUIKitState { ); } }, - child: Container( - constraints: - const BoxConstraints(minWidth: 20, minHeight: 20), - child: Hero( - tag: heroTag, - child: preloadImage != null - ? RawImage( - image: preloadImage, - fit: BoxFit.contain, - ) - : Image.file( - File(smallImage), - fit: BoxFit.contain, - ), - ), - )), + child: positionRadio != null + ? AspectRatio( + aspectRatio: positionRadio, + child: imageWidget, + ) + : imageWidget), imageElem: null) ], ); @@ -623,6 +680,8 @@ class _TIMUIKitImageElem extends TIMUIKitState { if (widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING) { isSent = true; } + final isDesktopScreen = + TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; final heroTag = "${widget.message.msgID ?? widget.message.id ?? widget.message.timestamp ?? DateTime.now().millisecondsSinceEpoch}${widget.isFrom}"; @@ -639,7 +698,7 @@ class _TIMUIKitImageElem extends TIMUIKitState { builder: (BuildContext context, BoxConstraints constraints) { return ConstrainedBox( constraints: BoxConstraints( - maxWidth: constraints.maxWidth * 0.5, + maxWidth: constraints.maxWidth * (isDesktopScreen ? 0.4 : 0.5), minWidth: 64, maxHeight: 256, ), diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_video_elem.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_video_elem.dart index 7cdb019..1d78f38 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_video_elem.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_video_elem.dart @@ -13,6 +13,7 @@ import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitMessageItem/TIMUIKitMessageReaction/tim_uikit_message_reaction_wrapper.dart'; import 'package:tencent_cloud_chat_uikit/ui/widgets/video_screen.dart'; +import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart'; import 'package:tencent_open_file/tencent_open_file.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -166,6 +167,15 @@ class _TIMUIKitVideoElemState extends TIMUIKitState { downloadMessageDetailAndSave(); } + void launchDesktopFile(String path) { + if (PlatformUtils().isWindows) { + OpenFile.open(path); + } else { + launchUrl(Uri.file(path)); + } + } + + @override Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { final theme = value.theme; @@ -175,10 +185,14 @@ class _TIMUIKitVideoElemState extends TIMUIKitState { return GestureDetector( onTap: () { if (PlatformUtils().isWeb) { - launchUrl( - Uri.parse(widget.message.videoElem?.videoPath ?? ""), - mode: LaunchMode.externalApplication, - ); + final url = widget.message.videoElem?.videoUrl ?? widget.message.videoElem?.videoPath ?? ""; + TUIKitWidePopup.showMedia( + context: context, + mediaURL: url, + onClickOrigin: () => launchUrl( + Uri.parse(url), + mode: LaunchMode.externalApplication, + )); return; } if (PlatformUtils().isDesktop) { @@ -188,19 +202,20 @@ class _TIMUIKitVideoElemState extends TIMUIKitState { TencentUtils.checkString(videoElem.localVideoUrl); final videoPath = TencentUtils.checkString(videoElem.videoPath); final videoUrl = videoElem.videoUrl; - if (localVideoUrl != null) { - if (PlatformUtils().isWindows) { - OpenFile.open(localVideoUrl); - } else { - launchUrl(Uri.file(localVideoUrl)); - } + launchDesktopFile(localVideoUrl); + // todo + // TUIKitWidePopup.showMedia( + // context: context, + // mediaPath: localVideoUrl, + // onClickOrigin: () => launchDesktopFile(localVideoUrl)); } else if (videoPath != null) { - if (PlatformUtils().isWindows) { - OpenFile.open(videoPath); - } else { - launchUrl(Uri.file(videoPath)); - } + launchDesktopFile(videoPath); + // todo + // TUIKitWidePopup.showMedia( + // context: context, + // mediaPath: videoPath, + // onClickOrigin: () => launchDesktopFile(videoPath)); } else if (TencentUtils.isTextNotEmpty(videoUrl)) { onTIMCallback(TIMCallback( infoCode: 6660414, 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 a02d16b..7e4c37b 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_more_panel.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_more_panel.dart @@ -455,9 +455,16 @@ class _MorePanelState extends TIMUIKitState { TUITheme theme, ) async { try { + if (!await Permissions.checkPermission( + context, + Permission.camera.value, + theme, + )) { + return; + } if (!await Permissions.checkPermission( context, - Permission.camera.value, + Permission.photos.value, theme, )) { return; diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart index c400393..6eeda06 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart @@ -42,6 +42,8 @@ class TIMUIKitInputTextField extends StatefulWidget { /// conversation id final String conversationID; + final TIMUIKitChatConfig? chatConfig; + /// conversation type final ConvType conversationType; @@ -116,7 +118,8 @@ class TIMUIKitInputTextField extends StatefulWidget { required this.currentConversation, this.groupType, this.atMemberPanelScroll, - this.groupID}) + this.groupID, + this.chatConfig}) : super(key: key); @override @@ -147,15 +150,51 @@ class _InputTextFieldState extends TIMUIKitState { currentCursor = value; } + void deleteStickerFromText() { + String originalText = textEditingController.text; + String text; + final cursorPosition = + currentCursor ?? originalText.length; + + if (originalText == zeroWidthSpace) { + _handleSoftKeyBoardDelete(); + } else if (originalText.isNotEmpty) { + if (cursorPosition == originalText.length) { + text = originalText.characters.skipLast(1).toString(); + currentCursor = null; + } else if (cursorPosition > 0 && cursorPosition < originalText.length) { + final firstString = originalText.substring(0, cursorPosition - 2); + final secondString = originalText.substring(cursorPosition); + text = '$firstString$secondString'; + if(currentCursor != null){ + currentCursor = currentCursor! - 2; + } + } else { + text = originalText.characters.skipLast(1).toString(); + currentCursor = null; + } + textEditingController.text = text; + + if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) { + textEditingController.selection = TextSelection.fromPosition(TextPosition( + offset: currentCursor ?? textEditingController.text.length)); + focusNode.requestFocus(); + } + } + } + void addStickerToText(String sticker) { - final oldText = textEditingController.text; - if (currentCursor != null && currentCursor! > -1) { - final firstString = oldText.substring(0, currentCursor); - final secondString = oldText.substring(currentCursor!); + final currentText = textEditingController.text; + if (currentCursor != null && + currentCursor! > -1 && + currentCursor! < currentText.length + 1) { + final firstString = currentText.substring(0, currentCursor); + final secondString = currentText.substring(currentCursor!); currentCursor = currentCursor! + sticker.length; textEditingController.text = "$firstString$sticker$secondString"; } else { - textEditingController.text = "$oldText$sticker"; + currentCursor = null; + textEditingController.text = "$currentText$sticker"; } if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) { @@ -169,7 +208,8 @@ class _InputTextFieldState extends TIMUIKitState { return text.replaceAll(RegExp(r'\ufeff'), ""); } - Future handleSetDraftText([String? id, ConvType? convType]) async { + Future handleSetDraftText( + {String? id, ConvType? convType, String? groupID}) async { String text = textEditingController.text; String convID = id ?? widget.conversationID; final isTopic = convID.contains("@TOPIC#"); @@ -180,25 +220,13 @@ class _InputTextFieldState extends TIMUIKitState { : "group_$convID"); String draftText = _filterU200b(text); return await conversationModel.setConversationDraft( - groupID: widget.groupID, + groupID: groupID ?? widget.groupID, isTopic: isTopic, isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb, conversationID: conversationID, draftText: draftText); } - backSpaceText() { - String originalText = textEditingController.text; - dynamic text; - - if (originalText == zeroWidthSpace) { - _handleSoftKeyBoardDelete(); - } else { - text = originalText.characters.skipLast(1); - textEditingController.text = text; - } - } - // 和onSubmitted一样,只是保持焦点的不同 onEmojiSubmitted() { lastText = ""; @@ -592,6 +620,8 @@ class _InputTextFieldState extends TIMUIKitState { KeyEventResult handleDesktopKeyEvent(FocusNode node, RawKeyEvent event) { final activeIndex = widget.model.activeAtIndex; final showMemberList = widget.model.showAtMemberList; + final isEneter = (event.physicalKey == PhysicalKeyboardKey.enter) || + (event.physicalKey == PhysicalKeyboardKey.numpadEnter); if (event.runtimeType == RawKeyDownEvent) { if (event.physicalKey == PhysicalKeyboardKey.backspace) { if (textEditingController.text.isEmpty && lastText.isEmpty) { @@ -602,7 +632,7 @@ class _InputTextFieldState extends TIMUIKitState { event.isAltPressed || event.isControlPressed || event.isMetaPressed) && - event.physicalKey == PhysicalKeyboardKey.enter) { + isEneter) { final offset = textEditingController.selection.baseOffset; textEditingController.text = '${lastText.substring(0, offset)}\n${lastText.substring(offset)}'; @@ -611,7 +641,7 @@ class _InputTextFieldState extends TIMUIKitState { lastText = textEditingController.text; return KeyEventResult.handled; - } else if (event.physicalKey == PhysicalKeyboardKey.enter) { + } else if (isEneter) { if (!_isComposingText) { if (!isAddingAtSearchWords || widget.model.showAtMemberList.isEmpty) { onSubmitted(); @@ -707,7 +737,10 @@ class _InputTextFieldState extends TIMUIKitState { super.didUpdateWidget(oldWidget); if (widget.conversationID != oldWidget.conversationID) { mentionedMembersMap.clear(); - handleSetDraftText(oldWidget.conversationID, oldWidget.conversationType); + handleSetDraftText( + id: oldWidget.conversationID, + convType: oldWidget.conversationType, + groupID: oldWidget.groupID); if (oldWidget.initText != widget.initText) { textEditingController.text = widget.initText ?? ""; } else { @@ -832,7 +865,7 @@ class _InputTextFieldState extends TIMUIKitState { defaultWidget: TIMUIKitTextFieldLayoutNarrow( onEmojiSubmitted: onEmojiSubmitted, onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted, - backSpaceText: backSpaceText, + backSpaceText: deleteStickerFromText, addStickerToText: addStickerToText, customStickerPanel: widget.customStickerPanel, forbiddenText: forbiddenText, @@ -864,11 +897,12 @@ class _InputTextFieldState extends TIMUIKitState { showMorePanel: widget.showMorePanel, customEmojiStickerList: widget.customEmojiStickerList), desktopWidget: TIMUIKitTextFieldLayoutWide( + chatConfig: widget.chatConfig ?? widget.model.chatConfig, theme: theme, currentConversation: widget.currentConversation, onEmojiSubmitted: onEmojiSubmitted, onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted, - backSpaceText: backSpaceText, + backSpaceText: deleteStickerFromText, addStickerToText: addStickerToText, customStickerPanel: widget.customStickerPanel, forbiddenText: forbiddenText, diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/wide.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/wide.dart index 56f80c4..08b94e2 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/wide.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/wide.dart @@ -131,6 +131,8 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget { /// show send audio icon final bool showSendAudio; + final TIMUIKitChatConfig chatConfig; + /// on text changed final void Function(String)? onChanged; @@ -183,7 +185,8 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget { required this.customEmojiStickerList, this.controller, required this.currentConversation, - required this.theme}) + required this.theme, + required this.chatConfig}) : super(key: key); @override @@ -288,12 +291,10 @@ class _TIMUIKitTextFieldLayoutWideState children: [ Text( TIM_t("回复 "), - style: TextStyle( - color: hexToColor("8f959e"), fontSize: 14), + style: TextStyle(color: hexToColor("8f959e"), fontSize: 14), ), Text( - MessageUtils.getDisplayName( - widget.model.repliedMessage!), + MessageUtils.getDisplayName(widget.model.repliedMessage!), softWrap: true, maxLines: 1, overflow: TextOverflow.ellipsis, @@ -367,7 +368,7 @@ class _TIMUIKitTextFieldLayoutWideState child: Container( child: widget.customStickerPanel != null ? widget.customStickerPanel!( - height: 400, + height: widget.chatConfig.desktopStickerPanelHeight, width: 350, sendTextMessage: () { widget.onEmojiSubmitted(); @@ -495,7 +496,8 @@ class _TIMUIKitTextFieldLayoutWideState final double? dx = (offset?.dx != null) ? offset!.dx : null; final double? dy = (offset?.dy != null && alignBox?.size.height != null) - ? offset!.dy - 420 + ? offset!.dy - + (widget.chatConfig.desktopStickerPanelHeight + 20) : null; e.onClick((dx != null && dy != null) ? Offset(dx, dy) : null); }, @@ -813,8 +815,7 @@ class _TIMUIKitTextFieldLayoutWideState generateDefaultControlBarItems() { final DesktopControlBarConfig config = - widget.model.chatConfig.desktopControlBarConfig ?? - DesktopControlBarConfig(); + widget.chatConfig.desktopControlBarConfig ?? DesktopControlBarConfig(); final List itemsList = [ if (config.showStickerPanel) DesktopControlBarItem( @@ -898,7 +899,7 @@ class _TIMUIKitTextFieldLayoutWideState TUIChatSeparateViewModel model, TUITheme theme) { final List itemsList = [ ...defaultControlBarItems, - ...(widget.model.chatConfig.additionalDesktopControlBarItems ?? []) + ...(widget.chatConfig.additionalDesktopControlBarItems ?? []) ]; return generateBarIcons(itemsList, theme); @@ -1021,10 +1022,10 @@ class _TIMUIKitTextFieldLayoutWideState child: ExtendedTextField( scrollController: _scrollController, autofocus: true, - maxLines: widget - .model.chatConfig.desktopMessageInputFieldLines, - minLines: widget - .model.chatConfig.desktopMessageInputFieldLines, + maxLines: + widget.chatConfig.desktopMessageInputFieldLines, + minLines: + widget.chatConfig.desktopMessageInputFieldLines, focusNode: widget.focusNode, onChanged: debounceFunc, keyboardType: TextInputType.multiline, diff --git a/lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart b/lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart index 4b7bd8a..fb31585 100644 --- a/lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart +++ b/lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart @@ -53,7 +53,7 @@ class TIMUIKitChat extends StatefulWidget { /// use for customize avatar final Widget Function(BuildContext context, V2TimMessage message)? - userAvatarBuilder; + userAvatarBuilder; /// Use for show conversation name. /// This field is not necessary to be provided, when `conversation` is provided, unless you want to cover this field manually. @@ -64,7 +64,7 @@ class TIMUIKitChat extends StatefulWidget { /// Avatar and name in message reaction secondary tap callback. final void Function(String userID, TapDownDetails tapDetails)? - onSecondaryTapAvatar; + onSecondaryTapAvatar; @Deprecated( "Nickname will not shows in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead") @@ -142,6 +142,8 @@ class TIMUIKitChat extends StatefulWidget { final Widget? customAppBar; + final Widget? inputTopBuilder; + /// Custom emoji panel. final CustomStickerPanel? customStickerPanel; @@ -154,46 +156,47 @@ class TIMUIKitChat extends StatefulWidget { /// Custom text field final Widget Function(BuildContext context)? textFieldBuilder; - TIMUIKitChat({Key? key, - this.groupID, - required this.conversation, - this.conversationID, - this.conversationType, - this.conversationShowName, - this.abstractMessageBuilder, - this.onTapAvatar, - @Deprecated( - "Nickname will not show in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead") this.showNickName = false, - this.showTotalUnReadCount = false, - this.messageItemBuilder, - @Deprecated( - "Please use [extraTipsActionItemBuilder] instead") this.exteraTipsActionItemBuilder, - this.extraTipsActionItemBuilder, - this.draftText, - this.textFieldHintText, - this.initFindingMsg, - this.userAvatarBuilder, - this.appBarConfig, - this.controller, - this.morePanelConfig, - this.customStickerPanel, - this.config = const TIMUIKitChatConfig(), - this.tongueItemBuilder, - this.groupAtInfoList, - this.mainHistoryListConfig, - this.onDealWithGroupApplication, - this.toolTipsConfig, - this.lifeCycle, - this.topFixWidget = const SizedBox(), - this.textFieldBuilder, - this.customEmojiStickerList = const [], - this.customAppBar, - this.onSecondaryTapAvatar, - this.customMessageHoverBarOnDesktop}) + TIMUIKitChat( + {Key? key, + this.groupID, + required this.conversation, + this.conversationID, + this.conversationType, + this.conversationShowName, + this.abstractMessageBuilder, + this.onTapAvatar, + @Deprecated( + "Nickname will not show in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead") + this.showNickName = false, + this.showTotalUnReadCount = false, + this.messageItemBuilder, + @Deprecated("Please use [extraTipsActionItemBuilder] instead") + this.exteraTipsActionItemBuilder, + this.extraTipsActionItemBuilder, + this.draftText, + this.textFieldHintText, + this.initFindingMsg, + this.userAvatarBuilder, + this.appBarConfig, + this.controller, + this.morePanelConfig, + this.customStickerPanel, + this.config = const TIMUIKitChatConfig(), + this.tongueItemBuilder, + this.groupAtInfoList, + this.mainHistoryListConfig, + this.onDealWithGroupApplication, + this.toolTipsConfig, + this.lifeCycle, + this.topFixWidget = const SizedBox(), + this.textFieldBuilder, + this.customEmojiStickerList = const [], + this.customAppBar, + this.inputTopBuilder, + this.onSecondaryTapAvatar, + this.customMessageHoverBarOnDesktop}) : super(key: key) { - startTime = DateTime - .now() - .millisecondsSinceEpoch; + startTime = DateTime.now().millisecondsSinceEpoch; } @override @@ -203,15 +206,15 @@ class TIMUIKitChat extends StatefulWidget { class _TUIChatState extends TIMUIKitState { TUIChatSeparateViewModel model = TUIChatSeparateViewModel(); final TUISelfInfoViewModel selfInfoViewModel = - serviceLocator(); + serviceLocator(); final TUIThemeViewModel themeViewModel = serviceLocator(); final TUIConversationViewModel conversationViewModel = - serviceLocator(); + serviceLocator(); TIMUIKitInputTextFieldController textFieldController = - TIMUIKitInputTextFieldController(); + TIMUIKitInputTextFieldController(); bool isInit = false; final TUIChatGlobalModel chatGlobalModel = - serviceLocator(); + serviceLocator(); bool _dragging = false; final GlobalKey alignKey = GlobalKey(); @@ -219,19 +222,13 @@ class _TUIChatState extends TIMUIKitState { late AutoScrollController autoController = AutoScrollController( viewportBoundaryGetter: () => - Rect.fromLTRB(0, 0, 0, MediaQuery - .of(context) - .padding - .bottom), + Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom), axis: Axis.vertical, ); late AutoScrollController atMemberPanelScroll = AutoScrollController( viewportBoundaryGetter: () => - Rect.fromLTRB(0, 0, 0, MediaQuery - .of(context) - .padding - .bottom), + Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom), axis: Axis.vertical, ); @@ -245,9 +242,7 @@ class _TUIChatState extends TIMUIKitState { model.onTapAvatar = widget.onTapAvatar; WidgetsBinding.instance.addPostFrameCallback((_) async { if (kProfileMode) { - widget.endTime = DateTime - .now() - .millisecondsSinceEpoch; + widget.endTime = DateTime.now().millisecondsSinceEpoch; int timeSpend = widget.endTime - widget.startTime; print("Page render time:$timeSpend ms"); } @@ -300,8 +295,8 @@ class _TUIChatState extends TIMUIKitState { final topicInfoList = await TencentImSDKPlugin.v2TIMManager .getGroupManager() .getTopicInfoList( - groupID: widget.groupID!, - topicIDList: [widget.conversation.conversationID]); + groupID: widget.groupID!, + topicIDList: [widget.conversation.conversationID]); final topicInfo = topicInfoList.data?.first.topicInfo; final draftText = topicInfo?.draftText; if (TencentUtils.checkString(draftText) != null) { @@ -367,7 +362,7 @@ class _TUIChatState extends TIMUIKitState { Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { final TUITheme theme = value.theme; final closePanel = - OptimizeUtils.throttle((_) => textFieldController.hideAllPanel(), 60); + OptimizeUtils.throttle((_) => textFieldController.hideAllPanel(), 60); final isBuild = isInit; isInit = true; @@ -386,7 +381,7 @@ class _TUIChatState extends TIMUIKitState { ], builder: (context, model, w) { final TUIChatGlobalModel chatGlobalModel = - Provider.of(context, listen: true); + Provider.of(context, listen: true); widget.controller?.model = model; widget.controller?.textFieldController = textFieldController; @@ -396,14 +391,14 @@ class _TUIChatState extends TIMUIKitState { widget.onDealWithGroupApplication != null) { filteredApplicationList = chatGlobalModel.groupApplicationList.where((item) { - return (item.groupID == widget.conversationID) && - item.handleStatus == 0; - }).toList(); + return (item.groupID == widget.conversationID) && + item.handleStatus == 0; + }).toList(); } final selfUserID = selfInfoViewModel.loginInfo?.userID; final TUIGroupListenerModel groupListenerModel = - Provider.of(context, listen: true); + Provider.of(context, listen: true); final NeedUpdate? needUpdate = groupListenerModel.needUpdate; if (needUpdate != null && needUpdate.groupID == widget.conversationID) { @@ -429,13 +424,13 @@ class _TUIChatState extends TIMUIKitState { resizeToAvoidBottomInset: false, appBar: (widget.customAppBar == null) ? TIMUIKitAppBar( - showTotalUnReadCount: widget.showTotalUnReadCount, - config: widget.appBarConfig, - conversationShowName: _getTitle(), - conversationID: _getConvID(), - showC2cMessageEditStatus: - widget.config?.showC2cMessageEditStatus ?? true, - ) + showTotalUnReadCount: widget.showTotalUnReadCount, + config: widget.appBarConfig, + conversationShowName: _getTitle(), + conversationID: _getConvID(), + showC2cMessageEditStatus: + widget.config?.showC2cMessageEditStatus ?? true, + ) : null, body: DropTarget( onDragDone: (detail) { @@ -463,6 +458,7 @@ class _TUIChatState extends TIMUIKitState { child: Stack( children: [ Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.customAppBar != null) widget.customAppBar!, if (filteredApplicationList.isNotEmpty) @@ -471,110 +467,110 @@ class _TUIChatState extends TIMUIKitState { if (widget.topFixWidget != null) widget.topFixWidget!, Expanded( child: Container( - color: theme.chatBgColor, - child: Align( - key: alignKey, - alignment: Alignment.topCenter, - child: Listener( - onPointerMove: closePanel, - child: TIMUIKitHistoryMessageListContainer( - customMessageHoverBarOnDesktop: widget - .customMessageHoverBarOnDesktop, - conversation: widget.conversation, - groupMemberInfo: model.groupMemberList - ?.firstWhere( - (element) => - element?.userID == selfUserID, + color: theme.chatBgColor, + child: Align( + key: alignKey, + alignment: Alignment.topCenter, + child: Listener( + onPointerMove: closePanel, + child: TIMUIKitHistoryMessageListContainer( + customMessageHoverBarOnDesktop: + widget.customMessageHoverBarOnDesktop, + conversation: widget.conversation, + groupMemberInfo: model.groupMemberList + ?.firstWhere( + (element) => + element?.userID == selfUserID, orElse: () => null), - textFieldController: textFieldController, - customEmojiStickerList: + textFieldController: textFieldController, + customEmojiStickerList: widget.customEmojiStickerList, - isUseDefaultEmoji: + isUseDefaultEmoji: widget.config!.isUseDefaultEmoji, - key: listContainerKey, - isAllowScroll: true, - userAvatarBuilder: widget - .userAvatarBuilder, - toolTipsConfig: widget.toolTipsConfig, - groupAtInfoList: widget.groupAtInfoList, - tongueItemBuilder: widget - .tongueItemBuilder, - onLongPressForOthersHeadPortrait: - (String? userId, String? nickName) { - textFieldController.longPressToAt( - nickName, userId); - }, - mainHistoryListConfig: + key: listContainerKey, + isAllowScroll: true, + userAvatarBuilder: widget.userAvatarBuilder, + toolTipsConfig: widget.toolTipsConfig, + groupAtInfoList: widget.groupAtInfoList, + tongueItemBuilder: widget.tongueItemBuilder, + onLongPressForOthersHeadPortrait: + (String? userId, String? nickName) { + textFieldController.longPressToAt( + nickName, userId); + }, + mainHistoryListConfig: widget.mainHistoryListConfig, - initFindingMsg: widget.initFindingMsg, - extraTipsActionItemBuilder: + initFindingMsg: widget.initFindingMsg, + extraTipsActionItemBuilder: widget.extraTipsActionItemBuilder ?? widget.exteraTipsActionItemBuilder, - conversationType: _getConvType(), - scrollController: autoController, - onSecondaryTapAvatar: + conversationType: _getConvType(), + scrollController: autoController, + onSecondaryTapAvatar: widget.onSecondaryTapAvatar, - onTapAvatar: widget.onTapAvatar, - // ignore: deprecated_member_use_from_same_package - showNickName: widget.showNickName, - messageItemBuilder: + onTapAvatar: widget.onTapAvatar, + // ignore: deprecated_member_use_from_same_package + showNickName: widget.showNickName, + messageItemBuilder: widget.messageItemBuilder, - conversationID: _getConvID(), - ), - )), - )), + conversationID: _getConvID(), + ), + )), + )), + widget.inputTopBuilder ?? Container(), Selector( builder: (context, value, child) { return value ? MultiSelectPanel( - conversationType: _getConvType(), - ) + conversationType: _getConvType(), + ) : (widget.textFieldBuilder != null - ? widget.textFieldBuilder!(context) - : TIMUIKitInputTextField( - groupID: widget.groupID, - atMemberPanelScroll: - atMemberPanelScroll, - groupType: - widget.conversation.groupType, - currentConversation: - widget.conversation, - model: model, - controller: textFieldController, - customEmojiStickerList: - widget.customEmojiStickerList, - isUseDefaultEmoji: - widget.config!.isUseDefaultEmoji, - customStickerPanel: - widget.customStickerPanel, - morePanelConfig: - widget.morePanelConfig, - scrollController: autoController, - conversationID: _getConvID(), - conversationType: _getConvType(), - initText: TencentUtils.checkString( - widget.draftText) ?? - (PlatformUtils().isWeb - ? TencentUtils.checkString( - conversationViewModel - .getWebDraft( - conversationID: widget - .conversation - .conversationID)) - : TencentUtils.checkString( - widget.conversation - .draftText)), - hintText: widget.textFieldHintText, - showMorePanel: widget.config - ?.isAllowShowMorePanel ?? - true, - showSendAudio: widget.config - ?.isAllowSoundMessage ?? - true, - showSendEmoji: widget - .config?.isAllowEmojiPanel ?? - true, - )); + ? widget.textFieldBuilder!(context) + : TIMUIKitInputTextField( + chatConfig: widget.config, + groupID: widget.groupID, + atMemberPanelScroll: + atMemberPanelScroll, + groupType: + widget.conversation.groupType, + currentConversation: + widget.conversation, + model: model, + controller: textFieldController, + customEmojiStickerList: + widget.customEmojiStickerList, + isUseDefaultEmoji: + widget.config!.isUseDefaultEmoji, + customStickerPanel: + widget.customStickerPanel, + morePanelConfig: + widget.morePanelConfig, + scrollController: autoController, + conversationID: _getConvID(), + conversationType: _getConvType(), + initText: TencentUtils.checkString( + widget.draftText) ?? + (PlatformUtils().isWeb + ? TencentUtils.checkString( + conversationViewModel + .getWebDraft( + conversationID: widget + .conversation + .conversationID)) + : TencentUtils.checkString( + widget.conversation + .draftText)), + hintText: widget.textFieldHintText, + showMorePanel: widget.config + ?.isAllowShowMorePanel ?? + true, + showSendAudio: widget.config + ?.isAllowSoundMessage ?? + true, + showSendEmoji: widget + .config?.isAllowEmojiPanel ?? + true, + )); }, selector: (c, model) { return model.isMultiSelect; @@ -603,13 +599,13 @@ class TIMUIKitChatProviderScope extends StatelessWidget { final TUIChatGlobalModel globalModel = serviceLocator(); TUIChatSeparateViewModel? model; final TUIGroupListenerModel groupListenerModel = - serviceLocator(); + serviceLocator(); final TUIThemeViewModel themeViewModel = serviceLocator(); final Widget? child; /// You could get the model from here, and transfer it to other widget from TUIKit. final Widget Function(BuildContext, TUIChatSeparateViewModel, Widget?) - builder; + builder; final List? providers; /// `TIMUIKitChatController` needs to be provided if you use it outside. @@ -636,20 +632,21 @@ class TIMUIKitChatProviderScope extends StatelessWidget { final AutoScrollController? scrollController; - TIMUIKitChatProviderScope({Key? key, - this.child, - this.providers, - this.textFieldController, - required this.builder, - this.model, - this.groupID, - this.isBuild, - required this.conversationID, - required this.conversationType, - this.controller, - this.config, - this.lifeCycle, - this.scrollController}) + TIMUIKitChatProviderScope( + {Key? key, + this.child, + this.providers, + this.textFieldController, + required this.builder, + this.model, + this.groupID, + this.isBuild, + required this.conversationID, + required this.conversationType, + this.controller, + this.config, + this.lifeCycle, + this.scrollController}) : super(key: key) { if (isBuild ?? false) { return; @@ -665,7 +662,7 @@ class TIMUIKitChatProviderScope extends StatelessWidget { model?.initForEachConversation( conversationType, conversationID, - (String value) { + (String value) { textFieldController?.textEditingController?.text = value; }, groupID: groupID, diff --git a/lib/ui/views/TIMUIKitChat/tim_uikit_chat_config.dart b/lib/ui/views/TIMUIKitChat/tim_uikit_chat_config.dart index 33e2166..f4a23e1 100644 --- a/lib/ui/views/TIMUIKitChat/tim_uikit_chat_config.dart +++ b/lib/ui/views/TIMUIKitChat/tim_uikit_chat_config.dart @@ -199,9 +199,17 @@ class TIMUIKitChatConfig { /// [Default]: false final bool isGroupAdminRecallEnabled; + /// Defines the height of the sticker panel on desktop platforms. + /// If the height of the sticker list exceeds this container height, + /// the sticker list will automatically become scrollable. + /// + /// [Default]: 400 + final double desktopStickerPanelHeight; + const TIMUIKitChatConfig( {this.onTapLink, this.timeDividerConfig, + this.desktopStickerPanelHeight = 400, this.isGroupAdminRecallEnabled = false, this.isAutoReportRead = true, this.faceURIPrefix, diff --git a/lib/ui/views/TIMUIKitChat/tim_uikit_send_file.dart b/lib/ui/views/TIMUIKitChat/tim_uikit_send_file.dart index 60bcbb0..8f4c4a7 100644 --- a/lib/ui/views/TIMUIKitChat/tim_uikit_send_file.dart +++ b/lib/ui/views/TIMUIKitChat/tim_uikit_send_file.dart @@ -9,6 +9,7 @@ import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'package:cross_file/cross_file.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart'; +import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart'; import 'package:path/path.dart' as path; import 'package:url_launcher/url_launcher.dart'; @@ -31,15 +32,27 @@ sendFileWithConfirmation( required BuildContext context}) async { bool isCanSend = true; - files.map((e) => e.path).any((filePath) { - final directory = Directory(filePath); - final isDirectoryExists = directory.existsSync(); - if (isDirectoryExists) { - isCanSend = false; - return false; - } - return true; - }); + if (!PlatformUtils().isWeb) { + files.map((e) => e.path).any((filePath) { + final directory = Directory(filePath); + final isDirectoryExists = directory.existsSync(); + if (isDirectoryExists) { + isCanSend = false; + return false; + } + return true; + }); + } else { + files.map((e) => e.name).any((fileName) { + String fileExtension = path.extension(fileName); + bool hasNoExtension = fileExtension.isEmpty; + if (hasNoExtension) { + isCanSend = false; + return false; + } + return true; + }); + } if (!isCanSend) { TUIKitWidePopup.showSecondaryConfirmDialog( @@ -71,6 +84,9 @@ sendFileWithConfirmation( child: ListView.separated( itemBuilder: (BuildContext context, int index) { final file = files[index]; + final fileName = PlatformUtils().isWeb + ? file.name + : path.basename(file.path); return Material( color: theme.wideBackgroundColor, child: InkWell( @@ -84,18 +100,13 @@ sendFileWithConfirmation( children: [ TIMUIKitFileIcon( size: 44, - fileFormat: path - .extension(file.path) - .split(".")[path - .extension(file.path) - .split(".") - .length - - 1], + fileFormat: fileName.split( + ".")[fileName.split(".").length - 1], ), const SizedBox(width: 16), Expanded( child: Text( - path.basename(file.path), + fileName, style: TextStyle( fontSize: 16, color: theme.darkTextColor), @@ -154,9 +165,12 @@ Future sendFiles( ConvType conversationType, BuildContext context) async { for (final file in files) { + final fileName = file.name; + final filePath = file.path; await MessageUtils.handleMessageError( model.sendFileMessage( - filePath: file.path, + fileName: fileName, + filePath: filePath, convID: _getConvID(conversation), convType: conversationType), context); diff --git a/lib/ui/widgets/forward_message_screen.dart b/lib/ui/widgets/forward_message_screen.dart index 781fb15..ed2c073 100644 --- a/lib/ui/widgets/forward_message_screen.dart +++ b/lib/ui/widgets/forward_message_screen.dart @@ -24,7 +24,8 @@ class ForwardMessageScreen extends StatefulWidget { {Key? key, this.isMergerForward = false, required this.conversationType, - required this.model, this.onClose}) + required this.model, + this.onClose}) : super(key: key); @override @@ -74,19 +75,25 @@ class _ForwardMessageScreenState extends TIMUIKitState { } widget.model.updateMultiSelectStatus(false); - if(widget.onClose != null){ - widget.onClose!(); - }else{ + if (widget.onClose != null) { + // widget.onClose!(); + } else { Navigator.pop(context); } } + @override + void dispose() { + super.dispose(); + widget.model.updateMultiSelectStatus(false); + } + @override Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; final TUITheme theme = value.theme; - if(isDesktopScreen){ + if (isDesktopScreen) { isMultiSelect = true; return RecentForwardList( isMultiSelect: isMultiSelect, @@ -101,16 +108,17 @@ class _ForwardMessageScreenState extends TIMUIKitState { } return Scaffold( appBar: AppBar( + centerTitle: true, title: Text( - TIM_t("选择"), + isMultiSelect ? TIM_t("选择多个会话") : TIM_t("选择一个会话"), style: TextStyle( color: theme.appbarTextColor, fontSize: 17, ), ), shadowColor: theme.weakBackgroundColor, - backgroundColor: theme.appbarBgColor ?? - theme.primaryColor, + backgroundColor: theme.appbarBgColor ?? theme.primaryColor, + leadingWidth: 80, leading: TextButton( onPressed: () { if (isMultiSelect) { @@ -120,9 +128,9 @@ class _ForwardMessageScreenState extends TIMUIKitState { }); } else { widget.model.updateMultiSelectStatus(false); - if(widget.onClose != null){ + if (widget.onClose != null) { widget.onClose!(); - }else{ + } else { Navigator.pop(context); } } @@ -135,7 +143,6 @@ class _ForwardMessageScreenState extends TIMUIKitState { ), ), ), - leadingWidth: 80, actions: [ TextButton( onPressed: () { @@ -149,9 +156,9 @@ class _ForwardMessageScreenState extends TIMUIKitState { }, child: Text( !isMultiSelect ? TIM_t("多选") : TIM_t("完成"), - style: const TextStyle( - color: Colors.white, - fontSize: 16, + style: TextStyle( + color: theme.appbarTextColor, + fontSize: 14, ), ), ) diff --git a/lib/ui/widgets/image_screen.dart b/lib/ui/widgets/image_screen.dart index 1abfe0d..832e141 100644 --- a/lib/ui/widgets/image_screen.dart +++ b/lib/ui/widgets/image_screen.dart @@ -122,124 +122,113 @@ class _ImageScreenState extends TIMUIKitState }, child: GestureDetector( onTap: close, - child: ExtendedImageGesturePageView.builder( - scrollDirection: Axis.horizontal, - controller: ExtendedPageController( - initialPage: 0, - pageSpacing: 0, - shouldIgnorePointerWhenScrolling: false, - ), - itemCount: 1, - physics: const BouncingScrollPhysics(), - itemBuilder: (context, index) { - return HeroWidget( - tag: widget.heroTag, - slidePagekey: slidePagekey, - child: ExtendedImage( - image: widget.imageProvider, - extendedImageGestureKey: - extendedImageGestureKey, - enableSlideOutPage: true, - // fit: BoxFit.scaleDown, - initGestureConfigHandler: (state) { - return GestureConfig( - minScale: 0.8, - animationMinScale: 0.6, - maxScale: 2 * fittedScale, - animationMaxScale: 2.5 * fittedScale, - speed: 1.0, - inertialSpeed: 100.0, - initialScale: initialScale, - initialAlignment: - InitialAlignment.topCenter, - hitTestBehavior: HitTestBehavior.opaque, - ); - }, - loadStateChanged: (ExtendedImageState state) { - switch (state.extendedImageLoadState) { - case LoadState.loading: - return Container( - color: Colors.black, - child: const Center( - child: CircularProgressIndicator( - color: Colors.white))); - case LoadState.completed: - final screenHeight = - MediaQuery.of(context).size.height; - final screenWidth = - MediaQuery.of(context).size.width; - final imgHeight = state.extendedImageInfo - ?.image.height ?? - 1; - final imgWidth = state - .extendedImageInfo?.image.width ?? - 0; - final imgRatio = imgWidth / imgHeight; - final screenRatio = - screenWidth / screenHeight; - final fitWidthScale = - screenRatio / imgRatio; - if (screenRatio > imgRatio) { - // Long Image - // initialScale = fitWidthScale; - fittedScale = fitWidthScale; - doubleTapScales[1] = fitWidthScale; - } else { - fittedScale = - 1 / fitWidthScale; // fittedHeight - doubleTapScales[1] = 1 / fitWidthScale; - } - return GesturedImage(state, - key: extendedImageGestureKey); - case LoadState.failed: - break; - } - return null; - }, - onDoubleTap: (ExtendedImageGestureState state) { - ///you can use define pointerDownPosition as you can, - ///default value is double tap pointer down postion. - final Offset? pointerDownPosition = - state.pointerDownPosition; - final double? begin = - state.gestureDetails!.totalScale; - double end; + child: HeroWidget( + tag: widget.heroTag, + slidePagekey: slidePagekey, + child: ExtendedImage( + image: widget.imageProvider, + extendedImageGestureKey: + extendedImageGestureKey, + enableSlideOutPage: true, + // fit: BoxFit.scaleDown, + initGestureConfigHandler: (state) { + return GestureConfig( + minScale: 0.8, + animationMinScale: 0.6, + maxScale: 2 * fittedScale, + animationMaxScale: 2.5 * fittedScale, + speed: 1.0, + inertialSpeed: 100.0, + initialScale: initialScale, + initialAlignment: + InitialAlignment.topCenter, + hitTestBehavior: HitTestBehavior.opaque, + ); + }, + loadStateChanged: (ExtendedImageState state) { + switch (state.extendedImageLoadState) { + case LoadState.loading: + return Container( + color: Colors.black, + child: const Center( + child: CircularProgressIndicator( + color: Colors.white))); + case LoadState.completed: + final screenHeight = + MediaQuery.of(context).size.height; + final screenWidth = + MediaQuery.of(context).size.width; + final imgHeight = state.extendedImageInfo + ?.image.height ?? + 1; + final imgWidth = state + .extendedImageInfo?.image.width ?? + 0; + final imgRatio = imgWidth / imgHeight; + final screenRatio = + screenWidth / screenHeight; + final fitWidthScale = + screenRatio / imgRatio; + if (screenRatio > imgRatio) { + // Long Image + // initialScale = fitWidthScale; + fittedScale = fitWidthScale; + doubleTapScales[1] = fitWidthScale; + } else { + fittedScale = + 1 / fitWidthScale; // fittedHeight + doubleTapScales[1] = 1 / fitWidthScale; + } + return GesturedImage(state, + key: extendedImageGestureKey); + case LoadState.failed: + break; + } + return null; + }, + onDoubleTap: (ExtendedImageGestureState state) { + ///you can use define pointerDownPosition as you can, + ///default value is double tap pointer down postion. + final Offset? pointerDownPosition = + state.pointerDownPosition; + final double? begin = + state.gestureDetails!.totalScale; + double end; - //remove old - _doubleClickAnimation?.removeListener( - _doubleClickAnimationListener); + //remove old + _doubleClickAnimation?.removeListener( + _doubleClickAnimationListener); - //stop pre - _doubleClickAnimationController.stop(); + //stop pre + _doubleClickAnimationController.stop(); - //reset to use - _doubleClickAnimationController.reset(); + //reset to use + _doubleClickAnimationController.reset(); - if (begin == doubleTapScales[0]) { - end = doubleTapScales[1]; - } else { - end = doubleTapScales[0]; - } + if (begin == doubleTapScales[0]) { + end = doubleTapScales[1]; + } else { + end = doubleTapScales[0]; + } - _doubleClickAnimationListener = () { - //print(_animation.value); - state.handleDoubleTap( - scale: _doubleClickAnimation!.value, - doubleTapPosition: pointerDownPosition); - }; - _doubleClickAnimation = - _doubleClickAnimationController.drive( - Tween( - begin: begin, end: end)); + _doubleClickAnimationListener = () { + //print(_animation.value); + state.handleDoubleTap( + scale: _doubleClickAnimation!.value, + doubleTapPosition: pointerDownPosition); + }; + _doubleClickAnimation = + _doubleClickAnimationController.drive( + Tween( + begin: begin, end: end)); - _doubleClickAnimation!.addListener( - _doubleClickAnimationListener); + _doubleClickAnimation!.addListener( + _doubleClickAnimationListener); - _doubleClickAnimationController.forward(); - }, - mode: ExtendedImageMode.gesture, - )); - }), + _doubleClickAnimationController.forward(); + }, + mode: ExtendedImageMode.gesture, + )), ), ), ), diff --git a/lib/ui/widgets/merger_message_screen.dart b/lib/ui/widgets/merger_message_screen.dart index 074cbca..002b66c 100644 --- a/lib/ui/widgets/merger_message_screen.dart +++ b/lib/ui/widgets/merger_message_screen.dart @@ -232,21 +232,23 @@ class MergerMessageScreenState extends TIMUIKitState { final faceUrl = message.faceUrl ?? ""; final showName = message.nickName ?? message.userID ?? ""; final theme = Provider.of(context).theme; + final isSelf = message.isSelf ?? false; return Container( margin: const EdgeInsets.only(top: 20), child: Row( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: isSelf ? MainAxisAlignment.end : MainAxisAlignment.start, children: [ - SizedBox( + if(!isSelf) SizedBox( width: 40, height: 40, child: Avatar(faceUrl: faceUrl, showName: showName), ), - const SizedBox( + if(!isSelf) const SizedBox( width: 12, ), Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: isSelf ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ Text(showName, style: TextStyle(fontSize: 12, color: theme.weakTextColor)), @@ -258,7 +260,15 @@ class MergerMessageScreenState extends TIMUIKitState { child: _getMsgItem(message), ) ], - ) + ), + if(isSelf) const SizedBox( + width: 12, + ), + if(isSelf) SizedBox( + width: 40, + height: 40, + child: Avatar(faceUrl: faceUrl, showName: showName), + ), ], ), ); diff --git a/lib/ui/widgets/video_screen.dart b/lib/ui/widgets/video_screen.dart index c43abe4..8c926bc 100644 --- a/lib/ui/widgets/video_screen.dart +++ b/lib/ui/widgets/video_screen.dart @@ -4,11 +4,10 @@ import 'dart:math'; import 'package:crypto/crypto.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; -import 'package:tencent_im_base/tencent_im_base.dart'; +import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'package:extended_image/extended_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:permission_handler/permission_handler.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart'; import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart'; import 'package:universal_html/html.dart' as html; @@ -21,11 +20,10 @@ import 'package:video_player/video_player.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; class VideoScreen extends StatefulWidget { - const VideoScreen( - {required this.message, - required this.heroTag, - required this.videoElement, - Key? key}) + const VideoScreen({required this.message, + required this.heroTag, + required this.videoElement, + Key? key}) : super(key: key); final V2TimMessage message; @@ -40,13 +38,14 @@ class _VideoScreenState extends TIMUIKitState { late VideoPlayerController videoPlayerController; late ChewieController chewieController; GlobalKey slidePagekey = - GlobalKey(); + GlobalKey(); final TUIChatGlobalModel model = serviceLocator(); bool isInit = false; + @override initState() { super.initState(); - setVideoMessage(); + setVideoPlayerController(); // 允许横屏 SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, @@ -57,14 +56,16 @@ class _VideoScreenState extends TIMUIKitState { } //保存网络视频到本地 - Future _saveNetworkVideo( - context, - String videoUrl, { - bool isAsset = true, - }) async { + Future _saveNetworkVideo(context, + String videoUrl, { + bool isAsset = true, + }) async { if (PlatformUtils().isWeb) { RegExp exp = RegExp(r"((\.){1}[^?]{2,4})"); - String? suffix = exp.allMatches(videoUrl).last.group(0); + String? suffix = exp + .allMatches(videoUrl) + .last + .group(0); var xhr = html.HttpRequest(); xhr.open('get', videoUrl); xhr.responseType = 'arraybuffer'; @@ -78,7 +79,7 @@ class _VideoScreenState extends TIMUIKitState { xhr.send(); return; } - if(PlatformUtils().isMobile){ + if (PlatformUtils().isMobile) { if (PlatformUtils().isIOS) { if (!await Permissions.checkPermission( context, @@ -91,17 +92,17 @@ class _VideoScreenState extends TIMUIKitState { AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; if ((androidInfo.version.sdkInt) >= 33) { final videos = await Permissions.checkPermission( - context,Permission.videos.value, + context, Permission.videos.value, ); - if(!videos){ + if (!videos) { return; } } else { final storage = await Permissions.checkPermission( context, Permission.storage.value, ); - if(!storage){ + if (!storage) { return; } } @@ -243,67 +244,41 @@ class _VideoScreenState extends TIMUIKitState { return width; } - setVideoMessage() async { - // Using local path while sending - // VideoPlayerController player = widget.message.videoElem!.videoUrl == null || - // widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING - // ? VideoPlayerController.file(File( - // widget.message.videoElem!.videoPath!, - // )) - // : (widget.message.videoElem?.localVideoUrl == null || - // widget.message.videoElem?.localVideoUrl == "") - // ? VideoPlayerController.network( - // widget.message.videoElem!.videoUrl!, - // ) - // : VideoPlayerController.file(File( - // widget.message.videoElem!.localVideoUrl!, - // )); + setVideoPlayerController() async { if (!PlatformUtils().isWeb) { - if (widget.message.msgID != null || widget.message.msgID != '') { - if (model.getMessageProgress(widget.message.msgID) == 100) { - String savePath; - if (widget.message.videoElem!.localVideoUrl != null && - widget.message.videoElem!.localVideoUrl != '') { - savePath = widget.message.videoElem!.localVideoUrl!; - } else { - savePath = model.getFileMessageLocation(widget.message.msgID); - } - File f = File(savePath); - if (f.existsSync()) { - widget.videoElement.localVideoUrl = - model.getFileMessageLocation(widget.message.msgID); - } + if (TencentUtils.checkString(widget.message.msgID) != null && + widget.videoElement.localVideoUrl == null) { + String savePath = model.getFileMessageLocation(widget.message.msgID); + File f = File(savePath); + if (f.existsSync()) { + widget.videoElement.localVideoUrl = savePath; } } } VideoPlayerController player = PlatformUtils().isWeb - ? ((widget.videoElement.videoPath != null && - widget.videoElement.videoPath!.isNotEmpty) || - widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING - ? VideoPlayerController.network( - widget.videoElement.videoPath!, - ) - : (widget.videoElement.localVideoUrl == null || - widget.videoElement.localVideoUrl == "") - ? VideoPlayerController.network( - widget.videoElement.videoUrl!, - ) - : VideoPlayerController.network( - widget.videoElement.localVideoUrl!, - )) - : (widget.videoElement.videoPath != null && - widget.videoElement.videoPath!.isNotEmpty) || - widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING - ? VideoPlayerController.file(File(widget.videoElement.videoPath!)) - : (widget.videoElement.localVideoUrl == null || - widget.videoElement.localVideoUrl == "") - ? VideoPlayerController.network( - widget.videoElement.videoUrl!, - ) - : VideoPlayerController.file(File( - widget.videoElement.localVideoUrl!, - )); + ? ((TencentUtils.checkString(widget.videoElement.videoPath) != null) || + widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING + ? VideoPlayerController.networkUrl( + Uri.parse(widget.videoElement.videoPath!), + ) + : (TencentUtils.checkString(widget.videoElement.localVideoUrl) == null) + ? VideoPlayerController.networkUrl( + Uri.parse(widget.videoElement.videoUrl!), + ) + : VideoPlayerController.networkUrl( + Uri.parse(widget.videoElement.localVideoUrl!), + )) + : (TencentUtils.checkString(widget.videoElement.videoPath) != null || + widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING) + ? VideoPlayerController.file(File(widget.videoElement.videoPath!)) + : (TencentUtils.checkString(widget.videoElement.localVideoUrl) == null) + ? VideoPlayerController.networkUrl( + Uri.parse(widget.videoElement.videoUrl!), + ) + : VideoPlayerController.file(File( + widget.videoElement.localVideoUrl!, + )); await player.initialize(); WidgetsBinding.instance.addPostFrameCallback((_) { double w = getVideoWidth(); @@ -315,7 +290,7 @@ class _VideoScreenState extends TIMUIKitState { showControlsOnInitialize: false, allowPlaybackSpeedChanging: false, aspectRatio: w == 0 || h == 0 ? null : w / h, - customControls: VideoCustomControls(downloadFn: () async{ + customControls: VideoCustomControls(downloadFn: () async { return await _saveVideo(); })); setState(() { @@ -330,7 +305,7 @@ class _VideoScreenState extends TIMUIKitState { didUpdateWidget(oldWidget) { if (oldWidget.videoElement.videoUrl != widget.videoElement.videoUrl || oldWidget.videoElement.videoPath != widget.videoElement.videoPath) { - setVideoMessage(); + setVideoPlayerController(); } super.didUpdateWidget(oldWidget); } @@ -350,55 +325,70 @@ class _VideoScreenState extends TIMUIKitState { @override Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { return OrientationBuilder(builder: ((context, orientation) { - return Scaffold( - body: Container( - color: Colors.transparent, - constraints: BoxConstraints.expand( - height: MediaQuery.of(context).size.height, - ), - child: ExtendedImageSlidePage( - key: slidePagekey, - slidePageBackgroundHandler: (Offset offset, Size size) { - if (orientation == Orientation.landscape) { - return Colors.black; - } - double opacity = 0.0; - opacity = offset.distance / - (Offset(size.width, size.height).distance / 2.0); - return Colors.black - .withOpacity(min(1.0, max(1.0 - opacity, 0.0))); - }, - slideType: SlideType.onlyImage, - child: ExtendedImageSlidePageHandler( - child: Container( - color: Colors.black, - child: isInit - ? Chewie( - controller: chewieController, - ) - : const Center( + return Material( + color: Colors.transparent, + child: Container( + color: Colors.transparent, + constraints: BoxConstraints.expand( + height: MediaQuery + .of(context) + .size + .height, + ), + child: ExtendedImageSlidePage( + key: slidePagekey, + slidePageBackgroundHandler: (Offset offset, Size size) { + if (orientation == Orientation.landscape) { + return Colors.black; + } + double opacity = 0.0; + opacity = offset.distance / + (Offset(size.width, size.height).distance / 2.0); + return Colors.black + .withOpacity(min(1.0, max(1.0 - opacity, 0.0))); + }, + slideType: SlideType.onlyImage, + slideEndHandler: (Offset offset, { + ExtendedImageSlidePageState? state, + ScaleEndDetails? details, + }) { + final vy = details?.velocity.pixelsPerSecond.dy ?? 0; + final oy = offset.dy; + if (vy > 300 || oy > 100) { + return true; + } + return null; + }, + child: ExtendedImageSlidePageHandler( + child: Container( + color: Colors.black, + child: isInit + ? Chewie( + controller: chewieController, + ) + : const Center( child: - CircularProgressIndicator(color: Colors.white))), - heroBuilderForSlidingPage: (Widget result) { - return Hero( - tag: widget.heroTag, - child: result, - flightShuttleBuilder: (BuildContext flightContext, - Animation animation, - HeroFlightDirection flightDirection, - BuildContext fromHeroContext, - BuildContext toHeroContext) { - final Hero hero = + CircularProgressIndicator(color: Colors.white))), + heroBuilderForSlidingPage: (Widget result) { + return Hero( + tag: widget.heroTag, + child: result, + flightShuttleBuilder: (BuildContext flightContext, + Animation animation, + HeroFlightDirection flightDirection, + BuildContext fromHeroContext, + BuildContext toHeroContext) { + final Hero hero = (flightDirection == HeroFlightDirection.pop ? fromHeroContext.widget : toHeroContext.widget) as Hero; - return hero.child; + return hero.child; + }, + ); }, - ); - }, - )), - )); + )), + )); })); } } diff --git a/lib/ui/widgets/wide_popup.dart b/lib/ui/widgets/wide_popup.dart index decced5..9b5d04f 100644 --- a/lib/ui/widgets/wide_popup.dart +++ b/lib/ui/widgets/wide_popup.dart @@ -1,9 +1,17 @@ +// ignore_for_file: unused_import + +import 'dart:io'; + +import 'package:chewie_for_us/chewie_for_us.dart'; import 'package:flutter/material.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart'; import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal_operation_key.dart'; import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart'; import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; +import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; import 'package:tencent_cloud_chat_uikit/ui/widgets/drag_widget.dart'; +import 'package:path/path.dart' as p; +import 'package:video_player/video_player.dart'; class TUIKitWidePopup { static OverlayEntry? entry; @@ -236,7 +244,7 @@ class TUIKitWidePopup { if (isUseMaterialAlert) { return showDialog( - barrierDismissible: false, + barrierDismissible: true, context: context, builder: (context) { return WillPopScope( @@ -249,7 +257,8 @@ class TUIKitWidePopup { content: contentWidget, ), onWillPop: () { - return Future.value(false); + isShow = false; + return Future.value(true); }); }); } @@ -276,4 +285,141 @@ class TUIKitWidePopup { }); Overlay.of(context).insert(entry!); } + + static void showMedia({ + String? mediaLocalPath, + String? mediaURL, + required BuildContext context, + required VoidCallback onClickOrigin, + double? aspectRatio, + }) async { + assert((mediaLocalPath != null) || (mediaURL != null), + "At least one of mediaLocalPath or mediaURL must be provided."); + + String _removeQueryString(String urlString) { + Uri uri = Uri.parse(urlString); + Uri cleanUri = Uri( + scheme: uri.scheme, + host: uri.host, + port: uri.port, + path: uri.path, + ); + return cleanUri.toString(); + } + + final String mediaPath = mediaLocalPath ?? mediaURL ?? ""; + final isLocalResource = mediaLocalPath != null; + + String fileExtension = p + .extension(isLocalResource ? mediaPath : _removeQueryString(mediaPath)); + bool isVideo = + ['.mp4', '.avi', '.mov', '.flv', '.wmv'].contains(fileExtension); + + VideoPlayerController? videoController; + ChewieController? chewieController; + Widget mediaWidget; + double? aspectRatioFinal = aspectRatio; + + if (isVideo) { + if (isLocalResource) { + videoController = VideoPlayerController.file(File(mediaPath)); + } else { + videoController = VideoPlayerController.networkUrl(Uri.parse(mediaPath)); + } + + await videoController.initialize(); + aspectRatioFinal = videoController.value.aspectRatio; + + chewieController = ChewieController( + videoPlayerController: videoController, + aspectRatio: aspectRatioFinal, + autoPlay: true, + looping: false, + autoInitialize: true, + ); + + mediaWidget = Chewie(controller: chewieController); + } else { + mediaWidget = FittedBox( + fit: BoxFit.contain, + child: isLocalResource + ? Image.file(File(mediaPath), fit: BoxFit.contain) + : Image.network(mediaPath, fit: BoxFit.contain), + ); + } + + showDialog( + barrierDismissible: true, + context: context, + builder: (context) { + return WillPopScope( + child: AlertDialog( + surfaceTintColor: Colors.transparent, + shadowColor: Colors.transparent, + backgroundColor: Colors.transparent, + titlePadding: const EdgeInsets.all(0), + contentPadding: const EdgeInsets.all(0), + content: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ConstrainedBox( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.85, + maxHeight: MediaQuery.of(context).size.height * 0.82, + ), + child: aspectRatioFinal != null + ? AspectRatio( + aspectRatio: aspectRatioFinal, + child: mediaWidget) + : mediaWidget, + ), + const SizedBox(height: 10), + InkWell( + onTap: onClickOrigin, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: const EdgeInsets.only(top: 0), + child: Icon( + Icons.open_in_new, + size: 14, + color: Colors.grey.shade200, + ), + ), + const SizedBox( + width: 8, + ), + // Custom Text Widget with designer baseline + Text( + TIM_t("在新窗口中打开"), + style: TextStyle( + fontSize: 13, + color: Colors.grey.shade200, + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + onWillPop: () { + if (isVideo) videoController?.dispose(); + return Future.value(true); + }, + ); + }); + } } diff --git a/pubspec.lock b/pubspec.lock index d119ffb..98e50b0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + sha256: "0816708f5fbcacca324d811297153fe3c8e047beb5c6752e12292d2974c17045" url: "https://pub.dev" source: hosted - version: "61.0.0" + version: "62.0.0" adaptive_action_sheet: dependency: "direct main" description: @@ -21,18 +21,18 @@ packages: dependency: transitive description: name: analyzer - sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + sha256: "21862995c9932cd082f89d72ae5f5e2c110d1a0204ad06e4ebaee8307b76b834" url: "https://pub.dev" source: hosted - version: "5.13.0" + version: "6.0.0" args: dependency: transitive description: name: args - sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" async: dependency: transitive description: @@ -117,10 +117,10 @@ packages: dependency: transitive description: name: build - sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc" + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" build_config: dependency: transitive description: @@ -141,26 +141,26 @@ packages: dependency: transitive description: name: build_resolvers - sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95 + sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.1" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced" + sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" url: "https://pub.dev" source: hosted - version: "2.4.4" + version: "2.4.6" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "88a57f2ac99849362e73878334caa9f06ee25f31d2adced882b8337838c84e1e" + sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" url: "https://pub.dev" source: hosted - version: "7.2.9" + version: "7.2.10" built_collection: dependency: transitive description: @@ -173,10 +173,10 @@ packages: dependency: transitive description: name: built_value - sha256: "7dd62d9faf105c434f3d829bbe9c4be02ec67f5ed94832222116122df67c5452" + sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166" url: "https://pub.dev" source: hosted - version: "8.6.0" + version: "8.6.1" cached_network_image: dependency: "direct main" description: @@ -213,10 +213,10 @@ packages: dependency: transitive description: name: camera_android - sha256: f83e406d34f5faa80bf0f5c3beee4b4c11da94a94e9621c1bb8e312988621b4b + sha256: f43d07f9d7228ea1ca87d22e30881bd68da4b78484a1fbd1f1408b412a41cefb url: "https://pub.dev" source: hosted - version: "0.10.8+2" + version: "0.10.8+3" camera_avfoundation: dependency: transitive description: @@ -285,10 +285,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" + sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.5.0" collection: dependency: "direct main" description: @@ -345,14 +345,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + dart_internal: + dependency: transitive + description: + name: dart_internal + sha256: dae3976f383beddcfcd07ad5291a422df2c8c0a8a03c52cda63ac7b4f26e0f4e + url: "https://pub.dev" + source: hosted + version: "0.2.8" dart_style: dependency: transitive description: name: dart_style - sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad + sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" desktop_drop: dependency: "direct main" description: @@ -365,10 +373,10 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: "499c61743e13909c13374a8c209075385858c614b9c0f2487b5f9995eeaf7369" + sha256: "2c35b6d1682b028e42d07b3aee4b98fa62996c10bc12cb651ec856a80d6a761b" url: "https://pub.dev" source: hosted - version: "9.0.1" + version: "9.0.2" device_info_plus_platform_interface: dependency: transitive description: @@ -397,42 +405,42 @@ packages: dependency: "direct main" description: name: extended_image - sha256: "73b7051722be79f9e8f8c120951fd9d3b22e6153fda6105c322fb88c066952d6" + sha256: e77d18f956649ba6e5ecebd0cb68542120886336a75ee673788145bd4c3f0767 url: "https://pub.dev" source: hosted - version: "8.0.1" + version: "8.0.2" extended_image_library: dependency: transitive description: name: extended_image_library - sha256: f2eba5c8500c5a7ce1f0db703b787756cb3bc65cd3818636d5fe9a9ace011ee3 + sha256: af3ff1c09c23ca7663f94272313d63499a6bd19121e99378e375e0cf2ac7a3e4 url: "https://pub.dev" source: hosted - version: "3.5.1" + version: "3.5.2" extended_text: dependency: "direct main" description: name: extended_text - sha256: "75ddf28ce7d5be33a050ff2179b6567b4b98e6225ad3e61e4c3748f7448c25f7" + sha256: dec14c9b36d9bbaaf007da5998f5dc72a2dbd5b877601d7b7970bb42524b3ced url: "https://pub.dev" source: hosted - version: "11.0.0" + version: "11.0.1" extended_text_field: dependency: "direct main" description: name: extended_text_field - sha256: "6cf8c090de4dc1e309cf3b24cb9448d7463c6c17926b628cf0954631bf4e56db" + sha256: e93248bb9b04a3e6c5e88a6a96e1c08cc765097657ab25aabe409e06a4f6760a url: "https://pub.dev" source: hosted - version: "12.0.0" + version: "12.0.1" extended_text_library: dependency: transitive description: name: extended_text_library - sha256: "308b50cfcc8e3accf46a09cb692715fbd1097333817c15b0f7527de1766bc1ff" + sha256: c06fbd8e3b6eedadf50cd6c109bbbd80921a6c43e4422d3b4ec9d4cb36ce4555 url: "https://pub.dev" source: hosted - version: "11.0.1" + version: "11.0.2" fast_i18n: dependency: "direct dev" description: @@ -469,10 +477,42 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf" + sha256: b1729fc96627dd44012d0a901558177418818d6bd428df59dcfeb594e5f66432 url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "5.3.2" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046" + url: "https://pub.dev" + source: hosted + version: "0.9.2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "7a6f1ae6107265664f3f7f89a66074882c4d506aef1441c9af313c1f7e6f41ce" + url: "https://pub.dev" + source: hosted + version: "0.9.3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26" + url: "https://pub.dev" + source: hosted + version: "0.9.3" fixnum: dependency: transitive description: @@ -498,10 +538,10 @@ packages: dependency: transitive description: name: flutter_cache_manager - sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3" + sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.3.1" flutter_easyrefresh: dependency: "direct main" description: @@ -530,10 +570,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: dc6d5258653f6857135b32896ccda7f7af0c54dcec832495ad6835154c6c77c0 + sha256: "4b1bfbb802d76320a1a46d9ce984106135093efd9d969765d07c2125af107bdf" url: "https://pub.dev" source: hosted - version: "0.6.15" + version: "0.6.17" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -562,10 +602,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: "6ff8c902c8056af9736de2689f63f81c42e2d642b9f4c79dbf8790ae48b63012" + sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.0.7" flutter_web_plugins: dependency: transitive description: flutter @@ -607,10 +647,10 @@ packages: dependency: transitive description: name: html - sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8" + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" url: "https://pub.dev" source: hosted - version: "0.15.3" + version: "0.15.4" http: dependency: "direct main" description: @@ -647,50 +687,74 @@ packages: dependency: "direct main" description: name: image_gallery_saver - sha256: "009b7722cd8507fd72c7f2cb7cbc46d6e15ad0895469cfcc39a10f86e3556979" + sha256: "0aba74216a4d9b0561510cb968015d56b701ba1bd94aace26aacdd8ae5761816" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" image_picker: dependency: "direct main" description: name: image_picker - sha256: "9978d3510af4e6a902e545ce19229b926e6de6a1828d6134d3aab2e129a4d270" + sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c url: "https://pub.dev" source: hosted - version: "0.8.7+5" + version: "0.8.9" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: c2f3c66400649bd132f721c88218945d6406f693092b2f741b79ae9cdb046e59 + sha256: d2bab152deb2547ea6f53d82ebca9b7e77386bb706e5789e815d37e08ea475bb url: "https://pub.dev" source: hosted - version: "0.8.6+16" + version: "0.8.7+3" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "98f50d6b9f294c8ba35e25cc0d13b04bfddd25dbc8d32fa9d566a6572f2c081c" + sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" url: "https://pub.dev" source: hosted - version: "2.1.12" + version: "2.2.0" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: d779210bda268a03b57e923fb1e410f32f5c5e708ad256348bcbf1f44f558fd0 + sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b url: "https://pub.dev" source: hosted - version: "0.8.7+4" + version: "0.8.8" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4 + url: "https://pub.dev" + source: hosted + version: "0.2.1" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8" + sha256: "7c7b96bb9413a9c28229e717e6fd1e3edd1cc5569c1778fcca060ecf729b65ee" url: "https://pub.dev" source: hosted - version: "2.6.3" + version: "2.8.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952 + url: "https://pub.dev" + source: hosted + version: "0.2.1" intl: dependency: "direct main" description: @@ -775,10 +839,10 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: @@ -831,10 +895,10 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "28386bbe89ab5a7919a47cea99cdd1128e5a6e0bbd7eaafe20440ead84a15de3" + sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" package_info_plus_platform_interface: dependency: transitive description: @@ -919,58 +983,50 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" url: "https://pub.dev" source: hosted - version: "2.1.6" - pedantic: - dependency: transitive - description: - name: pedantic - sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602" - url: "https://pub.dev" - source: hosted - version: "1.11.1" + version: "2.1.7" permission_handler: dependency: "direct main" description: name: permission_handler - sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8" + sha256: "415af30ba76a84faccfe1eb251fe1e4fdc790f876924c65ad7d6ed7a1404bcd6" url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.4.2" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: d8cc6a62ded6d0f49c6eac337e080b066ee3bce4d405bd9439a61e1f1927bfe8 + sha256: "3b61f3da3b1c83bc3fb6a2b431e8dab01d0e5b45f6a3d9c7609770ec88b2a89e" url: "https://pub.dev" source: hosted - version: "10.2.1" + version: "10.3.0" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: ee96ac32f5a8e6f80756e25b25b9f8e535816c8e6665a96b6d70681f8c4f7e85 + sha256: "7a187b671a39919462af2b5e813148365b71a615979165a119868d667fe90c03" url: "https://pub.dev" source: hosted - version: "9.0.8" + version: "9.1.3" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84" + sha256: "463a07cb7cc6c758a7a1c7da36ce666bb80a0b4b5e92df0fa36872e0ed456993" url: "https://pub.dev" source: hosted - version: "3.9.0" + version: "3.11.1" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b + sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098 url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "0.1.3" petitparser: dependency: transitive description: @@ -1079,58 +1135,58 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022" + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749" + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb + sha256: b046999bf0ff58f04c364491bb803dcfa8f42e47b19c75478f53d323684a8cc1 url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.3.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa" + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5" + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.2.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173" + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" shelf: dependency: transitive description: @@ -1147,14 +1203,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" - shell: - dependency: transitive - description: - name: shell - sha256: fd3b7b97e5e7f734138543d5815c6cb6cdd2a1645a0def8ac8e05577cddfbe03 - url: "https://pub.dev" - source: hosted - version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -1164,10 +1212,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" sqflite: dependency: transitive description: @@ -1180,26 +1228,26 @@ packages: dependency: transitive description: name: sqflite_common - sha256: e77abf6ff961d69dfef41daccbb66b51e9983cdd5cb35bf30733598057401555 + sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.5+1" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" stream_transform: dependency: transitive description: @@ -1224,6 +1272,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + tencent_chat_i18n_tool: + dependency: transitive + description: + name: tencent_chat_i18n_tool + sha256: ac8171d2574ed18babedd0cb67e937e255bf02fcb72f55408d033f74d4b11949 + url: "https://pub.dev" + source: hosted + version: "2.1.3+2" tencent_cloud_chat_sdk: dependency: transitive description: @@ -1236,18 +1292,18 @@ packages: dependency: "direct main" description: name: tencent_cloud_uikit_core - sha256: "0131874c7b15e181001c94f8a668f0ccae3006dea6e70d4e42e5531b63313a27" + sha256: "0a0f43e4c4241b25d12a9e9f0ee91922ac800a42229d97e3d21d16041ace3104" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.8" tencent_im_base: dependency: "direct main" description: name: tencent_im_base - sha256: "9b8e712bf27ffae9b686ec532ee8417b8263eba8bab04f105e28a95de1807322" + sha256: "0db83050452486571ee4ac07280a2fb4bbc07d297a54235b5cf12e46e79267d0" url: "https://pub.dev" source: hosted - version: "1.0.57" + version: "2.0.1" tencent_im_sdk_plugin_platform_interface: dependency: transitive description: @@ -1268,10 +1324,10 @@ packages: dependency: "direct main" description: name: tencent_open_file - sha256: "01f94f618da42e5593bbad0657fcd13cfc1c2360cca805d8cdfefe898cbe5429" + sha256: bb92d2f052c150a45942c564fba13d150a1b7b47525e6fdd74ccc58058ba5dcf url: "https://pub.dev" source: hosted - version: "4.0.10" + version: "4.0.11" tencent_super_tooltip: dependency: "direct main" description: @@ -1292,18 +1348,18 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.1" tim_ui_kit_sticker_plugin: dependency: "direct main" description: name: tim_ui_kit_sticker_plugin - sha256: "2a825d33076f319f6c1c87d58e2b0d650c9284ae4afd8efdc206f3e6f3582e64" + sha256: c9b0c1261bb51a5dee54bb50c6a106061b1bb10731b9c815fc5175afa60175e2 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.2.1" timing: dependency: transitive description: @@ -1324,10 +1380,10 @@ packages: dependency: "direct main" description: name: tuple - sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa" + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" typed_data: dependency: transitive description: @@ -1348,26 +1404,26 @@ packages: dependency: transitive description: name: universal_io - sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d" + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.2" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 + sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" url: "https://pub.dev" source: hosted - version: "6.1.11" + version: "6.1.12" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: eed4e6a1164aa9794409325c3b707ff424d4d1c2a785e7db67f8bbda00e36e51 + sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03" url: "https://pub.dev" source: hosted - version: "6.0.35" + version: "6.0.36" url_launcher_ios: dependency: transitive description: @@ -1396,26 +1452,26 @@ packages: dependency: transitive description: name: url_launcher_platform_interface - sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" + sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab" + sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.0.18" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" + sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.0.7" uuid: dependency: "direct main" description: @@ -1428,26 +1484,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: b96f10cbdfcbd03a65758633a43e7d04574438f059b1043104b5d61b23d38a4f + sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f" url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "1.1.7" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: "57a8e6e24662a3bdfe3b3d61257db91768700c0b8f844e235877b56480f31c69" + sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f" url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "1.1.7" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: "7430f5d834d0db4560d7b19863362cd892f1e52b43838553a3c5cdfc9ab28e5b" + sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e" url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "1.1.7" vector_math: dependency: transitive description: @@ -1460,18 +1516,18 @@ packages: dependency: "direct main" description: name: video_player - sha256: de95f0e9405f29b5582573d4166132e71f83b3158aac14e8ee5767a54f4f1fbd + sha256: "3fd106c74da32f336dc7feb65021da9b0207cb3124392935f1552834f7cce822" url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "2.7.0" video_player_android: dependency: transitive description: name: video_player_android - sha256: ae1c7d9a71c236a1bf9e567bd7ed4c90887e389a5f233b2192593f7f7395005c + sha256: f338a5a396c845f4632959511cad3542cdf3167e1b2a1a948ef07f7123c03608 url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.9" video_player_avfoundation: dependency: transitive description: @@ -1500,10 +1556,10 @@ packages: dependency: transitive description: name: wakelock_for_us - sha256: b73bfa90e5e764f41155063ae92fbd1e3a04ee6372e65ff7d288d2c3057f9498 + sha256: a5bdd445e51a617f7c24be8165230391447301f622aacd050038cee7b41989b4 url: "https://pub.dev" source: hosted - version: "0.6.3" + version: "0.6.3+1" wakelock_platform_interface: dependency: transitive description: @@ -1548,18 +1604,18 @@ packages: dependency: transitive description: name: win32 - sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" + sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee url: "https://pub.dev" source: hosted - version: "4.1.4" + version: "5.0.5" win32_registry: dependency: transitive description: name: win32_registry - sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae" + sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" xdg_directories: dependency: transitive description: @@ -1585,5 +1641,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" + dart: ">=3.0.0 <3.2.0" flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index c1fc164..1180f5d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: tencent_cloud_chat_uikit description: A powerful chat UI component library and business logic for Tencent Cloud Chat, creating seamless in-app chat modules for delightful user experiences. -version: 2.1.2 +version: 2.1.3+1 homepage: https://www.tencentcloud.com/products/im?from=pub repository: https://github.com/TencentCloud/tc-chat-uikit-flutter documentation: https://comm.qq.com/im/doc/flutter/en/TUIKit/readme.html @@ -29,7 +29,7 @@ dependencies: image_picker: ^0.8.5+3 file_picker: ^5.3.0 tencent_super_tooltip: ^0.0.1 - video_player: ^2.4.2 + video_player: ^2.7.0 chewie_for_us: ^1.5.0 flutter_slidable_for_tencent_im: ^1.4.0 flutter_plugin_record_plus: ^0.0.16 @@ -62,12 +62,12 @@ dependencies: uuid: ^3.0.6 tencent_open_file: ^4.0.10 tencent_keyboard_visibility: ^1.0.1 - tim_ui_kit_sticker_plugin: ^2.0.1 - tencent_im_base: ^1.0.57 + tim_ui_kit_sticker_plugin: ^2.2.1 + tencent_im_base: ^2.0.1 fc_native_video_thumbnail: any audioplayers: ^3.0.1 path: ^1.8.1 - tencent_cloud_uikit_core: ^1.0.2 + tencent_cloud_uikit_core: ^1.0.7 pasteboard: ^0.2.0 desktop_drop: ^0.4.1 device_info_plus: any