From 599ff9b9c43066b8a825e7cefaf89462c73cc0a2 Mon Sep 17 00:00:00 2001 From: anonymous Date: Tue, 30 May 2023 15:50:10 +0800 Subject: [PATCH] Flutter TUIKit V2.1.0 --- CHANGELOG.md | 54 +- README.md | 15 +- example/lib/GenerateUserSig.dart | 73 -- example/lib/main.dart | 11 +- .../Flutter/GeneratedPluginRegistrant.swift | 6 +- example/pubspec.lock | 286 +++----- images/svg/message_history.svg | 1 + images/svg/send_code.svg | 7 + images/svg/send_face.svg | 5 + images/svg/send_file.svg | 6 + images/svg/send_image.svg | 7 + images/svg/send_screenshot.svg | 4 + images/svg/send_video.svg | 6 + .../tui_chat_separate_view_model.dart | 69 +- .../view_models/tui_chat_global_model.dart | 107 +-- .../core/core_services_implements.dart | 2 +- .../friendship_services_implements.dart | 2 +- .../message/message_service_implement.dart | 30 +- .../message/message_services.dart | 4 +- lib/i18n/strings.i18n.json | 2 +- lib/i18n/strings_zh-Hans.i18n.json | 3 +- lib/i18n/strings_zh-Hant.i18n.json | 2 +- .../controller/tim_uikit_chat_controller.dart | 136 +++- lib/ui/utils/permission.dart | 2 +- lib/ui/utils/screen_shot.dart | 1 + lib/ui/utils/screen_utils.dart | 40 +- .../tim_uikit_add_friend.dart | 1 + .../tim_uikit_send_application.dart | 65 +- .../tim_uikit_send_application.dart | 40 +- .../tim_uikit_black_list.dart | 1 + ..._uikit_chat_history_message_list_item.dart | 511 ++++++++------ .../tim_uikit_chat_message_tooltip.dart | 160 +++-- ..._uikit_history_message_list_container.dart | 12 +- .../TIMUIKitAppBar/tim_uikit_appbar.dart | 39 +- .../tim_uikit_chat_file_elem.dart | 349 ++++++---- .../tim_uikit_chat_image_elem.dart | 313 +++++---- .../tim_uikit_chat_reply_elem.dart | 4 +- .../tim_uikit_chat_sound_elem.dart | 2 +- .../tim_uikit_chat_text_elem.dart | 4 +- .../tim_uikit_chat_text_translate_elem.dart | 4 +- .../tim_uikit_chat_video_elem.dart | 137 ++-- .../TIMUIKitTextField/at_member_panel.dart | 1 + .../TIMUIKitTextField/intl_camer_picker.dart | 2 +- .../DefaultSpecialTextSpanBuilder.dart | 2 +- .../special_text/emoji_text.dart | 2 +- .../special_text/http_text.dart | 2 +- .../TIMUIKitTextField/tim_uikit_at_text.dart | 8 +- .../tim_uikit_more_panel.dart | 4 +- .../tim_uikit_send_sound_message.dart | 2 +- .../tim_uikit_text_field.dart | 344 ++++++---- .../tim_uikit_text_field_controller.dart | 28 +- .../tim_uikit_text_field_layout/narrow.dart | 2 +- .../tim_uikit_text_field_layout/wide.dart | 289 +++++--- lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart | 44 +- .../TIMUIKitChat/tim_uikit_chat_config.dart | 19 +- .../tim_uikit_multi_select_panel.dart | 1 + .../tim_uikit_conversation.dart | 8 +- .../group_member/tui_add_group_member.dart | 1 + .../group_member/tui_delete_group_member.dart | 1 + .../widgets/tim_uikit_group_manage.dart | 8 +- .../TIMUIKitProfile/tim_uikit_profile.dart | 4 +- .../tim_uikit_profile_userinfo_card.dart | 1 + .../pureUI/tim_uikit_search_item.dart | 1 + .../link_preview/link_preview_entry.dart | 14 +- .../link_preview/widgets/link_text.dart | 42 +- lib/ui/widgets/merger_message_screen.dart | 1 + lib/ui/widgets/message_read_receipt.dart | 1 + lib/ui/widgets/text_input_bottom_sheet.dart | 2 +- .../widgets/transimit_group_owner_select.dart | 1 + lib/ui/widgets/video_custom_control.dart | 8 +- lib/ui/widgets/video_screen.dart | 4 +- lib/ui/widgets/wide_popup.dart | 267 ++++---- pub | 0 pubspec.lock | 632 ++++++++---------- pubspec.yaml | 29 +- test/tencent_cloud_chat_uikit_test.dart | 4 + 76 files changed, 2384 insertions(+), 1918 deletions(-) delete mode 100644 example/lib/GenerateUserSig.dart create mode 100644 images/svg/message_history.svg create mode 100644 images/svg/send_code.svg create mode 100644 images/svg/send_face.svg create mode 100644 images/svg/send_file.svg create mode 100644 images/svg/send_image.svg create mode 100644 images/svg/send_screenshot.svg create mode 100644 images/svg/send_video.svg delete mode 100644 pub create mode 100644 test/tencent_cloud_chat_uikit_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 86bae52..1c82a4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,55 @@ +## 2.1.0 + +### Breaking Changes + +* Migrated to Flutter 3.10.0 and Dart 3.0.0, no longer supporting projects with Flutter < 3.10.0 and Dart < 3.0.0. +* Updated the minimum requirement for Android AGP to 7.0, projects with AGP < 7.0 are no longer supported. + +We highly recommend updating to these new versions for a better experience. + +### New Features + +* Added several methods to `TIMUIKitChatController`, including `hideAllBottomPanelOnMobile`, `mentionOtherMemberInGroup`, `setInputTextField`, and `getGroupMemberList`. Please refer to the corresponding annotations for usage. +* Added more parameter fields to the `TIMUIKitChatController`'s `sendMessage` method. For details, please refer to the corresponding annotations. +* Added `onSecondaryTapAvatar` to `TIMUIKitChat`, serving as callback trigger for secondary avatar clicks in the message list. +* Introduced `isUseMessageHoverBarOnDesktop` and `desktopMessageInputFieldLines` to `TIMUIKitChatConfig`. For usage details, please refer to the corresponding annotations. + +### Improvements + +* Enhanced performance and user experience when switching conversations on Desktop, including features like text field auto-focus and draft text. +* Enabled displaying correct new lines in markdown mode. +* Changed the order of members in the mentioned member selection panel: Group Owner => Group Administrator => Member, sorted based on the code units' first differing position in the member show names. +* Implemented auto-focus after clicking a member in the mentioned member selection panel. +* Added text field auto-focus when replying to a message. +* Updated other members' display names in at-tag messages to use `namecard`, followed by `nickname` and `userId`. +* Widened Desktop message input area's control bar. +* Replaced the default icon in Desktop's message input area from `png` to `svg` for better performance and clarity. `DesktopControlBarConfig` now supports defining `svgPath` for each item as well. +* Improved Web platform detection. +* Mentioning "all" or "at all" can now only be used by group owners and administrators. +* Supported returning null for each message item builder in `MessageItemBuilder` to use the default message widget. +* Enhanced group members filtering in the group member mentioned selection panel with case-insensitive fuzzy matching, leading to increased filtering accuracy. +* For security purposes, downloading files by `fetch` and `blob` in the Web now replaces previewing files in a new browser tab, whereas previewing images and videos is displayed in a new tab on the Web. +* Changed the default order in the message tooltip menu. +* Previewing images and videos is set to open in a new tab on the Web. +* Improved the ratio for sending video messages. + +### Bug Fixes + +* Fixed issues when enabling the section function in markdown mode with `inEnableTextSelection` set to `true`. +* Addressed an issue where the replied message was removed when selecting all text in the message and clicking backspace. +* Fixed an issue where Chinese characters could not be entered while replying to a message. +* Resolved some console errors during debugging. +* Fixed an issue with links not opening in markdown mode. +* Fixed an issue that caused two `Scrollbar`s to appear in the message input field on Desktop. +* Solved an issue that might cause incorrect layout when the app is launched. +* Addressed an issue where messages were directly sent when the Enter key was pressed while entering Chinese text. +* Fixed related issues with the mentioned member selection panel on Desktop. +* Resolved an issue where images couldn't be pasted directly into the message input area for sending on the Web. +* Fixed an issue where files couldn't be sent on the Web. +* Remedied an issue where media and files couldn't be opened when local downloaded resources were deleted; now, resources will automatically re-download. +* Fixed an issue that caused the `iconImageAsset` of the `MessageToolTipItem` config to head internally to this chat UIKit. +* Improved the downloading process of media and files by avoiding frequent calls to `setState`, thus preventing the entire project from re-rendering. + ## 2.0.0 If you are upgrading from version 1.7.0, please refer to the changelog of all 2.0.0-preview versions, ranging from preview.1 to preview.7. @@ -377,4 +429,4 @@ The first released of TUIKit for Flutter of Tencent Cloud IM, the component of t * TIMUIKitGroup: Joined group list. * TIMUIKitBlackList: Blocklist. * TIMUIKitContact: Contacts list. -* TIMUIKitNewContact: New contact application list. \ No newline at end of file +* TIMUIKitNewContact: New contact application list. diff --git a/README.md b/README.md index 2a06226..56e2d57 100644 --- a/README.md +++ b/README.md @@ -74,19 +74,6 @@ Official Documentation
-## Preview Version Release Notes - -This version is a major update with version number 2.0.0-preview series, which is not backward -compatible. Tencent Cloud Chat UIKit has been extended from mobile-only (iOS/Android/mobile web) to -support all platforms, including iOS/Android/Web/Windows/macOS, resulting in significant changes to -the codebase. - -Therefore, users should evaluate the compatibility complexity of their business logic before -upgrading, while new users can use this version without any impact. - -The documentation for the new version is still being improved, and users can refer to the sample app -source code at at https://github.com/TencentCloud/chat-demo-flutter. - ## Check Out Our Sample Apps Experience our Chat and Voice/Video Call modules by trying out our sample apps. @@ -512,4 +499,4 @@ tend to learn more about the use cases. - WhatsApp Group: - QQ Group: 788910197, chat in Chinese -Our Website: \ No newline at end of file +Our Website: diff --git a/example/lib/GenerateUserSig.dart b/example/lib/GenerateUserSig.dart deleted file mode 100644 index 30e09ec..0000000 --- a/example/lib/GenerateUserSig.dart +++ /dev/null @@ -1,73 +0,0 @@ -// ignore_for_file: file_names - -import 'dart:convert'; - -import 'package:crypto/crypto.dart'; -import 'package:archive/archive.dart'; -import 'package:archive/archive_io.dart'; - -/// 生成腾讯云即时通信测试用userSig -/// Generate userSig for Tencent Cloud instant messaging test -/// -class GenerateTestUserSig { - GenerateTestUserSig({required this.sdkappid, required this.key}); - int sdkappid; - String key; - - /// 生成UserSig - /// Generate UserSig - /// - String genSig({ - required String identifier, - required int expire, - }) { - int currTime = _getCurrentTime(); - String sig = ''; - Map sigDoc = {}; - sigDoc.addAll({ - "TLS.ver": "2.0", - "TLS.identifier": identifier, - // ignore: unnecessary_this - "TLS.sdkappid": this.sdkappid, - "TLS.expire": expire, - "TLS.time": currTime, - }); - - sig = _hmacsha256( - identifier: identifier, - currTime: currTime, - expire: expire, - ); - sigDoc['TLS.sig'] = sig; - String jsonStr = json.encode(sigDoc); - List? compress = const ZLibEncoder().encode(utf8.encode(jsonStr)); - return _escape(content: base64.encode(compress)); - } - - int _getCurrentTime() { - return (DateTime.now().millisecondsSinceEpoch / 1000).floor(); - } - - String _hmacsha256({ - required String identifier, - required int currTime, - int expire = 30 * 24 * 60 * 60, - }) { - int sdkappid = this.sdkappid; - String contentToBeSigned = - "TLS.identifier:$identifier\nTLS.sdkappid:$sdkappid\nTLS.time:$currTime\nTLS.expire:$expire\n"; - Hmac hmacSha256 = Hmac(sha256, utf8.encode(key)); - Digest hmacSha256Digest = - hmacSha256.convert(utf8.encode(contentToBeSigned)); - return base64.encode(hmacSha256Digest.bytes); - } - - String _escape({ - required String content, - }) { - return content - .replaceAll('+', '*') - .replaceAll('/', '-') - .replaceAll('=', '_'); - } -} diff --git a/example/lib/main.dart b/example/lib/main.dart index eb814ac..20268ac 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,9 +1,5 @@ // ignore_for_file: avoid_print -import 'package:example/GenerateUserSig.dart'; -import 'package:example/TIMUIKitChatExample.dart'; -import 'package:example/TIMUIKitConversationExample.dart'; -import 'package:example/TIMUIKitProfileExample.dart'; import 'package:flutter/material.dart'; import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'TIMUIKitAddFriendExample.dart'; @@ -74,12 +70,15 @@ class _MyHomePageState extends State { return const String.fromEnvironment('SECRET', defaultValue: ""); } + String getUsersig() { + return const String.fromEnvironment('USERSIG', defaultValue: ""); + } + initTIMUIKIT() async { int sdkappid = getSDKAPPID(); String userid = getUserID(); String secret = getSecret(); - String usersig = GenerateTestUserSig(sdkappid: sdkappid, key: secret) - .genSig(identifier: userid, expire: 24 * 7 * 60 * 60 * 1000); + String usersig = getUsersig(); if (sdkappid == 0 || userid == '' || secret == '' || usersig == '') { print("The running parameters are abnormal, please check"); return; diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index e63f903..c03736a 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,16 +7,15 @@ import Foundation import audioplayers_darwin import desktop_drop -import device_info_plus_macos +import device_info_plus import fc_native_video_thumbnail_for_us -import package_info_plus_macos +import package_info_plus import pasteboard import path_provider_foundation import photo_manager import shared_preferences_foundation import sqflite import url_launcher_macos -import wakelock_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) @@ -30,5 +29,4 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) - WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin")) } diff --git a/example/pubspec.lock b/example/pubspec.lock index 0b1b6c2..07cc86d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" audioplayers: dependency: transitive description: @@ -197,10 +197,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" charcode: dependency: transitive description: @@ -209,14 +209,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" - chewie: + chewie_for_us: dependency: transitive description: - name: chewie - sha256: e9da4898ee4859825404f507969f57113c04ca0060e152b95c9afd73934126ad + name: chewie_for_us + sha256: "0307723e811508d361fffa6f8bbd9040b1bfea5536544e4d655e10c27de002ec" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" clock: dependency: transitive description: @@ -229,10 +229,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" convert: dependency: transitive description: @@ -293,50 +293,18 @@ packages: dependency: transitive description: name: device_info_plus - sha256: b809c4ed5f7fcdb325ccc70b80ad934677dc4e2aa414bf46859a42bfdfafcbb6 + sha256: "2c35b6d1682b028e42d07b3aee4b98fa62996c10bc12cb651ec856a80d6a761b" url: "https://pub.dev" source: hosted - version: "4.1.3" - device_info_plus_linux: - dependency: transitive - description: - name: device_info_plus_linux - sha256: "77a8b3c4af06bc46507f89304d9f49dfc64b4ae004b994532ed23b34adeae4b3" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - device_info_plus_macos: - dependency: transitive - description: - name: device_info_plus_macos - sha256: "37961762fbd46d3620c7b69ca606671014db55fc1b7a11e696fd90ed2e8fe03d" - url: "https://pub.dev" - source: hosted - version: "3.0.0" + version: "9.0.2" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: "83fdba24fcf6846d3b10f10dfdc8b6c6d7ada5f8ed21d62ea2909c2dfa043773" + sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64 url: "https://pub.dev" source: hosted - version: "3.0.0" - device_info_plus_web: - dependency: transitive - description: - name: device_info_plus_web - sha256: "5890f6094df108181c7a29720bc23d0fd6159f17d82787fac093d1fefcaf6325" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - device_info_plus_windows: - dependency: transitive - description: - name: device_info_plus_windows - sha256: "23a2874af0e23ee6e3a2a0ebcecec3a9da13241f2cb93a93a44c8764df123dd7" - url: "https://pub.dev" - source: hosted - version: "4.1.0" + version: "7.0.0" diff_match_patch: dependency: transitive description: @@ -365,10 +333,10 @@ packages: dependency: transitive description: name: extended_image - sha256: "5854d0d05ee0c687d1852af9db05f15cfe058520fa56f417075705c5bce965d4" + sha256: e77d18f956649ba6e5ecebd0cb68542120886336a75ee673788145bd4c3f0767 url: "https://pub.dev" source: hosted - version: "6.4.0" + version: "8.0.2" extended_image_library: dependency: transitive description: @@ -377,6 +345,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.1" + extended_text: + dependency: transitive + description: + name: extended_text + sha256: "75ddf28ce7d5be33a050ff2179b6567b4b98e6225ad3e61e4c3748f7448c25f7" + url: "https://pub.dev" + source: hosted + version: "11.0.0" + extended_text_field: + dependency: transitive + description: + name: extended_text_field + sha256: "6cf8c090de4dc1e309cf3b24cb9448d7463c6c17926b628cf0954631bf4e56db" + url: "https://pub.dev" + source: hosted + version: "12.0.0" + extended_text_library: + dependency: transitive + description: + name: extended_text_library + sha256: "308b50cfcc8e3accf46a09cb692715fbd1097333817c15b0f7527de1766bc1ff" + url: "https://pub.dev" + source: hosted + version: "11.0.1" fake_async: dependency: transitive description: @@ -421,10 +413,10 @@ packages: dependency: transitive description: name: file_picker - sha256: b85eb92b175767fdaa0c543bf3b0d1f610fe966412ea72845fe5ba7801e763ff + sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf" url: "https://pub.dev" source: hosted - version: "5.2.10" + version: "5.3.1" file_utils: dependency: transitive description: @@ -490,10 +482,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.15" flutter_plugin_record_plus: dependency: transitive description: @@ -636,18 +628,18 @@ packages: dependency: transitive description: name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.18.1" js: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" json_annotation: dependency: transitive description: @@ -708,10 +700,10 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -724,10 +716,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" mime_type: dependency: transitive description: @@ -764,50 +756,18 @@ packages: dependency: transitive description: name: package_info_plus - sha256: f62d7253edc197fe3c88d7c2ddab82d68f555e778d55390ccc3537eca8e8d637 + sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b url: "https://pub.dev" source: hosted - version: "1.4.3+1" - package_info_plus_linux: - dependency: transitive - description: - name: package_info_plus_linux - sha256: "04b575f44233d30edbb80a94e57cad9107aada334fc02aabb42b6becd13c43fc" - url: "https://pub.dev" - source: hosted - version: "1.0.5" - package_info_plus_macos: - dependency: transitive - description: - name: package_info_plus_macos - sha256: a2ad8b4acf4cd479d4a0afa5a74ea3f5b1c7563b77e52cc32b3ee6956d5482a6 - url: "https://pub.dev" - source: hosted - version: "1.3.0" + version: "4.0.2" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: f7a0c8f1e7e981bc65f8b64137a53fd3c195b18d429fba960babc59a5a1c7ae8 + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" url: "https://pub.dev" source: hosted - version: "1.0.2" - package_info_plus_web: - dependency: transitive - description: - name: package_info_plus_web - sha256: f0829327eb534789e0a16ccac8936a80beed4e2401c4d3a74f3f39094a822d3b - url: "https://pub.dev" - source: hosted - version: "1.0.6" - package_info_plus_windows: - dependency: transitive - description: - name: package_info_plus_windows - sha256: "79524f11c42dd9078b96d797b3cf79c0a2883a50c4920dc43da8562c115089bc" - url: "https://pub.dev" - source: hosted - version: "2.1.0" + version: "2.0.1" pasteboard: dependency: transitive description: @@ -820,10 +780,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_drawing: dependency: transitive description: @@ -948,10 +908,10 @@ packages: dependency: transitive description: name: photo_manager - sha256: "55d50ad1b8f984c57fa7c4bd4980f4760e80d3d9355263cf72624a6ff1bf2b5b" + sha256: bdc4ab1fa9fb064d8ccfea6ab44119f55b220293d7ce2e19eb5a5f998db86c88 url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.6.0" platform: dependency: transitive description: @@ -964,10 +924,10 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" pointycastle: dependency: transitive description: @@ -1177,73 +1137,49 @@ packages: dependency: transitive description: name: tencent_cloud_chat_sdk - sha256: "765a93262a41080e155ce5b8a6ca20147a81c7d306f7f87444077c5eaae87e08" + sha256: f98bdb55164051e2b196cac6e2e79e60248ed8351dc5a91d25568712ccb15839 url: "https://pub.dev" source: hosted - version: "5.1.5" + version: "5.1.7" tencent_cloud_chat_uikit: dependency: "direct main" description: path: ".." relative: true source: path - version: "2.0.0+1" + version: "2.1.0" tencent_cloud_uikit_core: dependency: transitive description: name: tencent_cloud_uikit_core - sha256: "829dfde0c4fbdae019ba233f7f2c299e7cbd18c3ae20ecfe3ab4a43084a33064" + sha256: "517d760b0d497ea291d70fe6a021508e5b66f0754c72679f19ee16c0bb354e91" url: "https://pub.dev" source: hosted - version: "1.0.2" - tencent_extended_text: - dependency: transitive - description: - name: tencent_extended_text - sha256: "27a2f7ee58ada480e295102471f1733a7402178a239d0c80a7aa33a134c641ef" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - tencent_extended_text_field: - dependency: transitive - description: - name: tencent_extended_text_field - sha256: d311c240983dbf78e31b58f91e425920a40d6564942813e692a3419bf5c9deb0 - url: "https://pub.dev" - source: hosted - version: "1.0.1" - tencent_extended_text_library: - dependency: transitive - description: - name: tencent_extended_text_library - sha256: d6dad4e4e426e6319db809267f160082c44a334716e9f8593fac56d65ae75545 - url: "https://pub.dev" - source: hosted - version: "1.0.0" + version: "1.0.3" tencent_im_base: dependency: transitive description: name: tencent_im_base - sha256: "516356a80f43b94a6c0719b54e4c641cb1f164830b2b3e887d175ae862ebab3f" + sha256: "9b8e712bf27ffae9b686ec532ee8417b8263eba8bab04f105e28a95de1807322" url: "https://pub.dev" source: hosted - version: "1.0.51" + version: "1.0.57" tencent_im_sdk_plugin_desktop: dependency: "direct main" description: name: tencent_im_sdk_plugin_desktop - sha256: "5fe5ab0765183185fe4a1f94ce1fdc6ab0a450b8522011806549678edb52130d" + sha256: "8d986f2f6aedeac8d771286e31b7bbb9bbee12192461fc879c857be903a41a7f" url: "https://pub.dev" source: hosted - version: "0.1.13" + version: "0.1.19" tencent_im_sdk_plugin_platform_interface: dependency: transitive description: name: tencent_im_sdk_plugin_platform_interface - sha256: "04043582f1af698b4abe12d53cd0f043466228fae712677688988d8ff7bfc1f1" + sha256: "53263e4acd7179871aad2a67ec4964bc8fae861f54384fba2c60bd2c16d2867c" url: "https://pub.dev" source: hosted - version: "0.3.19" + version: "0.3.20" tencent_im_sdk_plugin_web: dependency: "direct main" description: @@ -1276,14 +1212,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.1" - tencent_wechat_camera_picker: - dependency: transitive - description: - name: tencent_wechat_camera_picker - sha256: "8f95b435c7a12a9221f00fe4354fb9c0f9313d79cc09ddb5902b7b418185092d" - url: "https://pub.dev" - source: hosted - version: "3.6.5+1" term_glyph: dependency: transitive description: @@ -1296,10 +1224,10 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" tim_ui_kit_sticker_plugin: dependency: transitive description: @@ -1432,10 +1360,10 @@ packages: dependency: transitive description: name: video_player - sha256: "59f7f31c919c59cbedd37c617317045f5f650dc0eeb568b0b0de9a36472bdb28" + sha256: "868a139229acb5018d22aded3eb9cb4767ff43a8216573c086b6c535a4957481" url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.6.0" video_player_android: dependency: transitive description: @@ -1468,22 +1396,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.13" - wakelock: + wakelock_for_us: dependency: transitive description: - name: wakelock - sha256: "769ecf42eb2d07128407b50cb93d7c10bd2ee48f0276ef0119db1d25cc2f87db" + name: wakelock_for_us + sha256: b73bfa90e5e764f41155063ae92fbd1e3a04ee6372e65ff7d288d2c3057f9498 url: "https://pub.dev" source: hosted - version: "0.6.2" - wakelock_macos: - dependency: transitive - description: - name: wakelock_macos - sha256: "047c6be2f88cb6b76d02553bca5a3a3b95323b15d30867eca53a19a0a319d4cd" - url: "https://pub.dev" - source: hosted - version: "0.4.0" + version: "0.6.3" wakelock_platform_interface: dependency: transitive description: @@ -1492,22 +1412,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" - wakelock_web: - dependency: transitive - description: - name: wakelock_web - sha256: "1b256b811ee3f0834888efddfe03da8d18d0819317f20f6193e2922b41a501b5" - url: "https://pub.dev" - source: hosted - version: "0.4.0" - wakelock_windows: - dependency: transitive - description: - name: wakelock_windows - sha256: "857f77b3fe6ae82dd045455baa626bc4b93cb9bb6c86bf3f27c182167c3a5567" - url: "https://pub.dev" - source: hosted - version: "0.2.1" watcher: dependency: transitive description: @@ -1520,18 +1424,34 @@ packages: dependency: transitive description: name: wechat_assets_picker - sha256: "49184fbc83f855bade59961566a6323a2015634ece1f889de5af6fa133a10706" + sha256: "5aeac81c6a28e1142a2c9ba9ee802b909c2dad9186d9a58dbe4eb74493af4743" url: "https://pub.dev" source: hosted - version: "7.3.4" + version: "8.5.0" + wechat_camera_picker: + dependency: transitive + description: + name: wechat_camera_picker + sha256: d8108ea33b1ed25933770199d08d64c210a2854bc6a326fd058a2f34dca8bf46 + url: "https://pub.dev" + source: hosted + version: "3.8.0" win32: dependency: transitive description: name: win32 - sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4 + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "4.1.4" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae" + url: "https://pub.dev" + source: hosted + version: "1.1.0" xdg_directories: dependency: transitive description: @@ -1557,5 +1477,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.19.0 <3.0.0" - flutter: ">=3.7.0" + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.10.0" diff --git a/images/svg/message_history.svg b/images/svg/message_history.svg new file mode 100644 index 0000000..3754fc4 --- /dev/null +++ b/images/svg/message_history.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/svg/send_code.svg b/images/svg/send_code.svg new file mode 100644 index 0000000..a682ddb --- /dev/null +++ b/images/svg/send_code.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/images/svg/send_face.svg b/images/svg/send_face.svg new file mode 100644 index 0000000..4f0d3c5 --- /dev/null +++ b/images/svg/send_face.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/images/svg/send_file.svg b/images/svg/send_file.svg new file mode 100644 index 0000000..3df3b42 --- /dev/null +++ b/images/svg/send_file.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/images/svg/send_image.svg b/images/svg/send_image.svg new file mode 100644 index 0000000..5677fce --- /dev/null +++ b/images/svg/send_image.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/images/svg/send_screenshot.svg b/images/svg/send_screenshot.svg new file mode 100644 index 0000000..2ec0c61 --- /dev/null +++ b/images/svg/send_screenshot.svg @@ -0,0 +1,4 @@ +] + + + \ No newline at end of file diff --git a/images/svg/send_video.svg b/images/svg/send_video.svg new file mode 100644 index 0000000..afc43a6 --- /dev/null +++ b/images/svg/send_video.svg @@ -0,0 +1,6 @@ + + + + + + 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 a342a4a..a0984ec 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 @@ -7,6 +7,7 @@ import 'package:flutter/cupertino.dart'; // ignore: unnecessary_import import 'package:flutter/foundation.dart'; +import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart'; import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:path_provider/path_provider.dart'; @@ -30,6 +31,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier { final GroupServices _groupServices = serviceLocator(); final TUIChatGlobalModel globalModel = serviceLocator(); final TUIChatModelTools tools = serviceLocator(); + final TUISelfInfoViewModel selfModel = serviceLocator(); final _uuid = const Uuid(); ChatLifeCycle? lifeCycle; @@ -57,6 +59,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier { V2TimGroupInfo? _groupInfo; String groupMemberListSeq = "0"; List? groupMemberList = []; + V2TimGroupMemberFullInfo? selfMemberInfo; double atPositionX = 0.0; double atPositionY = 0.0; int _activeAtIndex = -1; @@ -191,6 +194,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier { isGroupExist = true; _groupInfo = null; groupMemberList?.clear(); + selfMemberInfo = null; notifyListeners(); } if (conversationType == ConvType.c2c) { @@ -216,7 +220,6 @@ class TUIChatSeparateViewModel extends ChangeNotifier { } } } - markMessageAsRead(); globalModel.lifeCycle = lifeCycle; globalModel.setCurrentConversation( CurrentConversation(conversationID, conversationType ?? ConvType.c2c)); @@ -225,6 +228,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier { globalModel.setChatConfig(chatConfig); globalModel.clearRecivedNewMessageCount(); _isInit = true; + Future.delayed(const Duration(milliseconds: 300), (){ + markMessageAsRead(); + }); } Future loadListForSpecificMessage({ @@ -504,6 +510,8 @@ class TUIChatSeparateViewModel extends ChangeNotifier { return await loadGroupMemberList( groupID: groupID, count: count, seq: nextSeq); } else { + selfMemberInfo = groupMemberList + ?.firstWhere((e) => e?.userID == selfModel.loginInfo?.userID); notifyListeners(); } } @@ -575,6 +583,11 @@ class TUIChatSeparateViewModel extends ChangeNotifier { V2TimMessage? messageInfo, OfflinePushInfo? offlinePushInfo, bool? onlineUserOnly = false, + MessagePriorityEnum priority = MessagePriorityEnum.V2TIM_PRIORITY_NORMAL, + bool? isExcludedFromUnreadCount, + bool? needReadReceipt, + String? cloudCustomData, + String? localCustomData, bool? isEditStatusMessage = false, }) async { String receiver = convType == ConvType.c2c ? convID : ''; @@ -586,27 +599,32 @@ class TUIChatSeparateViewModel extends ChangeNotifier { setLoadingMessageMap(convID, messageInfo); } final sendMsgRes = await _messageService.sendMessage( + priority: priority, + localCustomData: localCustomData, + isExcludedFromUnreadCount: isExcludedFromUnreadCount ?? false, id: id, receiver: receiver, - needReadReceipt: chatConfig.isShowGroupReadingStatus && - convType == ConvType.group && - ((chatConfig.groupReadReceiptPermissionList != null && - chatConfig.groupReadReceiptPermissionList! - .contains(_groupType)) || - (chatConfig.groupReadReceiptPermisionList != null && - chatConfig.groupReadReceiptPermisionList! - .contains(oldGroupType))), + needReadReceipt: needReadReceipt ?? + chatConfig.isShowGroupReadingStatus && + convType == ConvType.group && + ((chatConfig.groupReadReceiptPermissionList != null && + chatConfig.groupReadReceiptPermissionList! + .contains(_groupType)) || + (chatConfig.groupReadReceiptPermisionList != null && + chatConfig.groupReadReceiptPermisionList! + .contains(oldGroupType))), groupID: groupID, offlinePushInfo: offlinePushInfo, onlineUserOnly: onlineUserOnly ?? false, - cloudCustomData: showC2cMessageEditStatus == true - ? json.encode({ - "messageFeature": { - "needTyping": 1, - "version": 1, - } - }) - : "", + cloudCustomData: cloudCustomData ?? + (showC2cMessageEditStatus == true + ? json.encode({ + "messageFeature": { + "needTyping": 1, + "version": 1, + } + }) + : ""), ); if (isEditStatusMessage == false && globalModel.getMessageListPosition(conversationID) != @@ -916,6 +934,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier { Future?> sendImageMessage( {String? imagePath, + String? imageName, required String convID, dynamic inputElement, required ConvType convType}) async { @@ -939,7 +958,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier { } catch (e) {} } final imageMessageInfo = await _messageService.createImageMessage( - imagePath: image ?? imagePath, inputElement: inputElement); + imageName: imageName, + imagePath: image ?? imagePath, + inputElement: inputElement); List currentHistoryMsgList = getOriginMessageList(); final messageInfo = imageMessageInfo!.messageInfo; if (messageInfo != null) { @@ -1334,6 +1355,12 @@ class TUIChatSeparateViewModel extends ChangeNotifier { /// Offline push info OfflinePushInfo? offlinePushInfo, + MessagePriorityEnum priority = MessagePriorityEnum.V2TIM_PRIORITY_NORMAL, + bool? onlineUserOnly, + bool? isExcludedFromUnreadCount, + bool? needReadReceipt, + String? cloudCustomData, + String? localCustomData, }) { List currentHistoryMsgList = getOriginMessageList(); if (messageInfo != null) { @@ -1351,6 +1378,12 @@ class TUIChatSeparateViewModel extends ChangeNotifier { } return _sendMessage( + priority: priority, + onlineUserOnly: onlineUserOnly, + isExcludedFromUnreadCount: isExcludedFromUnreadCount, + needReadReceipt: needReadReceipt, + cloudCustomData: cloudCustomData, + localCustomData: localCustomData, convID: conversationID, id: messageInfo.id as String, convType: conversationType ?? ConvType.c2c, 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 d75acca..0981926 100644 --- a/lib/business_logic/view_models/tui_chat_global_model.dart +++ b/lib/business_logic/view_models/tui_chat_global_model.dart @@ -32,7 +32,7 @@ class CurrentConversation { CurrentConversation(this.conversationID, this.conversationType); } -class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { +class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass { final MessageService _messageService = serviceLocator(); final GroupServices _groupServices = serviceLocator(); final Map?> _messageListMap = {}; @@ -56,8 +56,8 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { late V2TimAdvancedMsgListener advancedMsgListener; int _unreadCountForConversation = 0; - // use for generate a new sliver list to show recived messag list - int _recivedNewMessageCount = 0; + // use for generate a new sliver list to show received message list + int _receivedNewMessageCount = 0; TIMUIKitChatConfig chatConfig = const TIMUIKitChatConfig(); List? _groupApplicationList; String Function(V2TimMessage message)? _abstractMessageBuilder; @@ -65,7 +65,7 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { Map.from({}); // 0 normal 1 sending final Map _c2cMessageFromUserActiveMap = Map.from({}); final Map _c2cMessageActiveTimer = Map.from({}); - bool _showC2cMessageEditStaus = true; + bool _showC2cMessageEditStatus = true; final Map _c2cMessageStatusShowTimer = Map.from({}); Map loadingMessage = {}; @@ -144,7 +144,7 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { print("start another download"); } - int getRecevied(msgID) { + int getReceived(msgID) { return messageListProgressMap[msgID] ?? 0; } @@ -173,11 +173,11 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { } int get receivedMessageListCount { - return _recivedNewMessageCount; + return _receivedNewMessageCount; } set receivedNewMessageCount(int value) { - _recivedNewMessageCount = value; + _receivedNewMessageCount = value; } int get unreadCountForConversation => _unreadCountForConversation; @@ -207,6 +207,10 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { } clearCurrentConversation() { + // Only keep the last 20 messages when existing a chat. + _messageListMap[currentSelectedConv] = + (_messageListMap[currentSelectedConv] ?? []).sublist( + max(0, ((_messageListMap[currentSelectedConv] ?? []).length - 20))); _currentConversationList.removeLast(); notifyListeners(); } @@ -216,7 +220,7 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { } setShowC2cEditStatus(bool show) { - _showC2cMessageEditStaus = show; + _showC2cMessageEditStatus = show; } /// set edit status from chats @@ -373,14 +377,14 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { _totalUnreadCount = 0; _groupApplicationList?.clear(); _totalUnreadCount = 0; - _recivedNewMessageCount = 0; + _receivedNewMessageCount = 0; _messageReadReceiptMap.clear(); _messageListProgressMap.clear(); notifyListeners(); } clearRecivedNewMessageCount() { - _recivedNewMessageCount = 0; + _receivedNewMessageCount = 0; } _preLoadImage(List msgList) { @@ -441,7 +445,6 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { return false; }); } - notifyListeners(); } setFileMessageLocation(String msgID, String location) { @@ -526,7 +529,7 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { } sendEditStatusMessage(bool isEditing, String toUser) async { - if (!_showC2cMessageEditStaus) { + if (!_showC2cMessageEditStatus) { return; } if (!(_c2cMessageFromUserActiveMap[toUser] ?? false)) { @@ -612,7 +615,7 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { ); }); } - _recivedNewMessageCount = 0; + _receivedNewMessageCount = 0; final currentMsg = _messageListMap[convID] ?? []; _messageListMap[convID] = [newMsg, ...currentMsg]; notifyListeners(); @@ -631,7 +634,7 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { } else { if (convID == currentSelectedConv) { unreadCountForConversation++; - _recivedNewMessageCount++; + _receivedNewMessageCount++; final currentMsg = _messageListMap[convID] ?? []; _messageListMap[convID] = [newMsg, ...currentMsg]; notifyListeners(); @@ -746,23 +749,12 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { } return; } - if (messageProgress.isError) { - TIMUIKitClass.onTIMCallback( - TIMCallback( - type: TIMCallbackType.INFO, - infoRecommendText: - TIM_t("视频保存失败") + ": ${messageProgress.errorCode.toString()}", - infoCode: 6660403), - ); - return; - } - if (messageProgress.totalSize != -1) { - int progrss = + int progress = (messageProgress.currentSize / messageProgress.totalSize * 100) .ceil(); - if (progrss > 1) { - setMessageProgress(messageProgress.msgID, progrss); + if (progress > 1) { + setMessageProgress(messageProgress.msgID, progress); } } } @@ -791,6 +783,12 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { required String convID, ValueChanged? setInputField, OfflinePushInfo? offlinePushInfo, + MessagePriorityEnum priority = MessagePriorityEnum.V2TIM_PRIORITY_NORMAL, + bool? onlineUserOnly, + bool? isExcludedFromUnreadCount, + bool? needReadReceipt, + String? cloudCustomData, + String? localCustomData, }) { final TUIChatModelTools tools = serviceLocator(); List currentHistoryMsgList = _messageListMap[convID] ?? []; @@ -807,6 +805,12 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { loadingMessage[convID] = [messageInfoWithSender]; } return _sendMessage( + priority: priority, + onlineUserOnly: onlineUserOnly, + isExcludedFromUnreadCount: isExcludedFromUnreadCount, + needReadReceipt: needReadReceipt, + cloudCustomData: cloudCustomData, + localCustomData: localCustomData, convID: convID, setInputField: setInputField, id: messageInfo.id as String, @@ -868,6 +872,11 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { bool? isEditStatusMessage = false, GroupReceiptAllowType? groupType, ValueChanged? setInputField, + MessagePriorityEnum priority = MessagePriorityEnum.V2TIM_PRIORITY_NORMAL, + bool? isExcludedFromUnreadCount, + bool? needReadReceipt, + String? cloudCustomData, + String? localCustomData, }) async { String receiver = convType == ConvType.c2c ? convID : ''; String groupID = convType == ConvType.group ? convID : ''; @@ -876,23 +885,28 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { final sendMsgRes = await _messageService.sendMessage( id: id, receiver: receiver, - needReadReceipt: chatConfig.isShowGroupReadingStatus && - convType == ConvType.group && - ((chatConfig.groupReadReceiptPermissionList != null && - chatConfig.groupReadReceiptPermissionList! - .contains(groupType)) || - (chatConfig.groupReadReceiptPermisionList != null && - chatConfig.groupReadReceiptPermisionList! - .contains(oldGroupType))), + needReadReceipt: needReadReceipt ?? + chatConfig.isShowGroupReadingStatus && + convType == ConvType.group && + ((chatConfig.groupReadReceiptPermissionList != null && + chatConfig.groupReadReceiptPermissionList! + .contains(groupType)) || + (chatConfig.groupReadReceiptPermisionList != null && + chatConfig.groupReadReceiptPermisionList! + .contains(oldGroupType))), groupID: groupID, + priority: priority, + localCustomData: localCustomData, + isExcludedFromUnreadCount: isExcludedFromUnreadCount ?? false, offlinePushInfo: offlinePushInfo, onlineUserOnly: onlineUserOnly ?? false, - cloudCustomData: json.encode({ - "messageFeature": { - "needTyping": 1, - "version": 1, - } - })); + cloudCustomData: cloudCustomData ?? + json.encode({ + "messageFeature": { + "needTyping": 1, + "version": 1, + } + })); if (isEditStatusMessage == false) { updateMessage(sendMsgRes, convID, id, convType, groupType, setInputField); } @@ -904,7 +918,7 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { {bool needResetNewMessageCount = true}) { _messageListMap[conversationID] = messageList; if (needResetNewMessageCount) { - _recivedNewMessageCount = 0; + _receivedNewMessageCount = 0; } notifyListeners(); } @@ -961,18 +975,21 @@ class TUIChatGlobalModel extends ChangeNotifier with TIMUIKitClass { String convID, ) { message.id = DateTime.now().millisecondsSinceEpoch.toString(); + final activeMessageList = _messageListMap[convID]; if (activeMessageList == null || activeMessageList.isEmpty) { return; } final msgID = message.msgID; - _messageListMap[currentSelectedConv] = activeMessageList.map((item) { + _messageListMap[convID] = activeMessageList.map((item) { if (item.msgID == msgID) { return message; } return item; }).toList(); - notifyListeners(); + if (convID == currentSelectedConv) { + notifyListeners(); + } } List? getMessageList(String conversationID) { diff --git a/lib/data_services/core/core_services_implements.dart b/lib/data_services/core/core_services_implements.dart index 14fd3af..cc2ac7d 100644 --- a/lib/data_services/core/core_services_implements.dart +++ b/lib/data_services/core/core_services_implements.dart @@ -31,7 +31,7 @@ class LoginInfo { {this.sdkAppID = 0, this.userSig = "", this.userID = "", this.loginUser}); } -class CoreServicesImpl with CoreServices { +class CoreServicesImpl implements CoreServices { V2TimUserFullInfo? _loginInfo; late int _sdkAppID; late String _userID; diff --git a/lib/data_services/friendShip/friendship_services_implements.dart b/lib/data_services/friendShip/friendship_services_implements.dart index ba50771..e03936f 100644 --- a/lib/data_services/friendShip/friendship_services_implements.dart +++ b/lib/data_services/friendShip/friendship_services_implements.dart @@ -3,7 +3,7 @@ import 'package:tencent_cloud_chat_uikit/data_services/friendShip/friendship_ser import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart'; import 'package:tencent_im_base/tencent_im_base.dart'; -class FriendshipServicesImpl with FriendshipServices { +class FriendshipServicesImpl implements FriendshipServices { final CoreServicesImpl _coreService = serviceLocator(); @override diff --git a/lib/data_services/message/message_service_implement.dart b/lib/data_services/message/message_service_implement.dart index 405567a..ae369c3 100644 --- a/lib/data_services/message/message_service_implement.dart +++ b/lib/data_services/message/message_service_implement.dart @@ -36,26 +36,26 @@ class MessageServiceImpl extends MessageService { lastMsgID: lastMsgID, lastMsgSeq: lastMsgSeq, messageTypeList: messageTypeList); - final List reponseMessageList = res.data ?? []; + final List responsedMessageList = res.data ?? []; final conversationID = userID ?? groupID; final cachedMessageList = messgaeListMap[conversationID]; - List commbinedMessageList = []; + List combinedMessageList = []; // 加载更多 if (lastMsgID != null && cachedMessageList != null) { - commbinedMessageList = [...cachedMessageList, ...reponseMessageList]; + combinedMessageList = [...cachedMessageList, ...responsedMessageList]; // 首次加载 } else { final bool existSendingMessage = sendingMessage[conversationID] != null && sendingMessage[conversationID]!.isNotEmpty; // 存在未发送完成的消息 if (existSendingMessage) { - commbinedMessageList = [ + combinedMessageList = [ ...sendingMessage[conversationID]!, - ...reponseMessageList + ...responsedMessageList ]; } else { sendingMessage.remove(conversationID); - commbinedMessageList = reponseMessageList; + combinedMessageList = responsedMessageList; } } if (res.code != 0) { @@ -64,15 +64,16 @@ class MessageServiceImpl extends MessageService { errorMsg: res.desc, errorCode: res.code)); } - if (reponseMessageList.isEmpty || - (!PlatformUtils().isWeb && reponseMessageList.length < count) || - (PlatformUtils().isWeb && reponseMessageList.length < min(count, 20))) { + if (responsedMessageList.isEmpty || + (!PlatformUtils().isWeb && responsedMessageList.length < count) || + (PlatformUtils().isWeb && + responsedMessageList.length < min(count, 20))) { haveMoreData = false; } else { haveMoreData = true; } return MessageListResponse( - haveMoreData: haveMoreData, data: commbinedMessageList); + haveMoreData: haveMoreData, data: combinedMessageList); } @override @@ -302,11 +303,13 @@ class MessageServiceImpl extends MessageService { @override Future createImageMessage( - {String? imagePath, dynamic inputElement}) async { + {String? imageName, String? imagePath, dynamic inputElement}) async { final res = await TencentImSDKPlugin.v2TIMManager .getMessageManager() .createImageMessage( - imagePath: imagePath ?? "", inputElement: inputElement); + imageName: imageName, + imagePath: imagePath ?? "", + inputElement: inputElement); if (res.code == 0) { return res.data; } @@ -345,7 +348,7 @@ class MessageServiceImpl extends MessageService { bool isExcludedFromUnreadCount = false, bool needReadReceipt = false, OfflinePushInfo? offlinePushInfo, - String? cloudCustomData, // 云自定义消息字段,只能在消息发送前添加 + String? cloudCustomData, String? localCustomData, }) async { final result = @@ -812,5 +815,4 @@ class MessageServiceImpl extends MessageService { } return result.data?[text] ?? ""; } - } diff --git a/lib/data_services/message/message_services.dart b/lib/data_services/message/message_services.dart index 6f027a3..99e9437 100644 --- a/lib/data_services/message/message_services.dart +++ b/lib/data_services/message/message_services.dart @@ -3,6 +3,7 @@ import 'package:tencent_im_base/tencent_im_base.dart'; class MessageListResponse { final bool haveMoreData; final List data; + MessageListResponse({required this.haveMoreData, required this.data}); } @@ -51,6 +52,7 @@ abstract class MessageService { Future removeSimpleMsgListener({V2TimSimpleMsgListener? listener}); Future createTextMessage({required String text}); + Future createFaceMessage( {required int index, required String data}); @@ -88,7 +90,7 @@ abstract class MessageService { {required V2TimMessage message}); Future createImageMessage( - {String? imagePath, dynamic inputElement}); + {String? imageName, String? imagePath, dynamic inputElement}); Future createVideoMessage( {String? videoPath = "", diff --git a/lib/i18n/strings.i18n.json b/lib/i18n/strings.i18n.json index b441b8d..a757905 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":"会话"} \ 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":"视频文件异常"} \ 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 5a79486..cab5bb7 100644 --- a/lib/i18n/strings_zh-Hans.i18n.json +++ b/lib/i18n/strings_zh-Hans.i18n.json @@ -688,5 +688,6 @@ "k_1698c42": "在访达中打开", "k_066fxsz": "查看文件夹", "k_0k432y2": "无法发送,包含文件夹", - "k_002wb4y": "会话" + "k_002wb4y": "会话", + "k_0od4qyh": "视频文件异常" } \ 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 0c8ea1c..46b286f 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":"会话"} \ 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":"视频文件异常"} \ 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 a2fadb7..054ca99 100644 --- a/lib/ui/controller/tim_uikit_chat_controller.dart +++ b/lib/ui/controller/tim_uikit_chat_controller.dart @@ -1,6 +1,7 @@ // ignore_for_file: avoid_print import 'package:flutter/cupertino.dart'; +import 'package:scroll_to_index/scroll_to_index.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.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'; @@ -8,6 +9,8 @@ import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; class TIMUIKitChatController { late TUIChatSeparateViewModel? model; + late TIMUIKitInputTextFieldController? textFieldController; + late AutoScrollController? scrollController; final TUIChatGlobalModel globalChatModel = serviceLocator(); @@ -35,13 +38,11 @@ class TIMUIKitChatController { false; } - /// clear the current conversation; - /// 销毁 + /// Clear the current conversation; @Deprecated("No need to dispose after tencent_cloud_chat_uikit 0.1.4") dispose() {} - /// clear the history of current conversation; - /// 清除历史记录 + /// Clear the history of current conversation; /// Please provide `convID`, if you use `TIMUIKitChatController` without specifying to a `TIMUIKitChat`. clearHistory([String? convID]) { if (convID != null) { @@ -51,7 +52,6 @@ class TIMUIKitChatController { } /// refresh the history message list manually; - /// 手动刷新会话历史消息列表 /// Please provide `convType` and `convID`, if you use `TIMUIKitChatController` without specifying to a `TIMUIKitChat`. Future refreshCurrentHistoryList( [String? convID, ConvType? convType]) async { @@ -64,8 +64,7 @@ class TIMUIKitChatController { return false; } - /// update single message at UI model - /// 更新单条消息 + /// Update single message at UI model /// Please provide `convID`, if you use `TIMUIKitChatController` without specifying to a `TIMUIKitChat`. Future updateMessage( { @@ -87,39 +86,72 @@ class TIMUIKitChatController { } /// Sends a message to the specified conversation, or to the current conversation specified on `TIMUIKitChat`. - /// 发送消息到指定的对话,或者发送到 `TIMUIKitChat` 中指定的当前对话。 /// You must provide `convType` and either `userID` or `groupID`, only if you use `TIMUIKitChat` without specifying a `TIMUIKitChatController`, you must provide these parameters. - /// 您需要提供 `convType` 和 `userID` 或 `groupID`, 只有在如果您使用 `TIMUIKitChat` 而没有指定 `TIMUIKitChatController`,则必须提供这些参数。 Future?>? sendMessage({ required V2TimMessage? messageInfo, /// The type of the target conversation: either ConvType.group or ConvType.c2c. Required if using `TIMUIKitChat` without specifying a `TIMUIKitChatController`. - /// 目标对话的类型:ConvType.group 或 ConvType.c2c。只有在如果您使用 `TIMUIKitChat` 而没有指定 `TIMUIKitChatController`,则必须提供此参数。 ConvType? convType, /// The user ID of the target one-to-one conversation. Required if convType is ConvType.c2c. - /// 目标一对一对话的用户 ID。如果 convType 是 ConvType.c2c,则必填。 String? userID, /// The target group ID. Required if convType is ConvType.group. - /// 目标群组的 ID。如果 convType 是 ConvType.group,则必填。 String? groupID, /// A callback function to update the input field when message sending fails. - /// 当消息发送失败时,用于更新输入框的回调函数。 ValueChanged? setInputField, /// Offline push information. - /// 离线推送信息。 OfflinePushInfo? offlinePushInfo, + + /// Whether automatically scrolling to the bottom of the message list after sending a message. + /// This field solely works when `TIMUIKitChatController` is specified for use within a `TIMUIKitChat`. + bool isNavigateToMessageListBottom = true, + + /// Message priorities. This field is valid only for group chat messages. + /// You are advised to set higher priorities for important messages (such as red packet and gift messages) + /// and set lower priorities for frequent but unimportant messages (such as like messages). + MessagePriorityEnum priority = MessagePriorityEnum.V2TIM_PRIORITY_NORMAL, + + /// Whether the message can be received only by online users. + /// If this field is set to true, the message cannot be pulled in recipient historical message pulling. + /// This field is often used to implement weak notification features such as "The other party is typing" or unimportant notifications in the group. This field is not supported by audio-video groups (AVChatRoom). + bool? onlineUserOnly, + + /// Whether the message is excluded from the conversation unread message count. + bool? isExcludedFromUnreadCount, + + /// Whether a read receipt is required. + bool? needReadReceipt, + + /// Cloud custom data (saved in the cloud, will be sent to the peer end, + /// and can still be pulled after the app is uninstalled and reinstalled) + String? cloudCustomData, + + /// Local custom message data (saved locally, will not be sent to the peer end, + /// and will become invalid after the app is uninstalled and reinstalled). + String? localCustomData, }) { if (convType != null) { - /// Sends a message to the specified conversation. 发送消息到指定的对话。 + /// Sends a message to the specified conversation. assert((groupID == null) != (userID == null)); assert(groupID != null || convType != ConvType.group); assert(userID != null || convType != ConvType.c2c); - + if (isNavigateToMessageListBottom) { + scrollController?.animateTo( + scrollController!.position.minScrollExtent, + duration: const Duration(milliseconds: 200), + curve: Curves.ease, + ); + } return globalChatModel.sendMessageFromController( + priority: priority, + onlineUserOnly: onlineUserOnly, + isExcludedFromUnreadCount: isExcludedFromUnreadCount, + needReadReceipt: needReadReceipt, + cloudCustomData: cloudCustomData, + localCustomData: localCustomData, messageInfo: messageInfo, convType: convType, convID: (convType == ConvType.group ? groupID : userID) ?? "", @@ -127,15 +159,28 @@ class TIMUIKitChatController { offlinePushInfo: offlinePushInfo); } else if (model != null) { /// Sends a message to the current conversation specified on `TIMUIKitChat`. 发送到 `TIMUIKitChat` 中指定的当前对话。 + if (isNavigateToMessageListBottom) { + scrollController?.animateTo( + scrollController!.position.minScrollExtent, + duration: const Duration(milliseconds: 200), + curve: Curves.ease, + ); + } return model!.sendMessageFromController( - messageInfo: messageInfo, offlinePushInfo: offlinePushInfo); + priority: priority, + onlineUserOnly: onlineUserOnly, + isExcludedFromUnreadCount: isExcludedFromUnreadCount, + needReadReceipt: needReadReceipt, + cloudCustomData: cloudCustomData, + localCustomData: localCustomData, + messageInfo: messageInfo, + offlinePushInfo: offlinePushInfo); } return null; } /// Send forward message; - /// 逐条转发 - /// This method needs use with TIMUIKitChat directly or model been initialized. + /// This function solely works when `TIMUIKitChatController` is specified for use within a `TIMUIKitChat`. sendForwardMessage({ required List conversationList, }) async { @@ -143,7 +188,6 @@ class TIMUIKitChatController { } /// Send merger message; - /// 合并转发 /// This method needs use with TIMUIKitChat directly or model been initialized. Future?> sendMergerMessage({ required List conversationList, @@ -158,8 +202,7 @@ class TIMUIKitChatController { context: context); } - /// Set local custom data; returns the bool shows if succeed - /// 为本地消息配置额外String字段 + /// Set local custom data; returns the bool shows if succeed. /// Please provide `convID`, if you use `TIMUIKitChatController` without specifying to a `TIMUIKitChat`. Future setLocalCustomData(String msgID, String localCustomData, [String? convID]) async { @@ -171,8 +214,7 @@ class TIMUIKitChatController { msgID, localCustomData, conversationID); } - /// Set local custom int; returns the bool shows if succeed - /// 为本地消息配置额外int字段 + /// Set local custom int; returns the bool shows if succeed. /// Please provide `convID`, if you use `TIMUIKitChatController` without specifying to a `TIMUIKitChat`. Future setLocalCustomInt(String msgID, int localCustomInt, [String? convID]) async { @@ -185,8 +227,52 @@ class TIMUIKitChatController { } /// Get current conversation, returns UserID or GroupID if in the chat page, returns "" if not. - /// 获取当前会话ID,如果在Chat页面,返回UserID or GroupID, 反之返回"" String getCurrentConversation() { return globalChatModel.currentSelectedConv; } + + /// Hide all bottom panels, including the sticker panel and the additional functions panel, on mobile devices. + /// This function solely works when `TIMUIKitChatController` is specified for use within a `TIMUIKitChat`. + void hideAllBottomPanelOnMobile() { + textFieldController?.hideAllPanel(); + } + + /// Mention or @ other members in a group manually. + /// This function solely works when `TIMUIKitChatController` is specified for use within a `TIMUIKitChat`. + void mentionOtherMemberInGroup( + {required String showNameInMessage, required String userID}) { + textFieldController?.longPressToAt(showNameInMessage, userID); + } + + /// Set the content within the message input text field. + /// This function solely works when `TIMUIKitChatController` is specified for use within a `TIMUIKitChat`. + void setInputTextField(String text) { + textFieldController?.setTextField(text); + } + + /// Returns the list of group members of current group chat based on the provided keyword. + /// + /// This method filters the group members based on the given keyword. If the keyword is not provided, + /// it returns the entire list of group members. The filtering is performed by checking if the keyword + /// is contained within the userID, nickName, or friendRemark properties of each group member. + /// + /// [keyword] (optional) - The keyword to filter the group members. If not provided, the entire list of group members is returned. + /// This function solely works when `TIMUIKitChatController` is specified for use within a `TIMUIKitChat`. + List getGroupMemberList({String? keyword}) { + final List memberList = + (model?.groupMemberList ?? []) + .whereType() + .toList(); + + return TencentUtils.checkString(keyword) == null + ? memberList + : memberList.where((e) { + final userID = e.userID; + final nickName = e.nickName ?? ""; + final friendRemark = e.friendRemark ?? ""; + return userID.contains(keyword!) || + nickName.contains(keyword) || + friendRemark.contains(keyword); + }).toList(); + } } diff --git a/lib/ui/utils/permission.dart b/lib/ui/utils/permission.dart index 675d05b..e28d6e1 100644 --- a/lib/ui/utils/permission.dart +++ b/lib/ui/utils/permission.dart @@ -278,7 +278,7 @@ class Permissions { ); }); _entry = entry; - Overlay.of(context)?.insert(entry); + Overlay.of(context).insert(entry); } static Future showPermissionConfirmDialog(BuildContext context, value, diff --git a/lib/ui/utils/screen_shot.dart b/lib/ui/utils/screen_shot.dart index 00e7894..a6d2d83 100644 --- a/lib/ui/utils/screen_shot.dart +++ b/lib/ui/utils/screen_shot.dart @@ -101,4 +101,5 @@ class ScreenshotHelper { })); return completer.future; } + } diff --git a/lib/ui/utils/screen_utils.dart b/lib/ui/utils/screen_utils.dart index 73b839c..5416c25 100644 --- a/lib/ui/utils/screen_utils.dart +++ b/lib/ui/utils/screen_utils.dart @@ -1,6 +1,9 @@ // ignore_for_file: constant_identifier_names +import 'dart:math'; + import 'package:flutter/cupertino.dart'; +import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; enum DeviceType { Desktop, Mobile } @@ -12,29 +15,48 @@ class FormFactor { class TUIKitScreenUtils { static DeviceType? deviceType; + /// Although specifying the `BuildContext` is optional, providing it can prevent layout issues when this widget renders immediately after the app launch. + /// If this widget needs to be used at the moment the app launches, it's recommended to provide the `BuildContext` here. static DeviceType getFormFactor([BuildContext? context]) { if (deviceType != null) return deviceType!; - if(context != null){ - double deviceWidth = MediaQuery.of(context).size.width; - double deviceHeight = MediaQuery.of(context).size.height; + if (PlatformUtils().isWeb) { + final win = WidgetsBinding.instance.platformDispatcher.views.first; + final size = win.physicalSize; + final screenWidth = size.width / win.devicePixelRatio; + final screenHeight = size.height / win.devicePixelRatio; - if (deviceWidth > FormFactor.desktop || deviceWidth > deviceHeight * 1.1) { - deviceType = DeviceType.Desktop; - } else if (deviceWidth > FormFactor.handset) { - deviceType = DeviceType.Mobile; - } + final diagonalInInches = + sqrt(pow(screenWidth, 2) + pow(screenHeight, 2)) / 96.0; + + deviceType = diagonalInInches < 8.0 ? DeviceType.Mobile : DeviceType.Desktop; return deviceType ?? DeviceType.Mobile; }else{ - return DeviceType.Mobile; + if(context != null){ + double deviceWidth = MediaQuery.of(context).size.width; + double deviceHeight = MediaQuery.of(context).size.height; + + if (deviceWidth > FormFactor.desktop || deviceWidth > deviceHeight * 1.1) { + deviceType = DeviceType.Desktop; + } else if (deviceWidth > FormFactor.handset) { + deviceType = DeviceType.Mobile; + } + return deviceType ?? DeviceType.Mobile; + }else{ + return DeviceType.Mobile; + } } } static Widget getDeviceWidget({ + /// Although specifying the `BuildContext` is optional, providing it can prevent layout issues when this widget renders immediately after the app launch. + /// If this widget needs to be used at the moment the app launches, it's recommended to provide the `BuildContext` here. + BuildContext? context, required Widget defaultWidget, Widget? desktopWidget, Widget? mobileWidget, }) { + deviceType ??= getFormFactor(context); if (deviceType == DeviceType.Desktop) return desktopWidget ?? defaultWidget; return mobileWidget ?? defaultWidget; } diff --git a/lib/ui/views/TIMUIKitAddFriend/tim_uikit_add_friend.dart b/lib/ui/views/TIMUIKitAddFriend/tim_uikit_add_friend.dart index aef87b5..90006ed 100644 --- a/lib/ui/views/TIMUIKitAddFriend/tim_uikit_add_friend.dart +++ b/lib/ui/views/TIMUIKitAddFriend/tim_uikit_add_friend.dart @@ -24,6 +24,7 @@ class TIMUIKitAddFriend extends StatefulWidget { /// The life cycle hooks for adding friends and contact business logic final AddFriendLifeCycle? lifeCycle; + /// The callback function to close the widget upon completion by the parent component. final VoidCallback? closeFunc; const TIMUIKitAddFriend( diff --git a/lib/ui/views/TIMUIKitAddFriend/tim_uikit_send_application.dart b/lib/ui/views/TIMUIKitAddFriend/tim_uikit_send_application.dart index 6b0515b..6d71fba 100644 --- a/lib/ui/views/TIMUIKitAddFriend/tim_uikit_send_application.dart +++ b/lib/ui/views/TIMUIKitAddFriend/tim_uikit_send_application.dart @@ -55,7 +55,7 @@ class _SendApplicationState extends TIMUIKitState { ""; final option2 = widget.friendInfo.selfSignature ?? ""; - Widget sendApplicationBody(){ + Widget sendApplicationBody() { return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -79,7 +79,7 @@ class _SendApplicationState extends TIMUIKitState { Text( showName, style: - TextStyle(color: theme.darkTextColor, fontSize: 18), + TextStyle(color: theme.darkTextColor, fontSize: 18), ), const SizedBox( height: 4, @@ -87,17 +87,18 @@ class _SendApplicationState extends TIMUIKitState { Text( "ID: $userID", style: - TextStyle(fontSize: 13, color: theme.weakTextColor), + TextStyle(fontSize: 13, color: theme.weakTextColor), ), const SizedBox( height: 4, ), - if(TencentUtils.checkString(option2) != null)Text( - TIM_t_para("个性签名: {{option2}}", "个性签名: $option2")( - option2: option2), - style: - TextStyle(fontSize: 13, color: theme.weakTextColor), - ), + if (TencentUtils.checkString(option2) != null) + Text( + TIM_t_para("个性签名: {{option2}}", "个性签名: $option2")( + option2: option2), + style: TextStyle( + fontSize: 13, color: theme.weakTextColor), + ), ], ) ], @@ -168,19 +169,19 @@ class _SendApplicationState extends TIMUIKitState { Container( color: theme.white, padding: - const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( TIM_t("分组"), style: - TextStyle(color: theme.darkTextColor, fontSize: 16), + TextStyle(color: theme.darkTextColor, fontSize: 16), ), Text( TIM_t("我的好友"), style: - TextStyle(color: theme.darkTextColor, fontSize: 16), + TextStyle(color: theme.darkTextColor, fontSize: 16), ) ], ), @@ -197,7 +198,7 @@ class _SendApplicationState extends TIMUIKitState { if (widget.lifeCycle?.shouldAddFriend != null && await widget.lifeCycle!.shouldAddFriend(userID, remark, - friendGroup, addWording, context) == + friendGroup, addWording, context) == false) { return; } @@ -234,25 +235,25 @@ class _SendApplicationState extends TIMUIKitState { } return TUIKitScreenUtils.getDeviceWidget( - desktopWidget: Container( - padding: const EdgeInsets.only(top: 10), - color: theme.weakBackgroundColor, - child: sendApplicationBody(), - ), + context: context, + desktopWidget: Container( + padding: const EdgeInsets.only(top: 10), + color: theme.weakBackgroundColor, + child: sendApplicationBody(), + ), defaultWidget: Scaffold( - appBar: AppBar( - title: Text( - TIM_t("添加好友"), - style: TextStyle(color: theme.appbarTextColor, fontSize: 17), - ), - shadowColor: theme.white, - backgroundColor: theme.appbarBgColor ?? - theme.primaryColor, - iconTheme: IconThemeData( - color: theme.appbarTextColor, - ), - ), - body: sendApplicationBody(), - )); + appBar: AppBar( + title: Text( + TIM_t("添加好友"), + style: TextStyle(color: theme.appbarTextColor, fontSize: 17), + ), + shadowColor: theme.white, + backgroundColor: theme.appbarBgColor ?? theme.primaryColor, + iconTheme: IconThemeData( + color: theme.appbarTextColor, + ), + ), + body: sendApplicationBody(), + )); } } diff --git a/lib/ui/views/TIMUIKitAddGroup/tim_uikit_send_application.dart b/lib/ui/views/TIMUIKitAddGroup/tim_uikit_send_application.dart index 1c64605..870e29b 100644 --- a/lib/ui/views/TIMUIKitAddGroup/tim_uikit_send_application.dart +++ b/lib/ui/views/TIMUIKitAddGroup/tim_uikit_send_application.dart @@ -13,6 +13,7 @@ import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; class SendJoinGroupApplication extends StatefulWidget { final V2TimGroupInfo groupInfo; final AddGroupLifeCycle? lifeCycle; + const SendJoinGroupApplication( {Key? key, required this.groupInfo, this.lifeCycle}) : super(key: key); @@ -76,7 +77,7 @@ class _SendJoinGroupApplicationState final showName = widget.groupInfo.groupName ?? groupID; final option1 = _getGroupType(widget.groupInfo.groupType); - Widget sendGroupApplicationBody(){ + Widget sendGroupApplicationBody() { return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -100,7 +101,7 @@ class _SendJoinGroupApplicationState Text( showName, style: - TextStyle(color: theme.darkTextColor, fontSize: 18), + TextStyle(color: theme.darkTextColor, fontSize: 18), ), const SizedBox( height: 4, @@ -108,7 +109,7 @@ class _SendJoinGroupApplicationState Text( "ID: $groupID", style: - TextStyle(fontSize: 13, color: theme.weakTextColor), + TextStyle(fontSize: 13, color: theme.weakTextColor), ), const SizedBox( height: 4, @@ -117,7 +118,7 @@ class _SendJoinGroupApplicationState TIM_t_para("群类型: {{option1}}", "群类型: $option1")( option1: option1), style: - TextStyle(fontSize: 12, color: theme.weakTextColor), + TextStyle(fontSize: 12, color: theme.weakTextColor), ), ], ) @@ -168,23 +169,22 @@ class _SendJoinGroupApplicationState ); } - return TUIKitScreenUtils.getDeviceWidget( - desktopWidget: sendGroupApplicationBody(), + context: context, + desktopWidget: sendGroupApplicationBody(), defaultWidget: Scaffold( - appBar: AppBar( - title: Text( - TIM_t("进群申请"), - style: TextStyle(color: theme.appbarTextColor, fontSize: 17), - ), - shadowColor: theme.white, - backgroundColor: theme.appbarBgColor ?? - theme.primaryColor, - iconTheme: IconThemeData( - color: theme.appbarTextColor, - ), - ), - body: sendGroupApplicationBody(), - )); + appBar: AppBar( + title: Text( + TIM_t("进群申请"), + style: TextStyle(color: theme.appbarTextColor, fontSize: 17), + ), + shadowColor: theme.white, + backgroundColor: theme.appbarBgColor ?? theme.primaryColor, + iconTheme: IconThemeData( + color: theme.appbarTextColor, + ), + ), + body: sendGroupApplicationBody(), + )); } } diff --git a/lib/ui/views/TIMUIKitBlackList/tim_uikit_black_list.dart b/lib/ui/views/TIMUIKitBlackList/tim_uikit_black_list.dart index 8c21604..4b9e4f5 100644 --- a/lib/ui/views/TIMUIKitBlackList/tim_uikit_black_list.dart +++ b/lib/ui/views/TIMUIKitBlackList/tim_uikit_black_list.dart @@ -109,6 +109,7 @@ class _TIMUIKitBlackListState extends TIMUIKitState { } return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: itemWidget(), defaultWidget: Slidable( endActionPane: ActionPane(motion: const DrawerMotion(), children: [ 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 6383cab..2410199 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 @@ -76,38 +76,38 @@ class MessageHoverControlItem { } class MessageItemBuilder { - /// text message builder + /// text message builder, returns null means using default widget. final MessageItemContent? textMessageItemBuilder; - /// text message builder for reply message + /// text message builder for reply message, returns null means using default widget. final MessageItemContent? textReplyMessageItemBuilder; - /// custom message builder + /// custom message builder, returns null means using default widget. final MessageItemContent? customMessageItemBuilder; - /// image message builder + /// image message builder, returns null means using default widget. final MessageItemContent? imageMessageItemBuilder; - /// sound message builder + /// sound message builder, returns null means using default widget. final MessageItemContent? soundMessageItemBuilder; - /// video message builder + /// video message builder, returns null means using default widget. final MessageItemContent? videoMessageItemBuilder; - /// file message builder + /// file message builder, returns null means using default widget. final MessageItemContent? fileMessageItemBuilder; /// location message (LBS) item builder; /// recommend to use our LBS plug-in: https://pub.dev/packages/tim_ui_kit_lbs_plugin final MessageItemContent? locationMessageItemBuilder; - /// face message, like emoji, message builder + /// face message, like emoji, message builder, returns null means using default widget. final MessageItemContent? faceMessageItemBuilder; - /// group tips message builder + /// group tips message builder, returns null means using default widget. final MessageItemContent? groupTipsMessageItemBuilder; - /// merger message builder + /// merger message builder, returns null means using default widget. final MessageItemContent? mergerMessageItemBuilder; /// The builder for the whole message line, expect for those message type without avatar and nickname. @@ -148,15 +148,32 @@ class MessageToolTipItem { } class ToolTipsConfig { + /// Whether to show the reply to a message option. final bool showReplyMessage; + + /// Whether to show the multiple-choice option for messages. final bool showMultipleChoiceMessage; + + /// Whether to show the option to delete a message. final bool showDeleteMessage; + + /// Whether to show the option to recall a message. final bool showRecallMessage; + + /// Whether to show the option to copy a message. final bool showCopyMessage; + + /// Whether to show the option to forward a message. final bool showForwardMessage; + + /// Whether to show the option to translate a text message. This module is not available by default. Please contact your Tencent Cloud sales representative or customer service team to enable this feature. final bool showTranslation; + + /// A builder for additional custom items. We recommend using `additionalMessageToolTips` instead of this field since version 2.0, as you only need to provide the data rather than the whole widget. This makes usage easier and you don't need to worry about the UI display. final Widget? Function(V2TimMessage message, Function() closeTooltip, [Key? key, BuildContext? context])? additionalItemBuilder; + + /// A list of additional message tooltip menu items, provided with the data only. We recommend using this field instead of the previous `additionalItemBuilder`. List Function( V2TimMessage message, Function() closeTooltip)? additionalMessageToolTips; @@ -169,8 +186,9 @@ class ToolTipsConfig { this.showCopyMessage = true, this.showForwardMessage = true, this.additionalMessageToolTips, - @Deprecated("Please use `additionalMessageToolTips` instead. You are now only expected to specify the data, rather than providing a whole widget. This makes usage easier, as you no longer need to worry about the UI display.") - this.additionalItemBuilder}); + @Deprecated( + "Please use `additionalMessageToolTips` instead. You are now only expected to specify the data, rather than providing a whole widget. This makes usage easier, as you no longer need to worry about the UI display.") + this.additionalItemBuilder}); } class TIMUIKitHistoryMessageListItem extends StatefulWidget { @@ -181,6 +199,10 @@ class TIMUIKitHistoryMessageListItem extends StatefulWidget { final void Function(String userID, TapDownDetails tapDetails)? onTapForOthersPortrait; + /// secondary tap remote user avatar callback function + final void Function(String userID, TapDownDetails tapDetails)? + onSecondaryTapForOthersPortrait; + /// the function use for reply message, when click replied message can scroll to it. final Function? onScrollToIndex; @@ -262,8 +284,9 @@ class TIMUIKitHistoryMessageListItem extends StatefulWidget { const TIMUIKitHistoryMessageListItem( {Key? key, required this.message, - @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, + @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.onScrollToIndex, this.onScrollToIndexBegin, this.onTapForOthersPortrait, @@ -287,7 +310,8 @@ class TIMUIKitHistoryMessageListItem extends StatefulWidget { this.bottomRowBuilder, this.isUseDefaultEmoji = false, this.customEmojiStickerList = const [], - this.textFieldController}) + this.textFieldController, + this.onSecondaryTapForOthersPortrait}) : super(key: key); @override @@ -386,192 +410,206 @@ class _TIMUIKItHistoryMessageListItemState switch (msgType) { case MessageElemType.V2TIM_ELEM_TYPE_CUSTOM: - if (messageItemBuilder?.customMessageItemBuilder != null) { - return messageItemBuilder!.customMessageItemBuilder!( - messageItem, - isShowJump, - () => model.jumpMsgID = "", - )!; - } - return TIMUIKitCustomElem( - message: messageItem, - customElem: messageItem.customElem, - isFromSelf: isFromSelf, - messageBackgroundColor: widget.themeData?.messageBackgroundColor, - messageBorderRadius: widget.themeData?.messageBorderRadius, - messageFontStyle: widget.themeData?.messageTextStyle, - textPadding: widget.textPadding, - isShowMessageReaction: widget.isUseMessageReaction, - ); + final customWidget = + messageItemBuilder?.customMessageItemBuilder != null + ? messageItemBuilder!.customMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? + TIMUIKitCustomElem( + message: messageItem, + customElem: messageItem.customElem, + isFromSelf: isFromSelf, + messageBackgroundColor: widget.themeData?.messageBackgroundColor, + messageBorderRadius: widget.themeData?.messageBorderRadius, + messageFontStyle: widget.themeData?.messageTextStyle, + textPadding: widget.textPadding, + isShowMessageReaction: widget.isUseMessageReaction, + ); case MessageElemType.V2TIM_ELEM_TYPE_SOUND: - if (messageItemBuilder?.soundMessageItemBuilder != null) { - return messageItemBuilder!.soundMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return TIMUIKitSoundElem( - chatModel: model, - message: messageItem, - soundElem: messageItem.soundElem!, - msgID: messageItem.msgID ?? "", - isFromSelf: messageItem.isSelf ?? true, - clearJump: clearJump, - isShowJump: isShowJump, - localCustomInt: messageItem.localCustomInt, - borderRadius: widget.themeData?.messageBorderRadius, - fontStyle: widget.themeData?.messageTextStyle, - backgroundColor: widget.themeData?.messageBackgroundColor, - textPadding: widget.textPadding, - isShowMessageReaction: widget.isUseMessageReaction, - ); + final customWidget = messageItemBuilder?.soundMessageItemBuilder != null + ? messageItemBuilder!.soundMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? + TIMUIKitSoundElem( + chatModel: model, + message: messageItem, + soundElem: messageItem.soundElem!, + msgID: messageItem.msgID ?? "", + isFromSelf: messageItem.isSelf ?? true, + clearJump: clearJump, + isShowJump: isShowJump, + localCustomInt: messageItem.localCustomInt, + borderRadius: widget.themeData?.messageBorderRadius, + fontStyle: widget.themeData?.messageTextStyle, + backgroundColor: widget.themeData?.messageBackgroundColor, + textPadding: widget.textPadding, + isShowMessageReaction: widget.isUseMessageReaction, + ); case MessageElemType.V2TIM_ELEM_TYPE_TEXT: if (isReplyMessage(messageItem)) { - if (messageItemBuilder?.textReplyMessageItemBuilder != null) { - return messageItemBuilder!.textReplyMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return TIMUIKitReplyElem( - message: messageItem, - clearJump: clearJump, - isShowJump: isShowJump, - scrollToIndex: widget.onScrollToIndex ?? () {}, - borderRadius: widget.themeData?.messageBorderRadius, - fontStyle: widget.themeData?.messageTextStyle, - backgroundColor: widget.themeData?.messageBackgroundColor, - textPadding: widget.textPadding, - isUseDefaultEmoji: widget.isUseDefaultEmoji, - customEmojiStickerList: widget.customEmojiStickerList, - chatModel: model, - isShowMessageReaction: widget.isUseMessageReaction, - ); + final customWidget = + messageItemBuilder?.textReplyMessageItemBuilder != null + ? messageItemBuilder!.textReplyMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? + TIMUIKitReplyElem( + message: messageItem, + clearJump: clearJump, + isShowJump: isShowJump, + scrollToIndex: widget.onScrollToIndex ?? () {}, + borderRadius: widget.themeData?.messageBorderRadius, + fontStyle: widget.themeData?.messageTextStyle, + backgroundColor: widget.themeData?.messageBackgroundColor, + textPadding: widget.textPadding, + isUseDefaultEmoji: widget.isUseDefaultEmoji, + customEmojiStickerList: widget.customEmojiStickerList, + chatModel: model, + isShowMessageReaction: widget.isUseMessageReaction, + ); } - if (messageItemBuilder?.textMessageItemBuilder != null) { - return messageItemBuilder!.textMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return TIMUIKitTextElem( - chatModel: model, - message: messageItem, - isFromSelf: messageItem.isSelf ?? true, - clearJump: clearJump, - isShowJump: isShowJump, - borderRadius: widget.themeData?.messageBorderRadius, - fontStyle: widget.themeData?.messageTextStyle, - backgroundColor: widget.themeData?.messageBackgroundColor, - textPadding: widget.textPadding, - isShowMessageReaction: widget.isUseMessageReaction, - isUseDefaultEmoji: widget.isUseDefaultEmoji, - customEmojiStickerList: widget.customEmojiStickerList, - ); + final customWidget = messageItemBuilder?.textMessageItemBuilder != null + ? messageItemBuilder!.textMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? + TIMUIKitTextElem( + chatModel: model, + message: messageItem, + isFromSelf: messageItem.isSelf ?? true, + clearJump: clearJump, + isShowJump: isShowJump, + borderRadius: widget.themeData?.messageBorderRadius, + fontStyle: widget.themeData?.messageTextStyle, + backgroundColor: widget.themeData?.messageBackgroundColor, + textPadding: widget.textPadding, + isShowMessageReaction: widget.isUseMessageReaction, + isUseDefaultEmoji: widget.isUseDefaultEmoji, + customEmojiStickerList: widget.customEmojiStickerList, + ); case MessageElemType.V2TIM_ELEM_TYPE_FACE: - if (messageItemBuilder?.faceMessageItemBuilder != null) { - return messageItemBuilder!.faceMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return TIMUIKitFaceElem( - model: model, - path: messageItem.faceElem!.data ?? "", - clearJump: clearJump, - isShowJump: isShowJump, - message: messageItem, - isShowMessageReaction: widget.isUseMessageReaction, - ); + final customWidget = messageItemBuilder?.faceMessageItemBuilder != null + ? messageItemBuilder!.faceMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? + TIMUIKitFaceElem( + model: model, + path: messageItem.faceElem!.data ?? "", + clearJump: clearJump, + isShowJump: isShowJump, + message: messageItem, + isShowMessageReaction: widget.isUseMessageReaction, + ); case MessageElemType.V2TIM_ELEM_TYPE_FILE: - if (messageItemBuilder?.fileMessageItemBuilder != null) { - return messageItemBuilder!.fileMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return TIMUIKitFileElem( - chatModel: model, - message: messageItem, - messageID: messageItem.msgID, - fileElem: messageItem.fileElem, - isSelf: messageItem.isSelf ?? true, - clearJump: clearJump, - isShowJump: isShowJump, - isShowMessageReaction: widget.isUseMessageReaction, - ); + final customWidget = messageItemBuilder?.fileMessageItemBuilder != null + ? messageItemBuilder!.fileMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? + TIMUIKitFileElem( + chatModel: model, + message: messageItem, + messageID: messageItem.msgID, + fileElem: messageItem.fileElem, + isSelf: messageItem.isSelf ?? true, + clearJump: clearJump, + isShowJump: isShowJump, + isShowMessageReaction: widget.isUseMessageReaction, + ); case MessageElemType.V2TIM_ELEM_TYPE_GROUP_TIPS: - if (messageItemBuilder?.groupTipsMessageItemBuilder != null) { - return messageItemBuilder!.groupTipsMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return Text(TIM_t("[群系统消息]")); + final customWidget = + messageItemBuilder?.groupTipsMessageItemBuilder != null + ? messageItemBuilder!.groupTipsMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? Text(TIM_t("[群系统消息]")); case MessageElemType.V2TIM_ELEM_TYPE_IMAGE: - if (messageItemBuilder?.imageMessageItemBuilder != null) { - return messageItemBuilder!.imageMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return TIMUIKitImageElem( - clearJump: clearJump, - isShowJump: isShowJump, - chatModel: model, - message: messageItem, - isShowMessageReaction: widget.isUseMessageReaction, - key: Key("${messageItem.seq}_${messageItem.timestamp}"), - ); + final customWidget = messageItemBuilder?.imageMessageItemBuilder != null + ? messageItemBuilder!.imageMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? + TIMUIKitImageElem( + clearJump: clearJump, + isShowJump: isShowJump, + chatModel: model, + message: messageItem, + isShowMessageReaction: widget.isUseMessageReaction, + key: Key("${messageItem.seq}_${messageItem.timestamp}"), + ); case MessageElemType.V2TIM_ELEM_TYPE_VIDEO: - if (messageItemBuilder?.videoMessageItemBuilder != null) { - return messageItemBuilder!.videoMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return TIMUIKitVideoElem( - messageItem, - isShowJump: isShowJump, - chatModel: model, - clearJump: clearJump, - isShowMessageReaction: widget.isUseMessageReaction, - ); + final customWidget = messageItemBuilder?.videoMessageItemBuilder != null + ? messageItemBuilder!.videoMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? + TIMUIKitVideoElem( + messageItem, + isShowJump: isShowJump, + chatModel: model, + clearJump: clearJump, + isShowMessageReaction: widget.isUseMessageReaction, + ); case MessageElemType.V2TIM_ELEM_TYPE_LOCATION: - if (messageItemBuilder?.locationMessageItemBuilder != null) { - return messageItemBuilder!.locationMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return Text(TIM_t("[位置]")); + final customWidget = + messageItemBuilder?.locationMessageItemBuilder != null + ? messageItemBuilder!.locationMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? Text(TIM_t("[位置]")); case MessageElemType.V2TIM_ELEM_TYPE_MERGER: - if (messageItemBuilder?.mergerMessageItemBuilder != null) { - return messageItemBuilder!.mergerMessageItemBuilder!( - messageItem, - isShowJump, - clearJump, - )!; - } - return TIMUIKitMergerElem( - messageItemBuilder: messageItemBuilder, - model: model, - isShowJump: isShowJump, - clearJump: clearJump, - message: messageItem, - isShowMessageReaction: widget.isUseMessageReaction, - mergerElem: messageItem.mergerElem!, - messageID: messageItem.msgID ?? "", - isSelf: messageItem.isSelf ?? true); + final customWidget = + messageItemBuilder?.mergerMessageItemBuilder != null + ? messageItemBuilder!.mergerMessageItemBuilder!( + messageItem, + isShowJump, + () => model.jumpMsgID = "", + ) + : null; + return customWidget ?? + TIMUIKitMergerElem( + messageItemBuilder: messageItemBuilder, + model: model, + isShowJump: isShowJump, + clearJump: clearJump, + message: messageItem, + isShowMessageReaction: widget.isUseMessageReaction, + mergerElem: messageItem.mergerElem!, + messageID: messageItem.msgID ?? "", + isSelf: messageItem.isSelf ?? true); default: return Text(TIM_t("[未知消息]")); } @@ -941,12 +979,18 @@ class _TIMUIKItHistoryMessageListItemState ), onClick: (_) { model.repliedMessage = widget.message; - if (widget.allowAtUserWhenReply && - widget.onLongPressForOthersHeadPortrait != null && - !(widget.message.isSelf ?? true)) { - widget.onLongPressForOthersHeadPortrait!( - widget.message.sender, widget.message.nickName); - } + final isSelf = widget.message.isSelf ?? true; + final isGroup = + TencentUtils.checkString(widget.message.groupID) != null; + final isAtWhenReply = !isSelf && + isGroup && + widget.allowAtUserWhenReply && + widget.onLongPressForOthersHeadPortrait != null; + + /// If replying to a self message, do not add a at tag, only requestFocus. + widget.onLongPressForOthersHeadPortrait!( + !isAtWhenReply ? null : widget.message.sender, + !isAtWhenReply ? null : widget.message.nickName); }, ), if ((widget.toolTipsConfig?.showForwardMessage ?? true) && @@ -1009,18 +1053,28 @@ class _TIMUIKItHistoryMessageListItemState context); } - Widget renderHoverTipAndReadStatus(TUIChatSeparateViewModel model, - bool isSelf, V2TimMessage message, bool isPeerRead, TUITheme theme) { + Widget renderHoverTipAndReadStatus( + TUIChatSeparateViewModel model, + bool isSelf, + V2TimMessage message, + bool isPeerRead, + TUITheme theme, + bool isDownloadWaiting) { final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; - final wideHoverTipList = getMessageHoverControlBar(model, theme); - final lastItemName = wideHoverTipList.last.name; + final wideHoverTipList = model.chatConfig.isUseMessageHoverBarOnDesktop + ? getMessageHoverControlBar(model, theme) + : []; + final lastItemName = + wideHoverTipList.isNotEmpty ? wideHoverTipList.last.name : ""; return Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, children: [ - if (isDesktopScreen && isShowWideToolTip) + if (isDesktopScreen && + isShowWideToolTip && + !((widget.message.elemType == 6 && isDownloadWaiting))) Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), @@ -1188,7 +1242,8 @@ class _TIMUIKItHistoryMessageListItemState children: [ if (model.isMultiSelect) Container( - margin: EdgeInsets.only(right: 12, top: 10, left: isSelf ? 16 : 0), + margin: + EdgeInsets.only(right: 12, top: 10, left: isSelf ? 16 : 0), child: CheckBoxButton( isChecked: model.multiSelectedMessageList.contains(message), onChanged: (value) { @@ -1264,6 +1319,26 @@ class _TIMUIKItHistoryMessageListItemState message.sender ?? "", TapDownDetails()); } }, + onSecondaryTap: isDesktopScreen + ? null + : () { + if (widget.onSecondaryTapForOthersPortrait != + null && + widget.allowAvatarTap) { + widget.onSecondaryTapForOthersPortrait!( + message.sender ?? "", TapDownDetails()); + } + }, + onSecondaryTapDown: isDesktopScreen + ? (details) { + if (widget.onSecondaryTapForOthersPortrait != + null && + widget.allowAvatarTap) { + widget.onSecondaryTapForOthersPortrait!( + message.sender ?? "", details); + } + } + : null, child: widget.userAvatarBuilder != null ? widget.userAvatarBuilder!(context, message) : Container( @@ -1282,6 +1357,16 @@ class _TIMUIKItHistoryMessageListItemState ), ), ), + if (isSelf && + widget.message.elemType == 6 && + isDownloadWaiting) + Container( + margin: const EdgeInsets.only(top: 2), + child: LoadingAnimationWidget.threeArchedCircle( + color: theme.weakTextColor ?? Colors.grey, + size: 20, + ), + ), Container( margin: widget.showAvatar ? (isSelf @@ -1319,8 +1404,13 @@ class _TIMUIKItHistoryMessageListItemState crossAxisAlignment: CrossAxisAlignment.end, children: [ if (isSelf) - renderHoverTipAndReadStatus(model, isSelf, - message, isPeerRead, theme), + renderHoverTipAndReadStatus( + model, + isSelf, + message, + isPeerRead, + theme, + isDownloadWaiting), Container( constraints: BoxConstraints( maxWidth: constraints.maxWidth * 0.77, @@ -1406,8 +1496,13 @@ class _TIMUIKItHistoryMessageListItemState child: Icon(Icons.circle, color: theme.cautionColor, size: 10)), if (!isSelf) - renderHoverTipAndReadStatus(model, isSelf, - message, isPeerRead, theme), + renderHoverTipAndReadStatus( + model, + isSelf, + message, + isPeerRead, + theme, + isDownloadWaiting), ], ), if (widget.bottomRowBuilder != null) @@ -1415,7 +1510,9 @@ class _TIMUIKItHistoryMessageListItemState ], ), ), - if (widget.message.elemType == 6 && isDownloadWaiting) + if (!isSelf && + widget.message.elemType == 6 && + isDownloadWaiting) Container( margin: const EdgeInsets.only(top: 24, left: 6), child: LoadingAnimationWidget.threeArchedCircle( 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 d7f6016..48f0744 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 @@ -85,7 +85,10 @@ class TIMUIKitMessageTooltipState } hasFile() { - if (PlatformUtils().isMobile || widget.message.fileElem == null) { + if (PlatformUtils().isMobile || + (widget.message.fileElem == null && + widget.message.imageElem == null && + widget.message.videoElem == null)) { isShowOpenFile = false; return; } @@ -94,26 +97,44 @@ class TIMUIKitMessageTooltipState return; } if (PlatformUtils().isDesktop) { - if (globalModal.getMessageProgress(widget.message.msgID) == 100) { - String savePath = - TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? - globalModal.getFileMessageLocation(widget.message.msgID); + 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 ?? ''; File f = File(savePath); if (f.existsSync() && widget.message.msgID != null) { filePath = savePath; + globalModal.setMessageProgress(widget.message.msgID!, 100); + isShowOpenFile = true; + return; + } + } else if (widget.message.imageElem != null) { + if (TencentUtils.checkString( + widget.message.imageElem!.imageList![0]!.localUrl) != + null && + File(widget.message.imageElem!.imageList![0]!.localUrl!) + .existsSync()) { + isShowOpenFile = true; + return; + } + } else if (widget.message.videoElem != null) { + if (TencentUtils.checkString(widget.message.videoElem!.localVideoUrl) != + null && + File(widget.message.videoElem!.localVideoUrl!).existsSync()) { isShowOpenFile = true; return; } - isShowOpenFile = false; - return; - } - String savePath = widget.message.fileElem!.localUrl ?? ''; - File f = File(savePath); - if (f.existsSync() && widget.message.msgID != null) { - filePath = savePath; - globalModal.setMessageProgress(widget.message.msgID!, 100); - isShowOpenFile = true; - return; } } isShowOpenFile = false; @@ -198,11 +219,6 @@ class TIMUIKitMessageTooltipState id: "forwardMessage", iconImageAsset: "images/forward_message.png", onClick: () => _onTap("forwardMessage", model)), - MessageToolTipItem( - label: TIM_t("多选"), - id: "multiSelect", - iconImageAsset: "images/multi_message.png", - onClick: () => _onTap("multiSelect", model)), if (shouldShowReplyAction) MessageToolTipItem( label: TIM_t(model.chatConfig.isAtWhenReply ? "回复" : "引用"), @@ -210,15 +226,20 @@ class TIMUIKitMessageTooltipState iconImageAsset: "images/reply_message.png", onClick: () => _onTap("replyMessage", model)), MessageToolTipItem( - label: TIM_t("删除"), - id: "delete", - iconImageAsset: "images/delete_message.png", - onClick: () => _onTap("delete", model)), + label: TIM_t("多选"), + id: "multiSelect", + iconImageAsset: "images/multi_message.png", + onClick: () => _onTap("multiSelect", model)), MessageToolTipItem( label: TIM_t("翻译"), id: "translate", iconImageAsset: "images/translate.png", onClick: () => _onTap("translate", model)), + MessageToolTipItem( + label: TIM_t("删除"), + id: "delete", + iconImageAsset: "images/delete_message.png", + onClick: () => _onTap("delete", model)), if (shouldShowRevokeAction) MessageToolTipItem( label: TIM_t("撤回"), @@ -226,6 +247,7 @@ class TIMUIKitMessageTooltipState iconImageAsset: "images/revoke_message.png", onClick: () => _onTap("revoke", model)), ]; + final defaultTipsIds = defaultTipsList.map((e) => e.id); List defaultFormattedTipsList = defaultTipsList; if (tooltipsConfig != null) { defaultFormattedTipsList = defaultTipsList.where((element) { @@ -235,10 +257,14 @@ class TIMUIKitMessageTooltipState widget.message.elemType == MessageElemType.V2TIM_ELEM_TYPE_TEXT; } if (type == "forwardMessage") { - return tooltipsConfig.showForwardMessage && !isDesktopScreen; + return tooltipsConfig.showForwardMessage && + !(isDesktopScreen && + widget.model.chatConfig.isUseMessageHoverBarOnDesktop); } if (type == "replyMessage") { - return tooltipsConfig.showReplyMessage && !isDesktopScreen; + return tooltipsConfig.showReplyMessage && + !(isDesktopScreen && + widget.model.chatConfig.isUseMessageHoverBarOnDesktop); } if (type == "delete") { return (!PlatformUtils().isWeb) && tooltipsConfig.showDeleteMessage; @@ -286,7 +312,9 @@ class TIMUIKitMessageTooltipState children: [ Image.asset( item.iconImageAsset, - package: 'tencent_cloud_chat_uikit', + package: defaultTipsIds.contains(item.id) + ? 'tencent_cloud_chat_uikit' + : null, width: 20, height: 20, ), @@ -353,37 +381,53 @@ class TIMUIKitMessageTooltipState return widgetList; } + _onOpenDesktop(String path) { + if (PlatformUtils().isDesktop) { + OpenFile.open(path); + } else { + launchUrl( + Uri.parse(path), + mode: LaunchMode.externalApplication, + ); + } + } + _onTap(String operation, TUIChatSeparateViewModel model) async { final messageItem = widget.message; final msgID = messageItem.msgID as String; switch (operation) { case "open": - if (PlatformUtils().isDesktop) { - final String savePath = - TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? - globalModal.getFileMessageLocation(widget.message.msgID); - launchUrl(Uri.file(savePath)); - } else { - if (PlatformUtils().isWindows) { - OpenFile.open(widget.message.fileElem?.path ?? ""); - } else { - launchUrl( - Uri.parse(widget.message.fileElem?.path ?? ""), - mode: LaunchMode.externalApplication, - ); - } + if (widget.message.fileElem != null) { + _onOpenDesktop(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 ?? + ""); + } else if (widget.message.videoElem != null) { + _onOpenDesktop(widget.message.videoElem!.localVideoUrl ?? + widget.message.videoElem?.videoPath ?? + ""); } break; case "finder": - final String savePath = - TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? - globalModal.getFileMessageLocation(widget.message.msgID); - final String fileDir = path.dirname(savePath); - if (PlatformUtils().isWindows) { - OpenFile.open(fileDir); - } else { - launchUrl(Uri.file(fileDir)); + String savePath = ""; + if (widget.message.fileElem != null) { + savePath = (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 ?? + ""); + } else if (widget.message.videoElem != null) { + savePath = (widget.message.videoElem!.localVideoUrl ?? + widget.message.videoElem?.videoPath ?? + ""); } + final String fileDir = path.dirname(savePath); + _onOpenDesktop(fileDir); break; case "delete": model.deleteMsg(msgID, webMessageInstance: messageItem.messageFromWeb); @@ -423,12 +467,18 @@ class TIMUIKitMessageTooltipState break; case "replyMessage": model.repliedMessage = widget.message; - if (widget.allowAtUserWhenReply && - widget.onLongPressForOthersHeadPortrait != null && - !(widget.message.isSelf ?? true)) { - widget.onLongPressForOthersHeadPortrait!( - widget.message.sender, widget.message.nickName); - } + final isSelf = widget.message.isSelf ?? true; + final isGroup = + TencentUtils.checkString(widget.message.groupID) != null; + final isAtWhenReply = !isSelf && + isGroup && + widget.allowAtUserWhenReply && + widget.onLongPressForOthersHeadPortrait != null; + + /// If replying to a self message, do not add a at tag, only requestFocus. + widget.onLongPressForOthersHeadPortrait!( + !isAtWhenReply ? null : widget.message.sender, + !isAtWhenReply ? null : widget.message.nickName); break; default: onTIMCallback(TIMCallback( diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_history_message_list_container.dart b/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_history_message_list_container.dart index 6ed275f..21fb73a 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_history_message_list_container.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_history_message_list_container.dart @@ -51,8 +51,13 @@ class TIMUIKitHistoryMessageListContainer extends StatefulWidget { /// conversation type final ConvType conversationType; + /// Avatar and name in message reaction tap callback. final void Function(String userID, TapDownDetails tapDetails)? onTapAvatar; + /// Avatar and name in message reaction secondary tap callback. + final void Function(String userID, TapDownDetails tapDetails)? + onSecondaryTapAvatar; + @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") final bool showNickName; @@ -85,8 +90,9 @@ class TIMUIKitHistoryMessageListContainer extends StatefulWidget { this.extraTipsActionItemBuilder, this.isAllowScroll = true, 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 = true, + @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 = true, this.initFindingMsg, this.mainHistoryListConfig, this.toolTipsConfig, @@ -94,6 +100,7 @@ class TIMUIKitHistoryMessageListContainer extends StatefulWidget { this.customEmojiStickerList = const [], this.textFieldController, required this.conversation, + this.onSecondaryTapAvatar, }) : super(key: key); @override @@ -169,6 +176,7 @@ class _TIMUIKitHistoryMessageListContainerState widget.extraTipsActionItemBuilder), message: message!, showAvatar: chatConfig.isShowAvatar, + onSecondaryTapForOthersPortrait: widget.onSecondaryTapAvatar, onTapForOthersPortrait: widget.onTapAvatar, messageItemBuilder: widget.messageItemBuilder, onLongPressForOthersHeadPortrait: diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar.dart index 396a60b..0588ea3 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar.dart @@ -80,9 +80,8 @@ class _TIMUIKitAppBarState extends TIMUIKitState { changedInfo.userProfile?.userID) ?? ""; } - // ignore: empty_catches - } catch (e) { - } + // ignore: empty_catches + } catch (e) {} }, ); if (_friendshipListener != null) { @@ -103,9 +102,8 @@ class _TIMUIKitAppBarState extends TIMUIKitState { setState(() {}); } } - // ignore: empty_catches - } catch (e) { - } + // ignore: empty_catches + } catch (e) {} }, ); if (_groupListener != null) { @@ -161,9 +159,8 @@ class _TIMUIKitAppBarState extends TIMUIKitState { ""; }); } - // ignore: empty_catches - } catch (e) { - } + // ignore: empty_catches + } catch (e) {} } @override @@ -193,7 +190,8 @@ class _TIMUIKitAppBarState extends TIMUIKitState { titleTextStyle: setAppbar?.titleTextStyle, toolbarOpacity: setAppbar?.toolbarOpacity ?? 1.0, toolbarTextStyle: setAppbar?.toolbarTextStyle, - textTheme: setAppbar?.textTheme, + + // textTheme: setAppbar?.textTheme, iconTheme: setAppbar?.iconTheme ?? const IconThemeData( color: Colors.white, @@ -201,10 +199,8 @@ class _TIMUIKitAppBarState extends TIMUIKitState { title: TIMUIKitAppBarTitle( title: setAppbar?.title, onClick: widget.onClickTitle, - textStyle: setAppbar?.textTheme?.titleMedium ?? - TextStyle( - color: theme.appbarTextColor ?? hexToColor("010000"), - fontSize: 16), + textStyle: TextStyle( + color: theme.appbarTextColor ?? hexToColor("010000"), fontSize: 16), conversationShowName: _conversationShowName, showC2cMessageEditStatus: widget.showC2cMessageEditStatus, fromUser: widget.conversationID, @@ -222,12 +218,10 @@ class _TIMUIKitAppBarState extends TIMUIKitState { }, child: Text( TIM_t('取消'), - style: setAppbar?.textTheme?.titleMedium ?? - TextStyle( - color: - theme.appbarTextColor ?? hexToColor("010000"), - fontSize: 16, - ), + style: TextStyle( + color: theme.appbarTextColor ?? hexToColor("010000"), + fontSize: 16, + ), ), ) : setAppbar?.leading ?? @@ -240,10 +234,7 @@ class _TIMUIKitAppBarState extends TIMUIKitState { constraints: const BoxConstraints(), icon: Icon( Icons.arrow_back_ios, - color: setAppbar - ?.textTheme?.titleMedium?.color ?? - theme.appbarTextColor ?? - hexToColor("010000"), + color: hexToColor("010000"), size: 17, ), onPressed: () async { 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 f121465..dd27861 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 @@ -8,18 +8,18 @@ import 'package:flutter/material.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'; -import 'package:provider/provider.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart'; 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; 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/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_file_icon.dart'; import 'package:tencent_cloud_chat_uikit/ui/widgets/textSize.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:http/http.dart' as http; class TIMUIKitFileElem extends StatefulWidget { final String? messageID; @@ -51,6 +51,16 @@ class _TIMUIKitFileElemState extends TIMUIKitState { String filePath = ""; bool isDownloading = false; final TUIChatGlobalModel model = serviceLocator(); + int downloadProgress = 0; + late V2TimAdvancedMsgListener advancedMsgListener; + + @override + void dispose() { + TencentImSDKPlugin.v2TIMManager + .getMessageManager() + .removeAdvancedMsgListener(listener: advancedMsgListener); + super.dispose(); + } @override void initState() { @@ -60,6 +70,32 @@ class _TIMUIKitFileElemState extends TIMUIKitState { hasFile(); }); } + advancedMsgListener = V2TimAdvancedMsgListener( + onMessageDownloadProgressCallback: + (V2TimMessageDownloadProgress messageProgress) async { + if (messageProgress.msgID == widget.message.msgID) { + if (messageProgress.isFinish) { + if(mounted){ + setState(() { + downloadProgress = 100; + }); + } + } else { + if(mounted){ + setState(() { + downloadProgress = (messageProgress.currentSize / + messageProgress.totalSize * + 100) + .ceil(); + }); + } + } + } + }, + ); + TencentImSDKPlugin.v2TIMManager + .getMessageManager() + .addAdvancedMsgListener(listener: advancedMsgListener); } Future getSavePath() async { @@ -75,12 +111,17 @@ class _TIMUIKitFileElemState extends TIMUIKitState { return true; } - if (model.getMessageProgress(widget.messageID) == 100) { - String savePath = TencentUtils.checkString(widget.message.fileElem!.localUrl) ?? - model.getFileMessageLocation(widget.messageID); + 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; @@ -89,6 +130,9 @@ class _TIMUIKitFileElemState extends TIMUIKitState { File f = File(savePath); if (f.existsSync() && widget.messageID != null) { filePath = savePath; + setState(() { + downloadProgress = 100; + }); model.setMessageProgress(widget.messageID!, 100); return true; } @@ -108,7 +152,7 @@ class _TIMUIKitFileElemState extends TIMUIKitState { } addUrlToWaitingPath() async { - if(widget.messageID !=null ){ + if (widget.messageID != null) { model.addWaitingList(widget.messageID!); print("add path success"); } @@ -127,7 +171,7 @@ class _TIMUIKitFileElemState extends TIMUIKitState { } downloadFile(TUITheme theme) async { - if(PlatformUtils().isMobile){ + if (PlatformUtils().isMobile) { if (PlatformUtils().isIOS) { if (!await Permissions.checkPermission( context, Permission.photosAddOnly.value, theme, false)) { @@ -136,12 +180,13 @@ class _TIMUIKitFileElemState extends TIMUIKitState { } else { final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; - if ((androidInfo.version.sdkInt ?? 0) >= 33) { + if ((androidInfo.version.sdkInt) >= 33) { } else { var storage = await Permissions.checkPermission( - context, Permission.storage.value, + context, + Permission.storage.value, ); - if(!storage){ + if (!storage) { return; } } @@ -151,7 +196,7 @@ class _TIMUIKitFileElemState extends TIMUIKitState { } tryOpenFile(context, theme) async { - if(PlatformUtils().isMobile){ + if (PlatformUtils().isMobile) { if (PlatformUtils().isIOS) { if (!await Permissions.checkPermission( context, Permission.photosAddOnly.value, theme!, false)) { @@ -160,12 +205,13 @@ class _TIMUIKitFileElemState extends TIMUIKitState { } else { final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; - if ((androidInfo.version.sdkInt ?? 0) >= 33) { + if ((androidInfo.version.sdkInt) >= 33) { } else { var storage = await Permissions.checkPermission( - context, Permission.storage.value, + context, + Permission.storage.value, ); - if(!storage){ + if (!storage) { return; } } @@ -173,19 +219,67 @@ class _TIMUIKitFileElemState extends TIMUIKitState { } try { - if(PlatformUtils().isDesktop && !PlatformUtils().isWindows){ + if (PlatformUtils().isDesktop && !PlatformUtils().isWindows) { launchUrl(Uri.file(filePath)); - }else{ + } else { OpenFile.open(filePath); } - // ignore: empty_catches + // ignore: empty_catches + } catch (e) {} + } + + void downloadWebFile(String fileUrl) async { + String fileName = Uri.parse(fileUrl).pathSegments.last; + try { + http.Response response = await http.get( + Uri.parse(fileUrl), + headers: {'Content-Type': 'application/x-www-form-urlencoded'}, + ); + + final html.AnchorElement downloadAnchor = + html.document.createElement('a') as html.AnchorElement; + + final html.Blob blob = html.Blob([response.bodyBytes]); + + downloadAnchor.href = html.Url.createObjectUrlFromBlob(blob); + downloadAnchor.download = widget.message.fileElem?.fileName ?? fileName; + + downloadAnchor.click(); } catch (e) { + html.AnchorElement( + href: widget.fileElem?.path ?? "", + ) + ..setAttribute( + "download", widget.message.fileElem?.fileName ?? fileName) + ..setAttribute("target", '_blank') + ..style.display = "none" + ..click(); } } @override Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { final theme = value.theme; + final received = downloadProgress; + final fileName = widget.fileElem!.fileName ?? ""; + final fileSize = widget.fileElem!.fileSize; + final borderRadius = widget.isSelf + ? const BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(2), + bottomLeft: Radius.circular(10), + bottomRight: Radius.circular(10)) + : const BorderRadius.only( + topLeft: Radius.circular(2), + topRight: Radius.circular(10), + bottomLeft: Radius.circular(10), + bottomRight: Radius.circular(10)); + String? fileFormat; + if (widget.fileElem?.fileName != null && + widget.fileElem!.fileName!.isNotEmpty) { + final String fileName = widget.fileElem!.fileName!; + fileFormat = fileName.split(".")[max(fileName.split(".").length - 1, 0)]; + } return TIMUIKitMessageReactionWrapper( chatModel: widget.chatModel, isShowJump: widget.isShowJump, @@ -193,135 +287,104 @@ class _TIMUIKitFileElemState extends TIMUIKitState { isFromSelf: widget.message.isSelf ?? true, isShowMessageReaction: widget.isShowMessageReaction ?? true, message: widget.message, - child: ChangeNotifierProvider.value( - value: model, - child: - Consumer(builder: (context, value, child) { - final received = value.getMessageProgress(widget.messageID); - final fileName = widget.fileElem!.fileName ?? ""; - final fileSize = widget.fileElem!.fileSize; - final borderRadius = widget.isSelf - ? const BorderRadius.only( - topLeft: Radius.circular(10), - topRight: Radius.circular(2), - bottomLeft: Radius.circular(10), - bottomRight: Radius.circular(10)) - : const BorderRadius.only( - topLeft: Radius.circular(2), - topRight: Radius.circular(10), - bottomLeft: Radius.circular(10), - bottomRight: Radius.circular(10)); - String? fileFormat; - if (widget.fileElem?.fileName != null && - widget.fileElem!.fileName!.isNotEmpty) { - final String fileName = widget.fileElem!.fileName!; - fileFormat = - fileName.split(".")[max(fileName.split(".").length - 1, 0)]; + 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; } - return InkWell( - onTap: () async { - if (PlatformUtils().isWeb) { - launchUrl( - Uri.parse(widget.fileElem?.path ?? ""), - mode: LaunchMode.externalApplication, - ); - 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(); - } - 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 (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, + ); + }, ), - ])), - ]), - )); - }))); + ), + 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, + ), + ])), + ]), + ))); } } 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 2b1eed1..5aef85c 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 @@ -56,6 +56,7 @@ class TIMUIKitImageElem extends StatefulWidget { } class _TIMUIKitImageElem extends TIMUIKitState { + final TUIChatGlobalModel globalModel = serviceLocator(); double? networkImagePositionRadio; // 加这个字段用于异步获取被安全打击后的兜底图的比例 final TUIChatGlobalModel model = serviceLocator(); final MessageService _messageService = serviceLocator(); @@ -140,7 +141,7 @@ class _TIMUIKitImageElem extends TIMUIKitState { final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; if (PlatformUtils().isMobile) { - if ((androidInfo.version.sdkInt ?? 0) >= 33) { + if ((androidInfo.version.sdkInt) >= 33) { final photos = await Permissions.checkPermission( context, Permission.photos.value, @@ -309,137 +310,6 @@ class _TIMUIKitImageElem extends TIMUIKitState { child: errorDisplay(context, theme), )); - Widget _renderLocalImage(String smallImage, dynamic heroTag, - double? positionRadio, TUITheme? theme, String? originImage) { - double? currentPositionRadio = positionRadio; - File imgF = File(smallImage); - - bool isExist = imgF.existsSync(); - if (!isExist) { - return errorDisplay(context, theme); - } - - Image image = Image.file(imgF); - - String showImage = (originImage != null && File(originImage).existsSync()) - ? originImage - : smallImage; - - image.image - .resolve(const ImageConfiguration()) - .addListener(ImageStreamListener((image, synchronousCall) { - if (image.image.width != 0 && image.image.height != 0) { - currentPositionRadio = image.image.width / image.image.height; - } - })); - final message = widget.message; - final preloadImage = model.preloadImageMap[ - message.seq! + message.timestamp.toString() + (message.msgID ?? "")]; - - final isDesktopScreen = - TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; - - return Stack( - alignment: AlignmentDirectional.topStart, - children: [ - if (!isDesktopScreen && currentPositionRadio != null) - AspectRatio( - aspectRatio: currentPositionRadio!, - child: Container( - decoration: const BoxDecoration(color: Colors.transparent), - ), - ), - getImage( - InkWell( - onTap: () { - if (PlatformUtils().isDesktop) { - if(PlatformUtils().isWindows){ - OpenFile.open(showImage); - } else{ - launchUrl(Uri.file(showImage)); - } - } else { - Navigator.of(context).push( - PageRouteBuilder( - opaque: false, // set to false - pageBuilder: (_, __, ___) => ImageScreen( - imageProvider: FileImage(File(showImage)), - heroTag: heroTag, - messageID: widget.message.msgID, - downloadFn: () async { - return await _saveImg(theme!); - }), - ), - ); - } - }, - 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, - ), - ), - )), - imageElem: null) - ], - ); - } - - @override - void initState() { - super.initState(); - if (!PlatformUtils().isWeb) { - if ((widget.message.msgID != null && widget.message.msgID != '') && - (widget.message.imageElem!.imageList![0]!.localUrl == null || - widget.message.imageElem!.imageList![0]!.localUrl!.isEmpty)) { - _messageService.downloadMessage( - msgID: widget.message.msgID!, - messageType: 3, - imageType: 0, - isSnapshot: false); - _messageService.downloadMessage( - msgID: widget.message.msgID!, - messageType: 3, - imageType: 1, - isSnapshot: false); - _messageService.downloadMessage( - msgID: widget.message.msgID!, - messageType: 3, - imageType: 2, - isSnapshot: false); - } - } - // 先暂时下掉用网络图片计算尺寸比例的feature,在没有找到准确的判断图片是否被打击前 - // setOnlineImageRatio(); - } - - void setOnlineImageRatio() { - if (networkImagePositionRadio == null) { - V2TimImage? smallImg = getImageFromList(V2TimImageTypesEnum.small); - V2TimImage? originalImg = getImageFromList(V2TimImageTypesEnum.original); - Image image = Image.network(smallImg?.url ?? originalImg?.url ?? ""); - - image.image - .resolve(const ImageConfiguration()) - .addListener(ImageStreamListener((ImageInfo info, bool _) { - if (info.image.width != 0 && info.image.height != 0) { - setState(() { - networkImagePositionRadio = (info.image.width / info.image.height); - }); - } - })); - } - } - Widget _renderNetworkImage( dynamic heroTag, double? positionRadio, TUITheme? theme, {String? path, V2TimImage? originalImg, V2TimImage? smallImg}) { @@ -458,12 +328,32 @@ class _TIMUIKitImageElem extends TIMUIKitState { getImage( GestureDetector( onTap: () { + if (PlatformUtils().isWeb) { + launchUrl( + Uri.parse(widget.message.imageElem?.path ?? ""), + mode: LaunchMode.externalApplication, + ); + return; + } if (isDesktopScreen) { - onTIMCallback(TIMCallback( - infoCode: 6660414, - infoRecommendText: TIM_t("正在下载中"), - type: TIMCallbackType.INFO - )); + 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)); + } } else { Navigator.of(context).push( PageRouteBuilder( @@ -516,6 +406,152 @@ class _TIMUIKitImageElem extends TIMUIKitState { } } + Widget _renderLocalImage(String smallImage, dynamic heroTag, + double? positionRadio, TUITheme? theme, String? originImage) { + double? currentPositionRadio = positionRadio; + File imgF = File(smallImage); + + bool isExist = imgF.existsSync(); + if (!isExist) { + return errorDisplay(context, theme); + } + + Image image = Image.file(imgF); + + String showImage = (originImage != null && File(originImage).existsSync()) + ? originImage + : smallImage; + + image.image + .resolve(const ImageConfiguration()) + .addListener(ImageStreamListener((image, synchronousCall) { + if (image.image.width != 0 && image.image.height != 0) { + currentPositionRadio = image.image.width / image.image.height; + } + })); + final message = widget.message; + final preloadImage = model.preloadImageMap[ + message.seq! + message.timestamp.toString() + (message.msgID ?? "")]; + + final isDesktopScreen = + TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; + + return Stack( + alignment: AlignmentDirectional.topStart, + children: [ + if (!isDesktopScreen && currentPositionRadio != null) + AspectRatio( + aspectRatio: currentPositionRadio!, + child: Container( + decoration: const BoxDecoration(color: Colors.transparent), + ), + ), + getImage( + GestureDetector( + onTap: () { + if (PlatformUtils().isDesktop) { + if (PlatformUtils().isWindows) { + OpenFile.open(showImage); + } else { + launchUrl(Uri.file(showImage)); + } + } else { + Navigator.of(context).push( + PageRouteBuilder( + opaque: false, // set to false + pageBuilder: (_, __, ___) => ImageScreen( + imageProvider: FileImage(File(showImage)), + heroTag: heroTag, + messageID: widget.message.msgID, + downloadFn: () async { + return await _saveImg(theme!); + }), + ), + ); + } + }, + 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, + ), + ), + )), + imageElem: null) + ], + ); + } + + @override + void initState() { + super.initState(); + if (!PlatformUtils().isWeb && + TencentUtils.checkString(widget.message.msgID) != null) { + if (TencentUtils.checkString( + widget.message.imageElem!.imageList![0]!.localUrl) == + null || + !File(widget.message.imageElem!.imageList![0]!.localUrl!) + .existsSync()) { + _messageService.downloadMessage( + msgID: widget.message.msgID!, + messageType: 3, + imageType: 0, + isSnapshot: false); + } + if (TencentUtils.checkString( + widget.message.imageElem!.imageList![1]!.localUrl) == + null || + !File(widget.message.imageElem!.imageList![1]!.localUrl!) + .existsSync()) { + _messageService.downloadMessage( + msgID: widget.message.msgID!, + messageType: 3, + imageType: 1, + isSnapshot: false); + } + if (TencentUtils.checkString( + widget.message.imageElem!.imageList![2]!.localUrl) == + null || + !File(widget.message.imageElem!.imageList![2]!.localUrl!) + .existsSync()) { + _messageService.downloadMessage( + msgID: widget.message.msgID!, + messageType: 3, + imageType: 2, + isSnapshot: false); + } + } + // 先暂时下掉用网络图片计算尺寸比例的feature,在没有找到准确的判断图片是否被打击前 + // setOnlineImageRatio(); + } + + void setOnlineImageRatio() { + if (networkImagePositionRadio == null) { + V2TimImage? smallImg = getImageFromList(V2TimImageTypesEnum.small); + V2TimImage? originalImg = getImageFromList(V2TimImageTypesEnum.original); + Image image = Image.network(smallImg?.url ?? originalImg?.url ?? ""); + + image.image + .resolve(const ImageConfiguration()) + .addListener(ImageStreamListener((ImageInfo info, bool _) { + if (info.image.width != 0 && info.image.height != 0) { + setState(() { + networkImagePositionRadio = (info.image.width / info.image.height); + }); + } + })); + } + } + bool isNeedShowLocalPath() { final current = (DateTime.now().millisecondsSinceEpoch / 1000).ceil(); final timeStamp = widget.message.timestamp ?? current; @@ -572,8 +608,7 @@ class _TIMUIKitImageElem extends TIMUIKitState { smallImg: smallImg, originalImg: originalImg); } - if ( - (smallImg?.url ?? originalImg?.url) != null && + if ((smallImg?.url ?? originalImg?.url) != null && (smallImg?.url ?? originalImg?.url)!.isNotEmpty) { return _renderNetworkImage(heroTag, positionRadio, theme, smallImg: smallImg, originalImg: originalImg); diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_reply_elem.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_reply_elem.dart index fb8c83a..e8e10b2 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_reply_elem.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_reply_elem.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.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_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart'; -import 'package:tencent_extended_text/extended_text.dart'; +import 'package:extended_text/extended_text.dart'; import 'package:tencent_im_base/tencent_im_base.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; @@ -302,7 +302,7 @@ class _TIMUIKitReplyElemState extends TIMUIKitState { isUseDefaultEmoji: widget.isUseDefaultEmoji, customEmojiStickerList: widget.customEmojiStickerList, isEnableTextSelection: - widget.chatModel.chatConfig.isEnableTextSelection); + widget.chatModel.chatConfig.isEnableTextSelection ?? false); return Container( padding: widget.textPadding ?? EdgeInsets.all(isDesktopScreen ? 12 : 10), decoration: BoxDecoration( diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_sound_elem.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_sound_elem.dart index d3ab96e..0321018 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_sound_elem.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_sound_elem.dart @@ -212,7 +212,7 @@ class _TIMUIKitSoundElemState extends TIMUIKitState { } } } - return InkWell( + return GestureDetector( onTap: () => _playSound(), child: Container( padding: widget.textPadding ?? const EdgeInsets.all(10), diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_text_elem.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_text_elem.dart index e1bed03..2938f5d 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_text_elem.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_text_elem.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; -import 'package:tencent_extended_text/extended_text.dart'; +import 'package:extended_text/extended_text.dart'; import 'package:flutter/material.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; @@ -170,7 +170,7 @@ class _TIMUIKitTextElemState extends TIMUIKitState { isUseDefaultEmoji: widget.isUseDefaultEmoji, customEmojiStickerList: widget.customEmojiStickerList, isEnableTextSelection: - widget.chatModel.chatConfig.isEnableTextSelection); + widget.chatModel.chatConfig.isEnableTextSelection ?? false); final borderRadius = widget.isFromSelf ? const BorderRadius.only( topLeft: Radius.circular(10), diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_text_translate_elem.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_text_translate_elem.dart index a703ee5..9a4a219 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_text_translate_elem.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitMessageItem/tim_uikit_chat_text_translate_elem.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; -import 'package:tencent_extended_text/extended_text.dart'; +import 'package:extended_text/extended_text.dart'; import 'package:flutter/material.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; @@ -127,7 +127,7 @@ class _TIMUIKitTextTranslationElemState isUseDefaultEmoji: widget.isUseDefaultEmoji, customEmojiStickerList: widget.customEmojiStickerList, isEnableTextSelection: - widget.chatModel.chatConfig.isEnableTextSelection); + widget.chatModel.chatConfig.isEnableTextSelection ?? false); return TencentUtils.checkString(translateText) != null ? Container( 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 eb6481e..e92a143 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 @@ -1,14 +1,12 @@ import 'dart:io'; import 'dart:math'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart'; -import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart'; import 'package:tencent_cloud_chat_uikit/data_services/message/message_services.dart'; import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart'; @@ -40,7 +38,6 @@ class TIMUIKitVideoElem extends StatefulWidget { } class _TIMUIKitVideoElemState extends TIMUIKitState { - final TUIChatGlobalModel globalModel = serviceLocator(); final MessageService _messageService = serviceLocator(); late V2TimVideoElem stateElement = widget.message.videoElem!; @@ -112,13 +109,13 @@ class _TIMUIKitVideoElemState extends TIMUIKitState { ), ); } - return (!kIsWeb && stateElement.snapshotUrl == null || + return (!PlatformUtils().isWeb && stateElement.snapshotUrl == null || widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING) ? (stateElement.snapshotPath!.isNotEmpty ? Image.file(File(stateElement.snapshotPath!), fit: BoxFit.fitWidth) : Image.file(File(stateElement.localSnapshotUrl!), fit: BoxFit.fitWidth)) - : (kIsWeb || + : (PlatformUtils().isWeb || stateElement.localSnapshotUrl == null || stateElement.localSnapshotUrl == "") ? Image.network(stateElement.snapshotUrl!, fit: BoxFit.fitWidth) @@ -127,9 +124,9 @@ class _TIMUIKitVideoElemState extends TIMUIKitState { } downloadMessageDetailAndSave() async { - if (widget.message.msgID != null && widget.message.msgID != '') { - if (widget.message.videoElem!.videoUrl == null || - widget.message.videoElem!.videoUrl == '') { + if (TencentUtils.checkString(widget.message.msgID) != null) { + if (TencentUtils.checkString(widget.message.videoElem!.videoUrl) == + null) { final response = await _messageService.getMessageOnlineUrl( msgID: widget.message.msgID!); if (response.data != null) { @@ -140,16 +137,19 @@ class _TIMUIKitVideoElemState extends TIMUIKitState { } } if (!PlatformUtils().isWeb) { - if (widget.message.videoElem!.localVideoUrl == null || - widget.message.videoElem!.localVideoUrl == '') { + if (TencentUtils.checkString(widget.message.videoElem!.localVideoUrl) == + null || + !File(widget.message.videoElem!.localVideoUrl!).existsSync()) { _messageService.downloadMessage( msgID: widget.message.msgID!, messageType: 5, imageType: 0, isSnapshot: false); } - if (widget.message.videoElem!.localSnapshotUrl == null || - widget.message.videoElem!.localSnapshotUrl == '') { + if (TencentUtils.checkString( + widget.message.videoElem!.localSnapshotUrl) == + null || + !File(widget.message.videoElem!.localSnapshotUrl!).existsSync()) { _messageService.downloadMessage( msgID: widget.message.msgID!, messageType: 5, @@ -172,33 +172,40 @@ class _TIMUIKitVideoElemState extends TIMUIKitState { final heroTag = "${widget.message.msgID ?? widget.message.id ?? widget.message.timestamp ?? DateTime.now().millisecondsSinceEpoch}${widget.isFrom}"; - return InkWell( + return GestureDetector( onTap: () { + if (PlatformUtils().isWeb) { + launchUrl( + Uri.parse(widget.message.videoElem?.videoPath ?? ""), + mode: LaunchMode.externalApplication, + ); + return; + } if (PlatformUtils().isDesktop) { final videoElem = widget.message.videoElem; if (videoElem != null) { - final localVideoUrl = TencentUtils.checkString(videoElem.localVideoUrl); + final localVideoUrl = + TencentUtils.checkString(videoElem.localVideoUrl); final videoPath = TencentUtils.checkString(videoElem.videoPath); final videoUrl = videoElem.videoUrl; if (localVideoUrl != null) { - if(PlatformUtils().isWindows){ + if (PlatformUtils().isWindows) { OpenFile.open(localVideoUrl); - } else{ + } else { launchUrl(Uri.file(localVideoUrl)); } } else if (videoPath != null) { - if(PlatformUtils().isWindows){ + if (PlatformUtils().isWindows) { OpenFile.open(videoPath); - } else{ + } else { launchUrl(Uri.file(videoPath)); } } else if (TencentUtils.isTextNotEmpty(videoUrl)) { onTIMCallback(TIMCallback( infoCode: 6660414, infoRecommendText: TIM_t("正在下载中"), - type: TIMCallbackType.INFO - )); + type: TIMCallbackType.INFO)); } } } else { @@ -227,15 +234,14 @@ class _TIMUIKitVideoElemState extends TIMUIKitState { borderRadius: const BorderRadius.all(Radius.circular(5)), child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { - double positionRadio = 0.56; - if (stateElement.snapshotWidth != null && + double? positionRadio; + if ((stateElement.snapshotWidth) != null && stateElement.snapshotHeight != null && stateElement.snapshotWidth != 0 && stateElement.snapshotHeight != 0) { positionRadio = (stateElement.snapshotWidth! / stateElement.snapshotHeight!); } - return ConstrainedBox( constraints: BoxConstraints( maxWidth: PlatformUtils().isWeb @@ -244,52 +250,49 @@ class _TIMUIKitVideoElemState extends TIMUIKitState { maxHeight: min(constraints.maxHeight * 0.8, 300), minHeight: 20, minWidth: 20), - child: AspectRatio( - aspectRatio: positionRadio, - child: Stack( - children: [ - if (stateElement.snapshotUrl != null || - stateElement.snapshotUrl != null) - AspectRatio( - aspectRatio: positionRadio, - child: Container( - decoration: const BoxDecoration( - color: Colors.transparent), - ), + child: Stack( + children: [ + if (positionRadio != null && + (stateElement.snapshotUrl != null || + stateElement.snapshotUrl != null)) + AspectRatio( + aspectRatio: positionRadio, + child: Container( + decoration: const BoxDecoration( + color: Colors.transparent), ), - Row( - children: [ - Expanded( - child: generateSnapshot(theme, - stateElement.snapshotHeight ?? 100)) - ], ), - if (widget.message.status != - MessageStatus - .V2TIM_MSG_STATUS_SENDING && - (stateElement.snapshotUrl != null || - stateElement.snapshotPath != null) && - stateElement.videoPath != null || - stateElement.videoUrl != null) - Positioned.fill( - // alignment: Alignment.center, - child: Center( - child: Image.asset('images/play.png', - package: 'tencent_cloud_chat_uikit', - height: 64)), - ), - Positioned( - right: 10, - bottom: 10, - child: Text( - MessageUtils.formatVideoTime(widget - .message.videoElem?.duration ?? - 0) - .toString(), - style: const TextStyle( - color: Colors.white, fontSize: 12))), - ], - ), + Row( + children: [ + Expanded( + child: generateSnapshot(theme, + stateElement.snapshotHeight ?? 100)) + ], + ), + if (widget.message.status != + MessageStatus.V2TIM_MSG_STATUS_SENDING && + (stateElement.snapshotUrl != null || + stateElement.snapshotPath != null) && + stateElement.videoPath != null || + stateElement.videoUrl != null) + Positioned.fill( + // alignment: Alignment.center, + child: Center( + child: Image.asset('images/play.png', + package: 'tencent_cloud_chat_uikit', + height: 64)), + ), + Positioned( + right: 10, + bottom: 10, + child: Text( + MessageUtils.formatVideoTime( + widget.message.videoElem?.duration ?? + 0) + .toString(), + style: const TextStyle( + color: Colors.white, fontSize: 12))), + ], )); }), ))), diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/at_member_panel.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/at_member_panel.dart index e133996..4eb68dc 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/at_member_panel.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/at_member_panel.dart @@ -100,6 +100,7 @@ class _AtMemberPanelState extends TIMUIKitState { width: 24, child: Avatar( faceUrl: memberItem.faceUrl ?? "", + type: 1, showName: showName), ), const SizedBox( diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/intl_camer_picker.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/intl_camer_picker.dart index 85bf61d..d876555 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/intl_camer_picker.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/intl_camer_picker.dart @@ -1,5 +1,5 @@ import 'package:tencent_im_base/tencent_im_base.dart'; -import 'package:tencent_wechat_camera_picker/tencent_wechat_camera_picker.dart'; +import 'package:wechat_camera_picker/wechat_camera_picker.dart'; class IntlCameraPickerTextDelegate extends CameraPickerTextDelegate { /// Confirm string for the confirm button. diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart index 852b017..c2746a2 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart @@ -1,7 +1,7 @@ // ignore_for_file: file_names -import 'package:tencent_extended_text_field/extended_text_field.dart'; +import 'package:extended_text_field/extended_text_field.dart'; import 'package:flutter/material.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/http_text.dart'; diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/emoji_text.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/emoji_text.dart index 2f0592b..2a7a564 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/emoji_text.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/emoji_text.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:tencent_extended_text/extended_text.dart'; +import 'package:extended_text/extended_text.dart'; import 'package:tim_ui_kit_sticker_plugin/constant/emoji.dart'; ///emoji/image text diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/http_text.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/http_text.dart index 3b5ef32..1c345b3 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/http_text.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/http_text.dart @@ -2,7 +2,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:tencent_cloud_chat_uikit/ui/widgets/link_preview/common/utils.dart'; -import 'package:tencent_extended_text/extended_text.dart'; +import 'package:extended_text/extended_text.dart'; class HttpText extends SpecialText { HttpText(TextStyle? textStyle, SpecialTextGestureTapCallback? onTap, diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_at_text.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_at_text.dart index d1a27eb..0bb631b 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_at_text.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_at_text.dart @@ -20,6 +20,7 @@ class AtText extends StatefulWidget { final Function( V2TimGroupMemberFullInfo memberInfo, TapDownDetails? tapDetails)? onChooseMember; + final bool canAtAll; // some Group type cant @all final String? groupType; @@ -32,6 +33,7 @@ class AtText extends StatefulWidget { this.groupMemberList, this.closeFunc, this.onChooseMember, + this.canAtAll = false, }) : super(key: key); @override @@ -116,7 +118,7 @@ class _AtTextState extends TIMUIKitState { groupType: widget.groupType ?? "", memberList: searchMemberList ?? [], onTapMemberItem: _onTapMemberItem, - canAtAll: true, + canAtAll: widget.canAtAll, canSlideDelete: false, touchBottomCallBack: () { // Get all by once, unnecessary to load more @@ -130,6 +132,7 @@ class _AtTextState extends TIMUIKitState { } return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: mentionedMembersBody(), defaultWidget: Scaffold( appBar: AppBar( @@ -137,8 +140,7 @@ class _AtTextState extends TIMUIKitState { iconTheme: IconThemeData( color: theme.appbarTextColor, ), - backgroundColor: theme.appbarBgColor ?? - theme.primaryColor, + backgroundColor: theme.appbarBgColor ?? theme.primaryColor, leading: Row( children: [ IconButton( 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 78c2d89..59e2ea7 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_more_panel.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_more_panel.dart @@ -12,7 +12,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_call_invite_list.dart'; -import 'package:tencent_wechat_camera_picker/tencent_wechat_camera_picker.dart'; +import 'package:wechat_camera_picker/wechat_camera_picker.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart'; @@ -360,7 +360,7 @@ class _MorePanelState extends TIMUIKitState { if (PlatformUtils().isMobile){ if(PlatformUtils().isAndroid){ AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; - if ((androidInfo.version.sdkInt ?? 0) >= 33) { + if ((androidInfo.version.sdkInt) >= 33) { final videos = await Permissions.checkPermission( context,Permission.videos.value, theme, diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart index bcd1a2e..0bbf7e7 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart @@ -129,7 +129,7 @@ class _SendSoundMessageState extends TIMUIKitState { ), ); }); - Overlay.of(context)?.insert(overlayEntry!); + Overlay.of(context).insert(overlayEntry!); } } 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 5c5d473..b4bbc45 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field.dart @@ -38,8 +38,6 @@ typedef CustomStickerPanel = Widget Function({ double? height, }); -GlobalKey<_InputTextFieldState> inputTextFieldState = GlobalKey(); - class TIMUIKitInputTextField extends StatefulWidget { /// conversation id final String conversationID; @@ -59,7 +57,7 @@ class TIMUIKitInputTextField extends StatefulWidget { /// hint text for textField widget final String? hintText; - /// config for more pannel + /// config for more panel final MorePanelConfig? morePanelConfig; /// show send audio icon @@ -133,15 +131,13 @@ class _InputTextFieldState extends TIMUIKitState { int? currentCursor; bool isAddingAtSearchWords = false; double inputWidth = 900; - - Map memberInfoMap = {}; - + Map mentionedMembersMap = {}; late TextEditingController textEditingController; final TUIConversationViewModel conversationModel = serviceLocator(); final TUISelfInfoViewModel selfModel = serviceLocator(); MuteStatus muteStatus = MuteStatus.none; - + bool _isComposingText = false; int latestSendEditStatusTime = DateTime.now().millisecondsSinceEpoch; setCurrentCursor(int? value) { @@ -160,7 +156,9 @@ class _InputTextFieldState extends TIMUIKitState { } if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) { - focusNode.unfocus(); + textEditingController.selection = TextSelection.fromPosition(TextPosition( + offset: currentCursor ?? textEditingController.text.length)); + focusNode.requestFocus(); } } @@ -168,18 +166,13 @@ class _InputTextFieldState extends TIMUIKitState { return text.replaceAll(RegExp(r'\ufeff'), ""); } - getShowName(message) { - return TencentUtils.checkStringWithoutSpace(message?.friendRemark) ?? - TencentUtils.checkStringWithoutSpace(message?.nickName) ?? - TencentUtils.checkStringWithoutSpace(message?.userID); - } - handleSetDraftText([String? id, ConvType? convType]) async { String convID = id ?? widget.conversationID; - String conversationID = - (convType ?? widget.conversationType) == ConvType.c2c + String conversationID = convID.contains("@TOPIC#") + ? convID + : ((convType ?? widget.conversationType) == ConvType.c2c ? "c2c_$convID" - : "group_$convID"; + : "group_$convID"); String text = textEditingController.text; String? draftText = _filterU200b(text); @@ -258,7 +251,7 @@ class _InputTextFieldState extends TIMUIKitState { List getUserIdFromMemberInfoMap() { List userList = []; - memberInfoMap.forEach((String key, V2TimGroupMemberFullInfo info) { + mentionedMembersMap.forEach((String key, V2TimGroupMemberFullInfo info) { userList.add(info.userID); }); @@ -278,7 +271,7 @@ class _InputTextFieldState extends TIMUIKitState { convType: convType, atUserIDList: getUserIdFromMemberInfoMap()), context); - } else if (memberInfoMap.isNotEmpty) { + } else if (mentionedMembersMap.isNotEmpty) { widget.model.sendTextAtMessage( text: text, convType: widget.conversationType, @@ -293,7 +286,7 @@ class _InputTextFieldState extends TIMUIKitState { textEditingController.clear(); currentCursor = null; lastText = ""; - memberInfoMap = {}; + mentionedMembersMap = {}; goDownBottom(); _handleSendEditStatus("", false); @@ -320,11 +313,6 @@ class _InputTextFieldState extends TIMUIKitState { } void onModelChanged() { - if (widget.model.repliedMessage != null) { - narrowTextFieldKey.currentState?.showKeyboard = true; - focusNode.requestFocus(); - _addDeleteTag(); - } else {} if (widget.model.editRevokedMsg != "") { narrowTextFieldKey.currentState?.showKeyboard = true; focusNode.requestFocus(); @@ -336,13 +324,6 @@ class _InputTextFieldState extends TIMUIKitState { } } - _addDeleteTag() { - final originalText = textEditingController.text; - textEditingController.text = zeroWidthSpace + originalText; - textEditingController.selection = TextSelection.fromPosition( - TextPosition(offset: textEditingController.text.length)); - } - _onCursorChange() { final selection = textEditingController.selection; currentCursor = selection.baseOffset; @@ -362,24 +343,32 @@ class _InputTextFieldState extends TIMUIKitState { } _longPressToAt(String? userID, String? nickName) { - final memberInfo = V2TimGroupMemberFullInfo( - userID: userID ?? "", - nickName: nickName, - ); - final showName = _getShowName(memberInfo); - memberInfoMap["@$showName"] = memberInfo; - String text = "${textEditingController.text}@$showName "; - //please do not delete space - focusNode.requestFocus(); - textEditingController.text = text; - textEditingController.selection = - TextSelection.fromPosition(TextPosition(offset: text.length - 1)); - lastText = text; + if (TencentUtils.checkString(userID) == null) { + focusNode.requestFocus(); + } else { + final memberInfo = widget.model.groupMemberList + ?.firstWhere((element) => element?.userID == userID) ?? + V2TimGroupMemberFullInfo( + userID: userID ?? "", + nickName: nickName, + ); + final showName = _getShowName(memberInfo); + mentionedMembersMap["@$showName"] = memberInfo; + String text = "${textEditingController.text}@$showName "; + //please do not delete space + focusNode.requestFocus(); + textEditingController.text = text; + textEditingController.selection = + TextSelection.fromPosition(TextPosition(offset: text.length)); + lastText = text; + _isComposingText = false; + narrowTextFieldKey.currentState?.showKeyboard = true; + } } bool shouldRemoveAtTag(String atTag, String deletedChar) { final atMemberArray = []; - memberInfoMap.forEach((key, value) { + mentionedMembersMap.forEach((key, value) { atMemberArray.add(key); }); for (String member in atMemberArray) { @@ -403,7 +392,11 @@ class _InputTextFieldState extends TIMUIKitState { final Offset caretPosition = textPainter.getOffsetForCaret(lastLineOffset, Rect.zero); final dx = min(inputWidth - 180, caretPosition.dx + 16); - final dy = max(24, 110 - caretPosition.dy).toDouble(); + final dy = max( + 24, + 18 * widget.model.chatConfig.desktopMessageInputFieldLines - + caretPosition.dy) + .toDouble(); return Offset(dx, dy); } @@ -417,11 +410,11 @@ class _InputTextFieldState extends TIMUIKitState { parseAtList.add(str); } for (String? key in parseAtList) { - if (key != null && memberInfoMap[key] != null) { - map[key] = memberInfoMap[key]!; + if (key != null && mentionedMembersMap[key] != null) { + map[key] = mentionedMembersMap[key]!; } } - memberInfoMap = map; + mentionedMembersMap = map; } _handleAtText(String text, TUIChatSeparateViewModel model) async { @@ -464,16 +457,21 @@ class _InputTextFieldState extends TIMUIKitState { parseAtList.add(str); } for (String? key in parseAtList) { - if (key != null && memberInfoMap[key] != null) { - map[key] = memberInfoMap[key]!; + if (key != null && mentionedMembersMap[key] != null) { + map[key] = mentionedMembersMap[key]!; } } - memberInfoMap = map; + mentionedMembersMap = map; return; } } } + final int selfRole = widget.model.selfMemberInfo?.role ?? 0; + final bool canAtAll = + (selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN || + selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER); + if (isDesktopScreen) { final atPlace = text.lastIndexOf("@"); final keyword = text.substring(atPlace + 1); @@ -484,16 +482,54 @@ class _InputTextFieldState extends TIMUIKitState { model.atPositionY = atPosition.dy; isAddingAtSearchWords = true; } - final List showAtMemberList = - (model.groupMemberList ?? []).where((element) { - final friendRemark = element?.friendRemark ?? ""; - final nickName = element?.nickName ?? ""; - final showName = TencentUtils.checkString(friendRemark) ?? - TencentUtils.checkString(nickName) ?? - TencentUtils.checkString(element?.userID) ?? - ""; - return showName.contains(keyword); - }).toList(); + List showAtMemberList = (model + .groupMemberList ?? + []) + .where((element) { + final showName = (TencentUtils.checkStringWithoutSpace( + element?.friendRemark) ?? + TencentUtils.checkStringWithoutSpace(element?.nameCard) ?? + TencentUtils.checkStringWithoutSpace(element?.nickName) ?? + TencentUtils.checkStringWithoutSpace(element?.userID) ?? + "") + .toLowerCase(); + return element != null && + showName.contains(keyword.toLowerCase()) && + TencentUtils.checkString(showName) != null && + element.userID != widget.model.selfMemberInfo?.userID; + }) + .whereType() + .toList(); + + showAtMemberList.sort( + (V2TimGroupMemberFullInfo userA, V2TimGroupMemberFullInfo userB) { + final isUserAIsGroupAdmin = userA.role == 300; + final isUserAIsGroupOwner = userA.role == 400; + + final isUserBIsGroupAdmin = userB.role == 300; + final isUserBIsGroupOwner = userB.role == 400; + + final String userAName = _getShowName(userA); + final String userBName = _getShowName(userB); + + if (isUserAIsGroupOwner != isUserBIsGroupOwner) { + return isUserAIsGroupOwner ? -1 : 1; + } + + if (isUserAIsGroupAdmin != isUserBIsGroupAdmin) { + return isUserAIsGroupAdmin ? -1 : 1; + } + + return userAName.compareTo(userBName); + }); + + if (canAtAll && showAtMemberList.isNotEmpty && keyword.isEmpty) { + showAtMemberList = [ + V2TimGroupMemberFullInfo( + userID: "__kImSDK_MesssageAtALL__", nickName: TIM_t("所有人")), + ...showAtMemberList + ]; + } model.activeAtIndex = 0; model.showAtMemberList = showAtMemberList; @@ -514,12 +550,13 @@ class _InputTextFieldState extends TIMUIKitState { groupMemberList: model.groupMemberList, groupInfo: model.groupInfo, groupID: groupID, + canAtAll: canAtAll, groupType: widget.groupType), ), ); final showName = _getShowName(memberInfo); if (memberInfo != null) { - memberInfoMap["@$showName"] = memberInfo; + mentionedMembersMap["@$showName"] = memberInfo; textEditingController.text = "$text$showName "; lastText = "$text$showName "; } @@ -547,103 +584,125 @@ class _InputTextFieldState extends TIMUIKitState { bool? isAddToCursorPosition = false}) { if (memberInfo != null) { final String showName = _getShowName(memberInfo); - memberInfoMap["@$showName"] = memberInfo; + mentionedMembersMap["@$showName"] = memberInfo; replaceAtTag(showName); widget.model.showAtMemberList = []; widget.model.activeAtIndex = -1; + focusNode.requestFocus(); } } + KeyEventResult handleDesktopKeyEvent(FocusNode node, RawKeyEvent event) { + final activeIndex = widget.model.activeAtIndex; + final showMemberList = widget.model.showAtMemberList; + if (event.runtimeType == RawKeyDownEvent) { + if (event.physicalKey == PhysicalKeyboardKey.backspace) { + if (textEditingController.text.isEmpty && lastText.isEmpty) { + widget.model.repliedMessage = null; + return KeyEventResult.handled; + } + } else if ((event.isShiftPressed || + event.isAltPressed || + event.isControlPressed || + event.isMetaPressed) && + event.physicalKey == PhysicalKeyboardKey.enter) { + final offset = textEditingController.selection.baseOffset; + textEditingController.text = + '${lastText.substring(0, offset)}\n${lastText.substring(offset)}'; + textEditingController.selection = + TextSelection.fromPosition(TextPosition(offset: offset + 1)); + lastText = textEditingController.text; + + return KeyEventResult.handled; + } else if (event.physicalKey == PhysicalKeyboardKey.enter) { + if (!_isComposingText) { + if (!isAddingAtSearchWords || widget.model.showAtMemberList.isEmpty) { + onSubmitted(); + } else { + isAddingAtSearchWords = false; + final V2TimGroupMemberFullInfo? memberInfo = + showMemberList[activeIndex]; + if (memberInfo != null) { + handleAtMember( + memberInfo: memberInfo, isAddToCursorPosition: true); + } + } + return KeyEventResult.handled; + } + } + + if (event.isKeyPressed(LogicalKeyboardKey.arrowUp) && + isAddingAtSearchWords && + showMemberList.isNotEmpty) { + final newIndex = max(activeIndex - 1, 0); + widget.model.activeAtIndex = newIndex; + widget.atMemberPanelScroll?.scrollToIndex(newIndex, + preferPosition: AutoScrollPosition.middle); + return KeyEventResult.handled; + } + + if (event.isKeyPressed(LogicalKeyboardKey.arrowDown) && + isAddingAtSearchWords && + showMemberList.isNotEmpty) { + final newIndex = min(activeIndex + 1, showMemberList.length - 1); + widget.model.activeAtIndex = newIndex; + widget.atMemberPanelScroll?.scrollToIndex(newIndex, + preferPosition: AutoScrollPosition.middle); + return KeyEventResult.handled; + } + } + + return KeyEventResult.ignored; + } + @override void initState() { super.initState(); if (PlatformUtils().isWeb || PlatformUtils().isDesktop) { focusNode = FocusNode( - onKey: (node, event) { - final activeIndex = widget.model.activeAtIndex; - final showMemberList = widget.model.showAtMemberList; - if (event.runtimeType == RawKeyDownEvent) { - if (event.physicalKey == PhysicalKeyboardKey.backspace) { - if (textEditingController.text.isEmpty && lastText.isEmpty) { - widget.model.repliedMessage = null; - return KeyEventResult.handled; - } - } else if ((event.isShiftPressed || - event.isAltPressed || - event.isControlPressed || - event.isMetaPressed) && - event.physicalKey == PhysicalKeyboardKey.enter) { - final offset = textEditingController.selection.baseOffset; - textEditingController.text = - '${lastText.substring(0, offset)}\n${lastText.substring(offset)}'; - textEditingController.selection = - TextSelection.fromPosition(TextPosition(offset: offset + 1)); - lastText = textEditingController.text; - - return KeyEventResult.handled; - } else if (event.physicalKey == PhysicalKeyboardKey.enter) { - if (!isAddingAtSearchWords || - widget.model.showAtMemberList.isEmpty) { - onSubmitted(); - } else { - isAddingAtSearchWords = false; - final V2TimGroupMemberFullInfo? memberInfo = - showMemberList[activeIndex]; - if (memberInfo != null) { - handleAtMember( - memberInfo: memberInfo, isAddToCursorPosition: true); - } - } - return KeyEventResult.handled; - } - - if (event.isKeyPressed(LogicalKeyboardKey.arrowUp) && - isAddingAtSearchWords && - showMemberList.isNotEmpty) { - final newIndex = max(activeIndex - 1, 0); - widget.model.activeAtIndex = newIndex; - widget.atMemberPanelScroll?.scrollToIndex(newIndex, - preferPosition: AutoScrollPosition.middle); - return KeyEventResult.handled; - } - - if (event.isKeyPressed(LogicalKeyboardKey.arrowDown) && - isAddingAtSearchWords && - showMemberList.isNotEmpty) { - final newIndex = min(activeIndex + 1, showMemberList.length - 1); - widget.model.activeAtIndex = newIndex; - widget.atMemberPanelScroll?.scrollToIndex(newIndex, - preferPosition: AutoScrollPosition.middle); - return KeyEventResult.handled; - } - } - - return KeyEventResult.ignored; - }, + onKey: (node, event) => handleDesktopKeyEvent(node, event), ); } else { focusNode = FocusNode(); } textEditingController = widget.controller?.textEditingController ?? TextEditingController(); - if (widget.controller != null) { - widget.controller?.addListener(() { - final actionType = widget.controller?.actionType; - if (actionType == ActionType.longPressToAt) { - _longPressToAt( - widget.controller?.atUserID, widget.controller?.atUserName); - } - }); - } - widget.model.addListener(onModelChanged); if (widget.initText != null) { textEditingController.text = widget.initText!; } + if (widget.controller != null) { + widget.controller?.addListener(controllerHandler); + } + widget.model.addListener(onModelChanged); final AppLocale appLocale = I18nUtils.findDeviceLocale(null); languageType = (appLocale == AppLocale.zhHans || appLocale == AppLocale.zhHant) ? 'zh' : 'en'; + textEditingController.addListener(() { + _isComposingText = textEditingController.value.composing.start != -1; + }); + } + + controllerHandler() { + final actionType = widget.controller?.actionType; + if (actionType == ActionType.longPressToAt) { + _longPressToAt( + widget.controller?.atUserID, widget.controller?.atUserName); + } else if (actionType == ActionType.setTextField) { + final newText = widget.controller?.inputText ?? ""; + textEditingController.text = newText; + textEditingController.selection = TextSelection.fromPosition( + TextPosition(offset: textEditingController.text.length)); + lastText = textEditingController.text; + return; + } else if (actionType == ActionType.requestFocus) { + focusNode.requestFocus(); + return; + } else if (actionType == ActionType.handleAtMember) { + handleAtMember(memberInfo: widget.controller?.groupMemberFullInfo); + return; + } } @override @@ -651,18 +710,27 @@ class _InputTextFieldState extends TIMUIKitState { super.didUpdateWidget(oldWidget); if (widget.conversationID != oldWidget.conversationID) { handleSetDraftText(oldWidget.conversationID, oldWidget.conversationType); + mentionedMembersMap.clear(); if (oldWidget.initText != widget.initText) { textEditingController.text = widget.initText ?? ""; } else { textEditingController.clear(); } } + if (widget.initText != oldWidget.initText && + TencentUtils.checkString(widget.initText) != null) { + textEditingController.text = widget.initText!; + focusNode.requestFocus(); + } } @override void dispose() { handleSetDraftText(); widget.model.removeListener(onModelChanged); + if (widget.controller != null) { + widget.controller?.removeListener(controllerHandler); + } focusNode.dispose(); super.dispose(); } @@ -738,6 +806,7 @@ class _InputTextFieldState extends TIMUIKitState { @override Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { + final theme = value.theme; final TUIChatSeparateViewModel model = Provider.of(context); @@ -763,6 +832,7 @@ class _InputTextFieldState extends TIMUIKitState { builder: (BuildContext context, BoxConstraints constraints) { inputWidth = constraints.maxWidth; return TUIKitScreenUtils.getDeviceWidget( + context: context, defaultWidget: TIMUIKitTextFieldLayoutNarrow( onEmojiSubmitted: onEmojiSubmitted, onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted, @@ -798,6 +868,7 @@ class _InputTextFieldState extends TIMUIKitState { showMorePanel: widget.showMorePanel, customEmojiStickerList: widget.customEmojiStickerList), desktopWidget: TIMUIKitTextFieldLayoutWide( + theme: theme, currentConversation: widget.currentConversation, onEmojiSubmitted: onEmojiSubmitted, onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted, @@ -825,7 +896,6 @@ class _InputTextFieldState extends TIMUIKitState { handleAtText: (text) { _handleAtText(text, model); }, - handleSoftKeyBoardDelete: _handleSoftKeyBoardDelete, onSubmitted: onSubmitted, goDownBottom: goDownBottom, showSendAudio: widget.showSendAudio, diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_controller.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_controller.dart index 7d1b988..628b5ef 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_controller.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_controller.dart @@ -1,12 +1,21 @@ import 'package:flutter/material.dart'; +import 'package:tencent_im_base/tencent_im_base.dart'; -enum ActionType { hideAllPanel, longPressToAt } +enum ActionType { + hideAllPanel, + longPressToAt, + setTextField, + requestFocus, + handleAtMember +} class TIMUIKitInputTextFieldController extends ChangeNotifier { TextEditingController? textEditingController = TextEditingController(); ActionType? actionType; String? atUserName; String? atUserID; + String inputText = ""; + V2TimGroupMemberFullInfo? groupMemberFullInfo; TIMUIKitInputTextFieldController([TextEditingController? controller]) { if (controller != null) { @@ -26,4 +35,21 @@ class TIMUIKitInputTextFieldController extends ChangeNotifier { atUserID = userID; notifyListeners(); } + + setTextField(String text) { + inputText = text; + actionType = ActionType.setTextField; + notifyListeners(); + } + + requestFocus() { + actionType = ActionType.requestFocus; + notifyListeners(); + } + + handleAtMember(V2TimGroupMemberFullInfo? memberInfo) { + actionType = ActionType.handleAtMember; + groupMemberFullInfo = memberInfo; + notifyListeners(); + } } diff --git a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart index 40679d4..3a427c1 100644 --- a/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart +++ b/lib/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart @@ -17,7 +17,7 @@ import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_emoji_panel.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_send_sound_message.dart'; -import 'package:tencent_extended_text_field/extended_text_field.dart'; +import 'package:extended_text_field/extended_text_field.dart'; import 'package:tencent_keyboard_visibility/tencent_keyboard_visibility.dart'; GlobalKey<_TIMUIKitTextFieldLayoutNarrowState> narrowTextFieldKey = GlobalKey(); 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 ef8f10d..94c9f37 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 @@ -3,6 +3,7 @@ import 'dart:io'; import 'dart:math'; import 'package:fc_native_video_thumbnail_for_us/fc_native_video_thumbnail_for_us.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:pasteboard/pasteboard.dart'; import 'package:path/path.dart' as p; @@ -26,7 +27,7 @@ import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_emoji_panel.dart'; import 'package:tencent_cloud_chat_uikit/ui/widgets/drag_widget.dart'; -import 'package:tencent_extended_text_field/extended_text_field.dart'; +import 'package:extended_text_field/extended_text_field.dart'; import 'package:universal_html/html.dart' as html; import 'package:url_launcher/url_launcher.dart'; import 'package:uuid/uuid.dart'; @@ -39,6 +40,7 @@ class DesktopControlBarItem { final String item; final IconData? icon; final String? imgPath; + final String? svgPath; final Color? color; final ValueChanged onClick; final String? showName; @@ -49,10 +51,13 @@ class DesktopControlBarItem { this.icon, this.color, this.imgPath, + this.svgPath, required this.onClick, this.showName, this.size}) - : assert(icon != null || imgPath != null); + : assert(icon != null || + TencentUtils.checkString(imgPath) != null || + TencentUtils.checkString(svgPath) != null); } class DesktopControlBarConfig { @@ -81,7 +86,7 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget { final Function(String, bool) handleSendEditStatus; final VoidCallback backSpaceText; final ValueChanged addStickerToText; - + final TUITheme theme; final ValueChanged handleAtText; /// Whether to use the default emoji @@ -125,8 +130,6 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget { /// show send audio icon final bool showSendAudio; - final VoidCallback handleSoftKeyBoardDelete; - /// on text changed final void Function(String)? onChanged; @@ -168,7 +171,6 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget { this.onChanged, required this.handleSendEditStatus, required this.handleAtText, - required this.handleSoftKeyBoardDelete, this.repliedMessage, this.forbiddenText, required this.onSubmitted, @@ -179,7 +181,8 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget { this.hintText, required this.customEmojiStickerList, this.controller, - required this.currentConversation}) + required this.currentConversation, + required this.theme}) : super(key: key); @override @@ -199,6 +202,7 @@ class _TIMUIKitTextFieldLayoutWideState double? bottomPadding; late ScrollController _scrollController; late FocusNode textFocusNode; + late List defaultControlBarItems; @override void initState() { @@ -214,6 +218,27 @@ class _TIMUIKitTextFieldLayoutWideState textFocusNode = FocusNode(); widget.focusNode.requestFocus(); _scrollController = ScrollController(); + try { + if (PlatformUtils().isWeb) { + html.window.addEventListener('paste', (event) { + _handlePaste(event as html.ClipboardEvent); + }); + } + } catch (e) { + print(e); + } + generateDefaultControlBarItems(); + } + + Future _handlePaste(html.ClipboardEvent event) async { + try { + if (event.clipboardData!.files!.isNotEmpty) { + html.File imageFile = event.clipboardData!.files![0]; + sendFileUseJs(imageFile); + } + } catch (e) { + print("Paste image failed: ${e.toString()}"); + } } hideAllPanel() { @@ -324,6 +349,8 @@ class _TIMUIKitTextFieldLayoutWideState addText: (int unicode) { final newText = String.fromCharCode(unicode); widget.addStickerToText(newText); + entry?.remove(); + entry = null; }, addCustomEmojiText: ((String singleEmojiName) { String? emojiName = singleEmojiName.split('.png')[0]; @@ -335,6 +362,8 @@ class _TIMUIKitTextFieldLayoutWideState } final newText = '[$emojiName]'; widget.addStickerToText(newText); + entry?.remove(); + entry = null; }), defaultCustomEmojiStickerList: widget.isUseDefaultEmoji ? ConstData.emojiList : []) @@ -349,7 +378,7 @@ class _TIMUIKitTextFieldLayoutWideState ), )); }); - Overlay.of(context)?.insert(entry!); + Overlay.of(context).insert(entry!); } } @@ -363,12 +392,12 @@ class _TIMUIKitTextFieldLayoutWideState color: const Color(0x7F000000), ); }); - Overlay.of(context)?.insert(entry!); + Overlay.of(context).insert(entry!); } } _removeOverlay() { - entry!.remove(); + entry?.remove(); entry = null; } @@ -399,20 +428,19 @@ class _TIMUIKitTextFieldLayoutWideState convID: convID, convType: convType), context); - return; + } else { + File file = File(result.files.single.path!); + final int size = file.lengthSync(); + final String savePath = file.path; + + MessageUtils.handleMessageError( + model.sendFileMessage( + filePath: savePath, + size: size, + convID: convID, + convType: convType), + context); } - - File file = File(result.files.single.path!); - final int size = file.lengthSync(); - final String savePath = file.path; - - MessageUtils.handleMessageError( - model.sendFileMessage( - filePath: savePath, - size: size, - convID: convID, - convType: convType), - context); } else { throw TypeError(); } @@ -424,10 +452,11 @@ class _TIMUIKitTextFieldLayoutWideState List generateBarIcons( List items, TUITheme theme) { + final defaultItems = defaultControlBarItems.map((e) => e.item); return items.map((e) { final GlobalKey key = GlobalKey(); return Container( - margin: const EdgeInsets.only(right: 6), + margin: const EdgeInsets.only(right: 10), child: InkWell( onTap: () { final alignBox = @@ -445,20 +474,39 @@ class _TIMUIKitTextFieldLayoutWideState textStyle: TextStyle(fontSize: 12, color: theme.white), message: e.showName, child: Container( - decoration: - BoxDecoration(borderRadius: BorderRadius.circular(2)), - padding: const EdgeInsets.all(4), - child: e.imgPath != null - ? Image.asset( - e.imgPath!, - key: key, - width: e.size ?? 20, - height: e.size ?? 20, - ) - : Icon(e.icon, - key: key, - color: e.color ?? hexToColor("646a73"), - size: e.size ?? 20)), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(2)), + padding: const EdgeInsets.all(4), + child: () { + if (TencentUtils.checkString(e.svgPath) != null) { + return SvgPicture.asset( + e.svgPath!, + package: defaultItems.contains(e.item) + ? 'tencent_cloud_chat_uikit' + : null, + key: key, + width: e.size ?? 16, + height: e.size ?? 16, + ); + } + if (TencentUtils.checkString(e.imgPath) != null) { + return Image.asset( + e.imgPath!, + package: defaultItems.contains(e.item) + ? 'tencent_cloud_chat_uikit' + : null, + key: key, + width: e.size ?? 16, + height: e.size ?? 16, + ); + } + return Icon( + e.icon, + key: key, + color: e.color ?? hexToColor("646a73"), + size: e.size ?? 20, + ); + }(), + ), ), ), ); @@ -658,10 +706,11 @@ class _TIMUIKitTextFieldLayoutWideState } } - _sendImageWithConfirmation(String file) async { + _sendImageWithConfirmation( + {String? fileName, Size? fileSize, required String filePath}) async { final option1 = widget.currentConversation.showName ?? (widget.conversationType == ConvType.group ? TIM_t("群聊") : TIM_t("对方")); - final size = await ScreenshotHelper.getImageSize(file); + final size = fileSize ?? await ScreenshotHelper.getImageSize(filePath); TUIKitWidePopup.showPopupWindow( operationKey: TUIKitWideModalOperationKey.beforeSendScreenShot, @@ -679,12 +728,19 @@ class _TIMUIKitTextFieldLayoutWideState height: min(360, size.height / 2), child: InkWell( onTap: () { - launchUrl(Uri.file(file)); + launchUrl(PlatformUtils().isWeb + ? Uri.parse(filePath) + : Uri.file(filePath)); }, - child: Image.file( - File(file), - height: min(360, size.height / 2), - ), + child: PlatformUtils().isWeb + ? Image.network( + filePath, + height: min(360, size.height / 2), + ) + : Image.file( + File(filePath), + height: min(360, size.height / 2), + ), ), ), Row( @@ -703,7 +759,8 @@ class _TIMUIKitTextFieldLayoutWideState onPressed: () { MessageUtils.handleMessageError( widget.model.sendImageMessage( - imagePath: file, + imagePath: filePath, + imageName: fileName, convID: widget.conversationID, convType: widget.conversationType), context); @@ -720,12 +777,11 @@ class _TIMUIKitTextFieldLayoutWideState _sendScreenShot() async { final file = await ScreenshotHelper.captureScreen(); if (file != null) { - _sendImageWithConfirmation(file); + _sendImageWithConfirmation(filePath: file); } else {} } - List generateControlBar( - TUIChatSeparateViewModel model, TUITheme theme) { + generateDefaultControlBarItems() { final DesktopControlBarConfig config = widget.model.chatConfig.desktopControlBarConfig ?? DesktopControlBarConfig(); @@ -735,9 +791,9 @@ class _TIMUIKitTextFieldLayoutWideState item: "face", showName: TIM_t("表情"), onClick: (offset) { - _sendEmoji(offset, theme); + _sendEmoji(offset, widget.theme); }, - icon: Icons.mood), + svgPath: "images/svg/send_face.svg"), if (config.showScreenshotButton && PlatformUtils().isDesktop) DesktopControlBarItem( item: "screenShot", @@ -745,15 +801,15 @@ class _TIMUIKitTextFieldLayoutWideState onClick: (offset) { _sendScreenShot(); }, - icon: Icons.cut_outlined), + svgPath: "images/svg/send_screenshot.svg"), if (config.showSendFileButton) DesktopControlBarItem( item: "file", showName: TIM_t("文件"), onClick: (offset) { - _sendFile(widget.model, theme); + _sendFile(widget.model, widget.theme); }, - icon: Icons.file_copy_outlined), + svgPath: "images/svg/send_file.svg"), if (config.showSendImageButton) DesktopControlBarItem( item: "photo", @@ -762,10 +818,10 @@ class _TIMUIKitTextFieldLayoutWideState if (PlatformUtils().isWeb) { _sendImageFileOnWeb(widget.model); } else { - _sendMediaMessage(widget.model, theme, FileType.image); + _sendMediaMessage(widget.model, widget.theme, FileType.image); } }, - icon: Icons.image_outlined), + svgPath: "images/svg/send_image.svg"), if (config.showSendVideoButton) DesktopControlBarItem( item: "video", @@ -774,10 +830,10 @@ class _TIMUIKitTextFieldLayoutWideState if (PlatformUtils().isWeb) { _sendVideoFileOnWeb(widget.model); } else { - _sendMediaMessage(widget.model, theme, FileType.video); + _sendMediaMessage(widget.model, widget.theme, FileType.video); } }, - icon: Icons.video_library_outlined), + svgPath: "images/svg/send_video.svg"), if (config.showMessageHistoryButton) DesktopControlBarItem( item: "history", @@ -801,19 +857,41 @@ class _TIMUIKitTextFieldLayoutWideState onTapConversation: (V2TimConversation conversation, V2TimMessage? message) {}, ), - theme: theme); + theme: widget.theme); }, - icon: Icons.chat_outlined), + svgPath: "images/svg/message_history.svg"), + ]; + defaultControlBarItems = itemsList; + } + + List generateControlBar( + TUIChatSeparateViewModel model, TUITheme theme) { + final List itemsList = [ + ...defaultControlBarItems, ...(widget.model.chatConfig.additionalDesktopControlBarItems ?? []) ]; return generateBarIcons(itemsList, theme); } + sendFileUseJs(html.File file) { + final mimeType = file.type.split('/'); + final type = mimeType[0]; + final blobUrl = html.Url.createObjectUrl(file); + if (type == 'image') { + _sendImageWithConfirmation( + filePath: blobUrl, + fileName: file.name, + fileSize: const Size(500, 500)); + } + } + Future _handleKeyEvent(RawKeyEvent event) async { - if ((event.isKeyPressed(LogicalKeyboardKey.controlLeft) && - event.logicalKey == LogicalKeyboardKey.keyV) || - (event.isMetaPressed && event.logicalKey == LogicalKeyboardKey.keyV)) { + if (PlatformUtils().isDesktop && + ((event.isKeyPressed(LogicalKeyboardKey.controlLeft) && + event.logicalKey == LogicalKeyboardKey.keyV) || + (event.isMetaPressed && + event.logicalKey == LogicalKeyboardKey.keyV))) { final bytes = await Pasteboard.image; if (bytes != null) { String directory; @@ -838,7 +916,7 @@ class _TIMUIKitTextFieldLayoutWideState await scDirectory.create(recursive: true); } await file.writeAsBytes(bytes.toList()); - _sendImageWithConfirmation(filePath); + _sendImageWithConfirmation(filePath: filePath); } } } @@ -857,10 +935,6 @@ class _TIMUIKitTextFieldLayoutWideState } widget.handleAtText(value); widget.handleSendEditStatus(value, true); - final isEmpty = value.isEmpty; - if (isEmpty) { - widget.handleSoftKeyBoardDelete(); - } }, const Duration(milliseconds: 80)); final MediaQueryData data = MediaQuery.of(context); @@ -873,7 +947,7 @@ class _TIMUIKitTextFieldLayoutWideState focusNode: textFocusNode, onKey: _handleKeyEvent, child: Container( - color: widget.backgroundColor, + color: widget.backgroundColor ?? theme.desktopChatMessageInputBgColor, child: Column( children: [ SizedBox( @@ -899,7 +973,8 @@ class _TIMUIKitTextFieldLayoutWideState Expanded( child: Container( height: 35, - color: theme.weakBackgroundColor, + color: widget.backgroundColor ?? + theme.desktopChatMessageInputBgColor, alignment: Alignment.center, child: Text( TIM_t(widget.forbiddenText!), @@ -913,45 +988,43 @@ class _TIMUIKitTextFieldLayoutWideState )), if (widget.forbiddenText == null) Expanded( - child: Scrollbar( - controller: _scrollController, - child: ExtendedTextField( - autofocus: true, - maxLines: 6, - minLines: 6, - focusNode: widget.focusNode, - onChanged: debounceFunc, - keyboardType: TextInputType.multiline, - textInputAction: PlatformUtils().isAndroid - ? TextInputAction.newline - : TextInputAction.send, - onEditingComplete: () { - widget.onSubmitted(); - }, - textAlignVertical: TextAlignVertical.top, - style: const TextStyle(fontSize: 14), - decoration: InputDecoration( - hoverColor: hexToColor("fafafa"), - border: InputBorder.none, - hintStyle: const TextStyle( - color: Color(0xffAEA4A3), - ), - fillColor: hexToColor("fafafa"), - filled: true, - isDense: true, - hintText: widget.hintText ?? '', + child: ExtendedTextField( + scrollController: _scrollController, + autofocus: true, + maxLines: widget + .model.chatConfig.desktopMessageInputFieldLines, + minLines: widget + .model.chatConfig.desktopMessageInputFieldLines, + focusNode: widget.focusNode, + onChanged: debounceFunc, + keyboardType: TextInputType.multiline, + onEditingComplete: () { + // // widget.onSubmitted(); + }, + textAlignVertical: TextAlignVertical.top, + style: const TextStyle(fontSize: 14), + decoration: InputDecoration( + hoverColor: hexToColor("fafafa"), + border: InputBorder.none, + hintStyle: const TextStyle( + color: Color(0xffAEA4A3), ), - controller: widget.textEditingController, - specialTextSpanBuilder: PlatformUtils().isWeb - ? null - : DefaultSpecialTextSpanBuilder( - isUseDefaultEmoji: - widget.isUseDefaultEmoji, - customEmojiStickerList: - widget.customEmojiStickerList, - showAtBackground: true, - )), - ), + fillColor: widget.backgroundColor ?? + theme.desktopChatMessageInputBgColor ?? + hexToColor("fafafa"), + filled: true, + isDense: true, + hintText: widget.hintText ?? '', + ), + controller: widget.textEditingController, + specialTextSpanBuilder: PlatformUtils().isWeb + ? null + : DefaultSpecialTextSpanBuilder( + isUseDefaultEmoji: widget.isUseDefaultEmoji, + customEmojiStickerList: + widget.customEmojiStickerList, + showAtBackground: true, + )), ), ], ), diff --git a/lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart b/lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart index a294e8f..1e2c089 100644 --- a/lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart +++ b/lib/ui/views/TIMUIKitChat/tim_uikit_chat.dart @@ -59,6 +59,10 @@ class TIMUIKitChat extends StatefulWidget { /// Avatar and name in message reaction tap callback. final void Function(String userID, TapDownDetails tapDetails)? onTapAvatar; + /// Avatar and name in message reaction secondary tap callback. + final void Function(String userID, TapDownDetails tapDetails)? + 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") @@ -145,12 +149,13 @@ class TIMUIKitChat extends StatefulWidget { 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, + @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.exteraTipsActionItemBuilder, this.extraTipsActionItemBuilder, this.draftText, this.textFieldHintText, @@ -170,7 +175,8 @@ class TIMUIKitChat extends StatefulWidget { this.topFixWidget = const SizedBox(), this.textFieldBuilder, this.customEmojiStickerList = const [], - this.customAppBar}) + this.customAppBar, + this.onSecondaryTapAvatar}) : super(key: key) { startTime = DateTime.now().millisecondsSinceEpoch; } @@ -239,7 +245,9 @@ class _TUIChatState extends TIMUIKitState { model = TUIChatSeparateViewModel(); model.abstractMessageBuilder = widget.abstractMessageBuilder; model.onTapAvatar = widget.onTapAvatar; + textFieldController.requestFocus(); Future.delayed(const Duration(milliseconds: 50), () { + textFieldController.requestFocus(); try { autoController.jumpTo( autoController.position.minScrollExtent, @@ -317,6 +325,7 @@ class _TUIChatState extends TIMUIKitState { return TIMUIKitChatProviderScope( model: model, groupID: widget.groupID, + scrollController: autoController, textFieldController: textFieldController, conversationID: _getConvID(), conversationType: _getConvType(), @@ -331,6 +340,8 @@ class _TUIChatState extends TIMUIKitState { Provider.of(context, listen: true); widget.controller?.model = model; + widget.controller?.textFieldController = textFieldController; + widget.controller?.scrollController = autoController; List filteredApplicationList = []; if (widget.conversationType == ConvType.group && widget.onDealWithGroupApplication != null) { @@ -431,11 +442,8 @@ class _TUIChatState extends TIMUIKitState { tongueItemBuilder: widget.tongueItemBuilder, onLongPressForOthersHeadPortrait: (String? userId, String? nickName) { - if (widget.conversationType != - ConvType.c2c) { - textFieldController.longPressToAt( - nickName, userId); - } + textFieldController.longPressToAt( + nickName, userId); }, mainHistoryListConfig: widget.mainHistoryListConfig, @@ -445,6 +453,8 @@ class _TUIChatState extends TIMUIKitState { widget.exteraTipsActionItemBuilder, conversationType: _getConvType(), scrollController: autoController, + onSecondaryTapAvatar: + widget.onSecondaryTapAvatar, onTapAvatar: widget.onTapAvatar, // ignore: deprecated_member_use_from_same_package showNickName: widget.showNickName, @@ -463,7 +473,6 @@ class _TUIChatState extends TIMUIKitState { : (widget.textFieldBuilder != null ? widget.textFieldBuilder!(context) : TIMUIKitInputTextField( - key: inputTextFieldState, atMemberPanelScroll: atMemberPanelScroll, groupType: @@ -483,7 +492,8 @@ class _TUIChatState extends TIMUIKitState { scrollController: autoController, conversationID: _getConvID(), conversationType: _getConvType(), - initText: widget.draftText, + initText: widget.draftText ?? + widget.conversation.draftText, hintText: widget.textFieldHintText, showMorePanel: widget.config ?.isAllowShowMorePanel ?? @@ -508,9 +518,8 @@ class _TUIChatState extends TIMUIKitState { ), AtMemberPanel( atMemberPanelScroll: atMemberPanelScroll, - onSelectMember: (member) => inputTextFieldState - .currentState - ?.handleAtMember(memberInfo: member), + onSelectMember: (member) => + textFieldController.handleAtMember(member), ) ], ), @@ -555,6 +564,8 @@ class TIMUIKitChatProviderScope extends StatelessWidget { final bool? isBuild; + final AutoScrollController? scrollController; + TIMUIKitChatProviderScope( {Key? key, this.child, @@ -568,13 +579,16 @@ class TIMUIKitChatProviderScope extends StatelessWidget { required this.conversationType, this.controller, this.config, - this.lifeCycle}) + this.lifeCycle, + this.scrollController}) : super(key: key) { if (isBuild ?? false) { return; } model ??= TUIChatSeparateViewModel(); controller?.model = model; + controller?.textFieldController = textFieldController; + controller?.scrollController = scrollController; if (config != null) { model?.chatConfig = config!; } diff --git a/lib/ui/views/TIMUIKitChat/tim_uikit_chat_config.dart b/lib/ui/views/TIMUIKitChat/tim_uikit_chat_config.dart index 7096a47..eddebef 100644 --- a/lib/ui/views/TIMUIKitChat/tim_uikit_chat_config.dart +++ b/lib/ui/views/TIMUIKitChat/tim_uikit_chat_config.dart @@ -147,7 +147,7 @@ class TIMUIKitChatConfig { /// Whether to use the default emoji final bool isUseDefaultEmoji; - /// Is show avatar on history message list. + /// Whether shows avatar on history message list. /// [Default]: true. final bool isShowAvatar; @@ -157,13 +157,13 @@ class TIMUIKitChatConfig { final List? additionalDesktopMessageHoverBarItem; /// This list contains additional items that are displayed - /// on the control bar on desktop (macOS, Windows, and desktop version of Web). + /// on the message sending area control bar on desktop (macOS, Windows, and desktop version of Web). /// Use `desktopControlBarConfig` to configure whether or not to show the default control items. final List? additionalDesktopControlBarItems; /// This configuration is used for the control bar /// on desktop (macOS, Windows, and desktop version of Web). - /// Use `desktopControlBarConfig` to add additional items to the desktop control bar, in addition to the default ones. + /// Use `desktopControlBarConfig` to add additional items to the desktop message sending area control bar, in addition to the default ones. final DesktopControlBarConfig? desktopControlBarConfig; /// Controls whether users are allowed to mention another user in the group by long-pressing on their avatar. @@ -178,15 +178,24 @@ class TIMUIKitChatConfig { /// [Default]: true on Desktop while false on Mobile. final bool? isEnableTextSelection; + /// Controls whether enable the control bar shows when hovering a message on Desktop. + /// [Default]: true. + final bool isUseMessageHoverBarOnDesktop; + + /// Define the lines in the text message input field on Desktop. + final int desktopMessageInputFieldLines; + const TIMUIKitChatConfig( {this.onTapLink, this.timeDividerConfig, - this.isAutoReportRead = true, + this.isAutoReportRead = true, this.faceURIPrefix, this.faceURISuffix, this.textHeight = 1.3, + this.desktopMessageInputFieldLines = 6, this.isAtWhenReply = true, this.notificationAndroidSound = "", + this.isUseMessageHoverBarOnDesktop = true, this.isSupportMarkdownForTextMessage = false, this.notificationExt, this.isUseMessageReaction = true, @@ -212,7 +221,7 @@ class TIMUIKitChatConfig { this.desktopControlBarConfig, this.isAllowLongPressMessage = true, this.isAllowClickAvatar = true, - this.isEnableTextSelection, + this.isEnableTextSelection, this.additionalDesktopMessageHoverBarItem, this.isShowGroupReadingStatus = true, this.isReportGroupReadingStatus = true, diff --git a/lib/ui/views/TIMUIKitChat/tim_uikit_multi_select_panel.dart b/lib/ui/views/TIMUIKitChat/tim_uikit_multi_select_panel.dart index 93f2be6..688d220 100644 --- a/lib/ui/views/TIMUIKitChat/tim_uikit_multi_select_panel.dart +++ b/lib/ui/views/TIMUIKitChat/tim_uikit_multi_select_panel.dart @@ -64,6 +64,7 @@ class MultiSelectPanel extends TIMUIKitStatelessWidget { Provider.of(context); return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: Container( decoration: BoxDecoration( color: theme.selectPanelBgColor ?? theme.primaryColor, diff --git a/lib/ui/views/TIMUIKitConversation/tim_uikit_conversation.dart b/lib/ui/views/TIMUIKitConversation/tim_uikit_conversation.dart index 5ec34e0..2fdabec 100644 --- a/lib/ui/views/TIMUIKitConversation/tim_uikit_conversation.dart +++ b/lib/ui/views/TIMUIKitConversation/tim_uikit_conversation.dart @@ -64,8 +64,6 @@ class TIMUIKitConversation extends StatefulWidget { final bool isShowOnlineStatus; /// Control if shows the identifier that the conversation has a draft text, inputted in previous. - /// Also, you have better specifying the `draftText` field for `TIMUIKitChat`, from the `draftText` in `V2TimConversation`, - /// to meet the identifier shows here. final bool isShowDraft; const TIMUIKitConversation( @@ -375,7 +373,7 @@ class _TIMUIKitConversationState extends TIMUIKitState { : isPined ? theme.conversationItemPinedBgColor : theme.conversationItemBgColor, - child: InkWell( + child: GestureDetector( child: TIMUIKitConversationItem( isCurrent: isCurrent, isShowDraft: widget.isShowDraft, @@ -402,11 +400,12 @@ class _TIMUIKitConversationState extends TIMUIKitState { } return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: AutoScrollTag( key: ValueKey(conversationItem.conversationID), controller: _autoScrollController, index: index, - child: GestureDetector( + child: InkWell( onSecondaryTapDown: (details) { TUIKitWidePopup.showPopupWindow( operationKey: TUIKitWideModalOperationKey @@ -450,6 +449,7 @@ class _TIMUIKitConversationState extends TIMUIKitState { } return TUIKitScreenUtils.getDeviceWidget( + context: context, defaultWidget: SlidableAutoCloseBehavior( child: EasyRefresh( header: CustomizeBallPulseHeader(color: theme.primaryColor), diff --git a/lib/ui/views/TIMUIKitGroupProfile/group_member/tui_add_group_member.dart b/lib/ui/views/TIMUIKitGroupProfile/group_member/tui_add_group_member.dart index 583a8fc..aeefa6a 100644 --- a/lib/ui/views/TIMUIKitGroupProfile/group_member/tui_add_group_member.dart +++ b/lib/ui/views/TIMUIKitGroupProfile/group_member/tui_add_group_member.dart @@ -34,6 +34,7 @@ class _AddGroupMemberPageState extends TIMUIKitState { final TUITheme theme = value.theme; return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: Container( padding: const EdgeInsets.symmetric(horizontal: 16), child: ContactList( diff --git a/lib/ui/views/TIMUIKitGroupProfile/group_member/tui_delete_group_member.dart b/lib/ui/views/TIMUIKitGroupProfile/group_member/tui_delete_group_member.dart index 2e693e4..36082e6 100644 --- a/lib/ui/views/TIMUIKitGroupProfile/group_member/tui_delete_group_member.dart +++ b/lib/ui/views/TIMUIKitGroupProfile/group_member/tui_delete_group_member.dart @@ -82,6 +82,7 @@ class _DeleteGroupMemberPageState extends TIMUIKitState { final TUITheme theme = value.theme; return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: Container( padding: const EdgeInsets.symmetric(horizontal: 16), child: GroupProfileMemberList( diff --git a/lib/ui/views/TIMUIKitGroupProfile/widgets/tim_uikit_group_manage.dart b/lib/ui/views/TIMUIKitGroupProfile/widgets/tim_uikit_group_manage.dart index 625a781..46195b9 100644 --- a/lib/ui/views/TIMUIKitGroupProfile/widgets/tim_uikit_group_manage.dart +++ b/lib/ui/views/TIMUIKitGroupProfile/widgets/tim_uikit_group_manage.dart @@ -376,7 +376,7 @@ class _GroupProfileGroupManagePageState size: 16), onClick: () { widget.model.muteGroupMember( - e?.userID ?? "", + e.userID, false, serverTime); onClose(); @@ -409,6 +409,7 @@ class _GroupProfileGroupManagePageState } return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: managePage(), defaultWidget: Scaffold( appBar: AppBar( @@ -501,6 +502,7 @@ Widget _buildListItem(BuildContext context, V2TimGroupMemberFullInfo memberInfo, } return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: nameItem(), defaultWidget: SingleChildScrollView( child: Slidable(endActionPane: endActionPane, child: nameItem()))); @@ -724,7 +726,7 @@ class _GroupProfileSetManagerPageState Icons.remove_circle_outline, size: 16), onClick: () { - _removeAdmin(context, e!); + _removeAdmin(context, e); onClose(); }), ])); @@ -758,6 +760,7 @@ class _GroupProfileSetManagerPageState } return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: adminPage(), defaultWidget: Scaffold( appBar: AppBar( @@ -876,6 +879,7 @@ class _GroupProfileAddAdminState extends TIMUIKitState { } return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: Container( padding: const EdgeInsets.symmetric(horizontal: 16), child: addAdminPage(), diff --git a/lib/ui/views/TIMUIKitProfile/tim_uikit_profile.dart b/lib/ui/views/TIMUIKitProfile/tim_uikit_profile.dart index 37a65cf..b3251ad 100644 --- a/lib/ui/views/TIMUIKitProfile/tim_uikit_profile.dart +++ b/lib/ui/views/TIMUIKitProfile/tim_uikit_profile.dart @@ -76,11 +76,11 @@ class TIMUIKitProfile extends StatefulWidget { /// The life cycle hooks for user profile business logic final ProfileLifeCycle? lifeCycle; - /// If the loading user is self. + /// Whether the specify user is current logged in user. /// Default: [false]. final bool isSelf; - /// Is use the small card mode on Desktop. Usually shows on the Chat page. + /// Whether use the small card mode on Desktop. Usually shows on the Chat page. final bool smallCardMode; const TIMUIKitProfile( diff --git a/lib/ui/views/TIMUIKitProfile/widget/tim_uikit_profile_userinfo_card/tim_uikit_profile_userinfo_card.dart b/lib/ui/views/TIMUIKitProfile/widget/tim_uikit_profile_userinfo_card/tim_uikit_profile_userinfo_card.dart index 6e40ca1..d858778 100644 --- a/lib/ui/views/TIMUIKitProfile/widget/tim_uikit_profile_userinfo_card/tim_uikit_profile_userinfo_card.dart +++ b/lib/ui/views/TIMUIKitProfile/widget/tim_uikit_profile_userinfo_card/tim_uikit_profile_userinfo_card.dart @@ -27,6 +27,7 @@ class TIMUIKitProfileUserInfoCard extends StatelessWidget { @override Widget build(BuildContext context) { return TUIKitScreenUtils.getDeviceWidget( + context: context, defaultWidget: TIMUIKitProfileUserInfoCardNarrow( userInfo: userInfo, isJumpToPersonalProfile: isJumpToPersonalProfile, diff --git a/lib/ui/views/TIMUIKitSearch/pureUI/tim_uikit_search_item.dart b/lib/ui/views/TIMUIKitSearch/pureUI/tim_uikit_search_item.dart index 4a5ed9f..fb0b396 100644 --- a/lib/ui/views/TIMUIKitSearch/pureUI/tim_uikit_search_item.dart +++ b/lib/ui/views/TIMUIKitSearch/pureUI/tim_uikit_search_item.dart @@ -54,6 +54,7 @@ class TIMUIKitSearchItem extends TIMUIKitStatelessWidget { final TUITheme theme = value.theme; return TUIKitScreenUtils.getDeviceWidget( + context: context, defaultWidget: GestureDetector( onTap: onClick, child: Container( diff --git a/lib/ui/widgets/link_preview/link_preview_entry.dart b/lib/ui/widgets/link_preview/link_preview_entry.dart index 1d42689..ba0de41 100644 --- a/lib/ui/widgets/link_preview/link_preview_entry.dart +++ b/lib/ui/widgets/link_preview/link_preview_entry.dart @@ -10,13 +10,16 @@ class LinkPreviewEntry { /// get the text message with hyperlinks static LinkPreviewText? getHyperlinksText(String messageText, bool isMarkdown, {Function(String)? onLinkTap, - bool? isEnableTextSelection, + bool isEnableTextSelection = false, bool isUseDefaultEmoji = false, List customEmojiStickerList = const []}) { return ({TextStyle? style}) { return isMarkdown ? LinkTextMarkdown( - messageText: messageText, style: style, onLinkTap: onLinkTap) + isEnableTextSelection: isEnableTextSelection, + messageText: replaceSingleNewlineWithTwo(messageText), + style: style, + onLinkTap: onLinkTap) : LinkText( isEnableTextSelection: isEnableTextSelection, messageText: messageText, @@ -27,6 +30,13 @@ class LinkPreviewEntry { }; } + static String replaceSingleNewlineWithTwo(String inputText) { + return inputText.replaceAllMapped( + RegExp(r'(? '\n\n', + ); + } + /// get the [LinkPreviewContent] with preview widget and website information for the first link. /// If you provide `onUpdateMessage(String linkInfoJson)`, it can save the link info to local custom data than call updating the message on UI automatically. static Future getFirstLinkPreviewContent( diff --git a/lib/ui/widgets/link_preview/widgets/link_text.dart b/lib/ui/widgets/link_preview/widgets/link_text.dart index a039b46..3460a3d 100644 --- a/lib/ui/widgets/link_preview/widgets/link_text.dart +++ b/lib/ui/widgets/link_preview/widgets/link_text.dart @@ -1,8 +1,7 @@ // ignore_for_file: deprecated_member_use import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; -import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; -import 'package:tencent_extended_text/extended_text.dart'; +import 'package:extended_text/extended_text.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; @@ -20,14 +19,21 @@ class LinkTextMarkdown extends TIMStatelessWidget { /// text style for default words final TextStyle? style; + final bool? isEnableTextSelection; + const LinkTextMarkdown( - {Key? key, required this.messageText, this.onLinkTap, this.style}) + {Key? key, + required this.messageText, + this.isEnableTextSelection, + this.onLinkTap, + this.style}) : super(key: key); @override Widget timBuild(BuildContext context) { return MarkdownBody( data: messageText, + selectable: isEnableTextSelection ?? false, styleSheet: MarkdownStyleSheet.fromTheme(ThemeData( textTheme: TextTheme( bodyText2: style ?? const TextStyle(fontSize: 16.0)))) @@ -40,9 +46,9 @@ class LinkTextMarkdown extends TIMStatelessWidget { String title, ) { if (onLinkTap != null) { - onLinkTap!(link); + onLinkTap!(href ?? ""); } else { - LinkUtils.launchURL(context, link); + LinkUtils.launchURL(context, href ?? ""); } }, ); @@ -130,15 +136,8 @@ class LinkText extends TIMStatelessWidget { @override Widget timBuild(BuildContext context) { - final isDesktopScreen = - TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; - return - // Text.rich( - // TextSpan(children: [..._getContentSpan(messageText, context)]), - // style: style ?? const TextStyle(fontSize: 16.0), - // ); - ExtendedText(_getContentSpan(messageText, context), softWrap: true, - onSpecialTextTap: (dynamic parameter) { + return ExtendedText(_getContentSpan(messageText, context), softWrap: true, + onSpecialTextTap: (dynamic parameter) { if (parameter.toString().startsWith('\$')) { if (onLinkTap != null) { onLinkTap!((parameter.toString()).replaceAll('\$', '')); @@ -148,14 +147,11 @@ class LinkText extends TIMStatelessWidget { } } }, - selectionEnabled: isEnableTextSelection != null - ? isEnableTextSelection! - : isDesktopScreen, - style: style ?? const TextStyle(fontSize: 16.0), - specialTextSpanBuilder: DefaultSpecialTextSpanBuilder( - isUseDefaultEmoji: isUseDefaultEmoji, - customEmojiStickerList: customEmojiStickerList, - showAtBackground: true, - )); + style: style ?? const TextStyle(fontSize: 16.0), + specialTextSpanBuilder: DefaultSpecialTextSpanBuilder( + isUseDefaultEmoji: isUseDefaultEmoji, + customEmojiStickerList: customEmojiStickerList, + showAtBackground: true, + )); } } diff --git a/lib/ui/widgets/merger_message_screen.dart b/lib/ui/widgets/merger_message_screen.dart index d086f10..074cbca 100644 --- a/lib/ui/widgets/merger_message_screen.dart +++ b/lib/ui/widgets/merger_message_screen.dart @@ -305,6 +305,7 @@ class MergerMessageScreenState extends TIMUIKitState { } return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: Container( padding: const EdgeInsets.symmetric(horizontal: 16), child: messageListPage(), diff --git a/lib/ui/widgets/message_read_receipt.dart b/lib/ui/widgets/message_read_receipt.dart index 473ebff..be96585 100644 --- a/lib/ui/widgets/message_read_receipt.dart +++ b/lib/ui/widgets/message_read_receipt.dart @@ -362,6 +362,7 @@ class _MessageReadReceiptState extends TIMUIKitState { } return TUIKitScreenUtils.getDeviceWidget( + context: context, desktopWidget: pageBody(), defaultWidget: DefaultTabController( length: 2, diff --git a/lib/ui/widgets/text_input_bottom_sheet.dart b/lib/ui/widgets/text_input_bottom_sheet.dart index 76f9b0e..559624b 100644 --- a/lib/ui/widgets/text_input_bottom_sheet.dart +++ b/lib/ui/widgets/text_input_bottom_sheet.dart @@ -227,7 +227,7 @@ class TextInputBottomSheet { ), )); }); - Overlay.of(context)?.insert(entry!); + Overlay.of(context).insert(entry!); } else { showModalBottomSheet( isScrollControlled: true, // !important diff --git a/lib/ui/widgets/transimit_group_owner_select.dart b/lib/ui/widgets/transimit_group_owner_select.dart index 8dbe873..2d29902 100644 --- a/lib/ui/widgets/transimit_group_owner_select.dart +++ b/lib/ui/widgets/transimit_group_owner_select.dart @@ -116,6 +116,7 @@ class _SelectNewGroupOwner extends TIMUIKitState { } return TUIKitScreenUtils.getDeviceWidget( + context: context, defaultWidget: Scaffold( appBar: AppBar( shadowColor: theme.weakBackgroundColor, diff --git a/lib/ui/widgets/video_custom_control.dart b/lib/ui/widgets/video_custom_control.dart index db4ce5c..f696220 100644 --- a/lib/ui/widgets/video_custom_control.dart +++ b/lib/ui/widgets/video_custom_control.dart @@ -2,10 +2,10 @@ import 'dart:async'; -import 'package:chewie/chewie.dart'; -import 'package:chewie/src/helpers/utils.dart'; -import 'package:chewie/src/animated_play_pause.dart'; -import 'package:chewie/src/material/material_progress_bar.dart'; +import 'package:chewie_for_us/chewie_for_us.dart'; +import 'package:chewie_for_us/src/helpers/utils.dart'; +import 'package:chewie_for_us/src/animated_play_pause.dart'; +import 'package:chewie_for_us/src/material/material_progress_bar.dart'; import 'package:flutter/material.dart'; import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; diff --git a/lib/ui/widgets/video_screen.dart b/lib/ui/widgets/video_screen.dart index 933cfd3..c43abe4 100644 --- a/lib/ui/widgets/video_screen.dart +++ b/lib/ui/widgets/video_screen.dart @@ -12,7 +12,7 @@ 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; -import 'package:chewie/chewie.dart'; +import 'package:chewie_for_us/chewie_for_us.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/permission.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; @@ -89,7 +89,7 @@ class _VideoScreenState extends TIMUIKitState { } else { final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; - if ((androidInfo.version.sdkInt ?? 0) >= 33) { + if ((androidInfo.version.sdkInt) >= 33) { final videos = await Permissions.checkPermission( context,Permission.videos.value, ); diff --git a/lib/ui/widgets/wide_popup.dart b/lib/ui/widgets/wide_popup.dart index e866ac0..5b023ee 100644 --- a/lib/ui/widgets/wide_popup.dart +++ b/lib/ui/widgets/wide_popup.dart @@ -88,142 +88,145 @@ class TUIKitWidePopup { return; } entry = OverlayEntry(builder: (BuildContext context) { - return TUIKitDragArea( - backgroundColor: isDarkBackground ? const Color(0x7F000000) : null, - closeFun: () { - if (entry != null) { - entry?.remove(); - entry = null; - } - }, - initOffset: offset ?? - (width != null && height != null - ? Offset(MediaQuery.of(context).size.width * 0.5 - width / 2, - MediaQuery.of(context).size.height * 0.5 - height / 2) - : null), - child: Container( - width: width, - height: height, - decoration: BoxDecoration( - borderRadius: - borderRadius ?? const BorderRadius.all(Radius.circular(16)), - color: theme?.wideBackgroundColor ?? const Color(0xFFffffff), - border: isDarkBackground - ? Border.all( - width: 2, - color: - theme?.weakBackgroundColor ?? const Color(0xFFbebebe), - ) - : null, - boxShadow: isDarkBackground - ? null - : const [ - BoxShadow( - color: Color(0xFFbebebe), - offset: Offset(3, 3), - blurRadius: 10, - spreadRadius: 1, - ), - ], - ), - child: Column( - children: [ - if (title != null) - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: hexToColor("f5f6f7"), - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.max, - children: [ - Text( - title, - style: TextStyle( - fontSize: 18, - color: theme?.darkTextColor ?? - const Color(0xFF444444)), - ), - InkWell( - onTap: () { - if (onSubmit != null) { - onSubmit(); - } - entry?.remove(); - entry = null; - }, - child: onSubmit != null - ? (submitWidget ?? const Icon(Icons.check)) - : const Icon(Icons.close), - ) - ], - ), + return Material( + color: Colors.transparent, + child: TUIKitDragArea( + backgroundColor: isDarkBackground ? const Color(0x7F000000) : null, + closeFun: () { + if (entry != null) { + entry?.remove(); + entry = null; + } + }, + initOffset: offset ?? + (width != null && height != null + ? Offset(MediaQuery.of(context).size.width * 0.5 - width / 2, + MediaQuery.of(context).size.height * 0.5 - height / 2) + : null), + child: Container( + width: width, + height: height, + decoration: BoxDecoration( + borderRadius: + borderRadius ?? const BorderRadius.all(Radius.circular(16)), + color: theme?.wideBackgroundColor ?? const Color(0xFFffffff), + border: isDarkBackground + ? Border.all( + width: 2, + color: + theme?.weakBackgroundColor ?? const Color(0xFFbebebe), + ) + : null, + boxShadow: isDarkBackground + ? null + : const [ + BoxShadow( + color: Color(0xFFbebebe), + offset: Offset(3, 3), + blurRadius: 10, + spreadRadius: 1, ), - if (title != null) - SizedBox( - height: 1, - child: Container( - color: theme?.weakDividerColor ?? const Color(0xFFE5E6E9), - ), - ), - if (height != null && width != null) - Expanded(child: child(() { - entry?.remove(); - entry = null; - })), - if (height == null || width == null) - child(() { - entry?.remove(); - entry = null; - }), - if (onCancel != null || onConfirm != null) - Container( - padding: const EdgeInsets.only(bottom: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (onCancel != null) - Container( - margin: const EdgeInsets.only(right: 16), - child: OutlinedButton( - onPressed: () { - entry?.remove(); - entry = null; - onCancel(); - }, - child: Text( - TIM_t("取消"), - style: TextStyle( - color: - theme?.weakTextColor ?? Colors.black), - )), + ], + ), + child: Column( + children: [ + if (title != null) + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: hexToColor("f5f6f7"), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Text( + title, + style: TextStyle( + fontSize: 18, + color: theme?.darkTextColor ?? + const Color(0xFF444444)), ), - if (onConfirm != null) - Container( - margin: const EdgeInsets.only(right: 16), - child: ElevatedButton( - onPressed: () { - entry?.remove(); - entry = null; - onConfirm(); - }, - child: Text( - TIM_t("确定"), - style: TextStyle(color: theme?.primaryColor), - )), - ), - ], + InkWell( + onTap: () { + if (onSubmit != null) { + onSubmit(); + } + entry?.remove(); + entry = null; + }, + child: onSubmit != null + ? (submitWidget ?? const Icon(Icons.check)) + : const Icon(Icons.close), + ) + ], + ), ), - ) - ], - ), - )); + if (title != null) + SizedBox( + height: 1, + child: Container( + color: theme?.weakDividerColor ?? const Color(0xFFE5E6E9), + ), + ), + if (height != null && width != null) + Expanded(child: child(() { + entry?.remove(); + entry = null; + })), + if (height == null || width == null) + child(() { + entry?.remove(); + entry = null; + }), + if (onCancel != null || onConfirm != null) + Container( + padding: const EdgeInsets.only(bottom: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (onCancel != null) + Container( + margin: const EdgeInsets.only(right: 16), + child: OutlinedButton( + onPressed: () { + entry?.remove(); + entry = null; + onCancel(); + }, + child: Text( + TIM_t("取消"), + style: TextStyle( + color: + theme?.weakTextColor ?? Colors.black), + )), + ), + if (onConfirm != null) + Container( + margin: const EdgeInsets.only(right: 16), + child: ElevatedButton( + onPressed: () { + entry?.remove(); + entry = null; + onConfirm(); + }, + child: Text( + TIM_t("确定"), + style: TextStyle(color: theme?.primaryColor), + )), + ), + ], + ), + ) + ], + ), + )), + ); }); - Overlay.of(context)?.insert(entry!); + Overlay.of(context).insert(entry!); } } diff --git a/pub b/pub deleted file mode 100644 index e69de29..0000000 diff --git a/pubspec.lock b/pubspec.lock index 48af976..d87d9fb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "3444216bfd127af50bbe4862d8843ed44db946dd933554f0d7285e89f10e28ac" + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a url: "https://pub.dev" source: hosted - version: "50.0.0" + version: "61.0.0" adaptive_action_sheet: dependency: "direct main" description: @@ -21,26 +21,26 @@ packages: dependency: transitive description: name: analyzer - sha256: "68796c31f510c8455a06fed75fc97d8e5ad04d324a830322ab3efc9feb6201c1" + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.13.0" args: dependency: transitive description: name: args - sha256: b003c3098049a51720352d219b0bb5f219b60fbfb68e7a4748139a06a5676515 + sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.1" async: dependency: transitive description: name: async - sha256: "271b8899fc99f9df4f4ed419fa14e2fff392c7b2c162fbb87b222e2e963ddc73" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.11.0" audioplayers: dependency: "direct main" description: @@ -105,14 +105,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" build: dependency: transitive description: name: build - sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.0" build_config: dependency: transitive description: @@ -125,34 +133,34 @@ packages: dependency: transitive description: name: build_daemon - sha256: "757153e5d9cd88253cb13f28c2fb55a537dc31fefd98137549895b5beb7c6169" + sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "4.0.0" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6" + sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95 url: "https://pub.dev" source: hosted - version: "2.0.10" + version: "2.2.0" build_runner: dependency: "direct dev" description: name: build_runner - sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.4" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292" + sha256: "88a57f2ac99849362e73878334caa9f06ee25f31d2adced882b8337838c84e1e" url: "https://pub.dev" source: hosted - version: "7.2.7" + version: "7.2.9" built_collection: dependency: transitive description: @@ -165,82 +173,82 @@ packages: dependency: transitive description: name: built_value - sha256: "31b7c748fd4b9adf8d25d72a4c4a59ef119f12876cf414f94f8af5131d5fa2b0" + sha256: "7dd62d9faf105c434f3d829bbe9c4be02ec67f5ed94832222116122df67c5452" url: "https://pub.dev" source: hosted - version: "8.4.4" + version: "8.6.0" cached_network_image: dependency: "direct main" description: name: cached_network_image - sha256: e764e48ef036cabdf84319ba7b8b5871b6b43266e14de787cb43f77639089ae5 + sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.3" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: "8e2b5befefec5063bee8f209fda21751f6328d405d4237c70f21104568b2fee7" + sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7 url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "2.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: d4351c7eb16767df129b0474a5ebc4e028870379c063e8ba265a56aa00831e70 + sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0 url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" camera: dependency: transitive description: name: camera - sha256: ad1c53c554a2f3e5708f3b01eb738d60b902bb61f7f4ad420c65c715e65a7379 + sha256: ebebead3d5ec3d148249331d751d462d7e8c98102b8830a9b45ec96a2bd4333f url: "https://pub.dev" source: hosted - version: "0.10.3+2" + version: "0.10.5+2" camera_android: dependency: transitive description: name: camera_android - sha256: "16e46b32915fcbc53afc1f96ca868cd91495608935a20bd16f47b854bfed9b17" + sha256: f83e406d34f5faa80bf0f5c3beee4b4c11da94a94e9621c1bb8e312988621b4b url: "https://pub.dev" source: hosted - version: "0.10.4+3" + version: "0.10.8+2" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: c328d477e5af88b3edcf277183c3b68f6e73b0f4e4e1053a22026e1c175e5bdb + sha256: "1a416e452b30955b392f4efbf23291d3f2ba3660a85e1628859eb62d2a2bab26" url: "https://pub.dev" source: hosted - version: "0.9.11+1" + version: "0.9.13+2" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: "00d972adee2e8a282b4d7445e8e694aa1dc0c36b70455b99afa96fbf5e814119" + sha256: "60fa0bb62a4f3bf3a7c413e31e4cd01b69c779ccc8e4668904a24581b86c316b" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.5.1" camera_web: dependency: transitive description: name: camera_web - sha256: d77965f32479ee6d8f48205dcf10f845d7210595c6c00faa51eab265d1cae993 + sha256: bcbd775fb3a9d51cc3ece899d54ad66f6306410556bac5759f78e13f9228841f url: "https://pub.dev" source: hosted - version: "0.3.1+3" + version: "0.3.1+4" characters: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" charcode: dependency: transitive description: @@ -253,18 +261,18 @@ packages: dependency: transitive description: name: checked_yaml - sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659 + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted - version: "2.0.1" - chewie: + version: "2.0.3" + chewie_for_us: dependency: "direct main" description: - name: chewie - sha256: e9da4898ee4859825404f507969f57113c04ca0060e152b95c9afd73934126ad + name: chewie_for_us + sha256: "0307723e811508d361fffa6f8bbd9040b1bfea5536544e4d655e10c27de002ec" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" clock: dependency: transitive description: @@ -285,18 +293,18 @@ packages: dependency: "direct main" description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" convert: dependency: transitive description: name: convert - sha256: "1be13198012c1d5bc042dc40ad1d7f16cbd522350984c0c1abf471d6d7e305c6" + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" cross_file: dependency: "direct main" description: @@ -309,26 +317,26 @@ packages: dependency: "direct main" 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: name: csslib - sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f" url: "https://pub.dev" source: hosted - version: "0.17.2" + version: "0.17.3" csv: 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: transitive description: @@ -341,10 +349,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "5be16bf1707658e4c03078d4a9b90208ded217fb02c163e207d334082412f2fb" + sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad url: "https://pub.dev" source: hosted - version: "2.2.5" + version: "2.3.1" desktop_drop: dependency: "direct main" description: @@ -357,50 +365,18 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: b809c4ed5f7fcdb325ccc70b80ad934677dc4e2aa414bf46859a42bfdfafcbb6 + sha256: "499c61743e13909c13374a8c209075385858c614b9c0f2487b5f9995eeaf7369" url: "https://pub.dev" source: hosted - version: "4.1.3" - device_info_plus_linux: - dependency: transitive - description: - name: device_info_plus_linux - sha256: "77a8b3c4af06bc46507f89304d9f49dfc64b4ae004b994532ed23b34adeae4b3" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - device_info_plus_macos: - dependency: transitive - description: - name: device_info_plus_macos - sha256: "37961762fbd46d3620c7b69ca606671014db55fc1b7a11e696fd90ed2e8fe03d" - url: "https://pub.dev" - source: hosted - version: "3.0.0" + version: "9.0.1" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: "83fdba24fcf6846d3b10f10dfdc8b6c6d7ada5f8ed21d62ea2909c2dfa043773" + sha256: d3b01d5868b50ae571cd1dc6e502fc94d956b665756180f7b16ead09e836fd64 url: "https://pub.dev" source: hosted - version: "3.0.0" - device_info_plus_web: - dependency: transitive - description: - name: device_info_plus_web - sha256: "5890f6094df108181c7a29720bc23d0fd6159f17d82787fac093d1fefcaf6325" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - device_info_plus_windows: - dependency: transitive - description: - name: device_info_plus_windows - sha256: "23a2874af0e23ee6e3a2a0ebcecec3a9da13241f2cb93a93a44c8764df123dd7" - url: "https://pub.dev" - source: hosted - version: "4.1.0" + version: "7.0.0" diff_match_patch: dependency: "direct main" description: @@ -429,18 +405,42 @@ packages: dependency: "direct main" description: name: extended_image - sha256: a417f57e0434fc739c435e456ceace53753304157e85f77acaa680b266d4a7d8 + sha256: "73b7051722be79f9e8f8c120951fd9d3b22e6153fda6105c322fb88c066952d6" url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "8.0.1" extended_image_library: dependency: transitive description: name: extended_image_library - sha256: "83285a9286db7d96154dc427d9c56cf00fb5931a2ce369efb707804d7461a896" + sha256: f2eba5c8500c5a7ce1f0db703b787756cb3bc65cd3818636d5fe9a9ace011ee3 url: "https://pub.dev" source: hosted - version: "3.3.0" + version: "3.5.1" + extended_text: + dependency: "direct main" + description: + name: extended_text + sha256: "75ddf28ce7d5be33a050ff2179b6567b4b98e6225ad3e61e4c3748f7448c25f7" + url: "https://pub.dev" + source: hosted + version: "11.0.0" + extended_text_field: + dependency: "direct main" + description: + name: extended_text_field + sha256: "6cf8c090de4dc1e309cf3b24cb9448d7463c6c17926b628cf0954631bf4e56db" + url: "https://pub.dev" + source: hosted + version: "12.0.0" + extended_text_library: + dependency: transitive + description: + name: extended_text_library + sha256: "308b50cfcc8e3accf46a09cb692715fbd1097333817c15b0f7527de1766bc1ff" + url: "https://pub.dev" + source: hosted + version: "11.0.1" fast_i18n: dependency: "direct dev" description: @@ -461,10 +461,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: @@ -477,26 +477,18 @@ packages: dependency: "direct main" description: name: file_picker - sha256: dcde5ad1a0cebcf3715ea3f24d0db1888bf77027a26c77d7779e8ef63b8ade62 + sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf" url: "https://pub.dev" source: hosted - version: "5.2.9" - file_utils: - dependency: transitive - description: - name: file_utils - sha256: d1e64389a22649095c8405c9e177272caf05139255931c9ff30d53b5c9bcaa34 - url: "https://pub.dev" - source: hosted - version: "1.0.1" + version: "5.3.1" fixnum: dependency: transitive description: name: fixnum - sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec" + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" flutter: dependency: "direct main" description: flutter @@ -554,10 +546,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: c224ac897bed083dabf11f238dd11a239809b446740be0c2044608c50029ffdf + sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.0.15" flutter_plugin_record_plus: dependency: "direct main" description: @@ -599,58 +591,50 @@ packages: dependency: "direct main" 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" - globbing: - dependency: transitive - description: - name: globbing - sha256: "4f89cfaf6fa74c9c1740a96259da06bd45411ede56744e28017cc534a12b6e2d" - url: "https://pub.dev" - source: hosted - version: "1.0.0" + version: "2.1.2" graphs: dependency: transitive description: name: graphs - sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.1" html: dependency: transitive description: name: html - sha256: "79d498e6d6761925a34ee5ea8fa6dfef38607781d2fa91e37523474282af55cb" + sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8" url: "https://pub.dev" source: hosted - version: "0.15.2" + version: "0.15.3" http: dependency: "direct main" 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_multi_server: dependency: transitive description: @@ -679,18 +663,18 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "64b21d9f0e065f9ab0e4dde458076226c97382cc0c6949144cb874c62bf8e9f8" + sha256: "9978d3510af4e6a902e545ce19229b926e6de6a1828d6134d3aab2e129a4d270" url: "https://pub.dev" source: hosted - version: "0.8.7" + version: "0.8.7+5" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "420ed22d2c9ce767ed96df723aaebfeb20ce92dfda8665cd2ba72d72a51ae669" + sha256: c2f3c66400649bd132f721c88218945d6406f693092b2f741b79ae9cdb046e59 url: "https://pub.dev" source: hosted - version: "0.8.6+1" + version: "0.8.6+16" image_picker_for_web: dependency: transitive description: @@ -703,10 +687,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: "39aa70b5f1e5e7c94585b9738632d5fdb764a5655e40cd9e7b95fbd2fc50c519" + sha256: d779210bda268a03b57e923fb1e410f32f5c5e708ad256348bcbf1f44f558fd0 url: "https://pub.dev" source: hosted - version: "0.8.6+9" + version: "0.8.7+4" image_picker_platform_interface: dependency: transitive description: @@ -719,10 +703,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.18.1" io: dependency: transitive description: @@ -735,18 +719,18 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" json_annotation: dependency: transitive description: name: json_annotation - sha256: "3520fa844009431b5d4491a5a778603520cdc399ab3406332dcc50f93547258c" + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.8.1" link_preview_generator: dependency: "direct main" description: @@ -775,10 +759,10 @@ packages: dependency: transitive description: name: logging - sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946 + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" lpinyin: dependency: "direct main" description: @@ -791,18 +775,18 @@ packages: dependency: transitive description: name: markdown - sha256: b3c60dee8c2af50ad0e6e90cceba98e47718a6ee0a7a6772c77846a0cc21f78b + sha256: "8e332924094383133cee218b676871f42db2514f1f6ac617b6cf6152a7faab8e" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.1.0" matcher: dependency: transitive description: name: matcher - sha256: "80c2989398773fa06e2457e9ff08580f24e9858b28462a722241cb53e5613478" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -815,18 +799,18 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" mime: dependency: transitive description: name: mime - sha256: "52e38f7e1143ef39daf532117d6b8f8f617bf4bcd6044ed8c29040d20d269630" + sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" nested: dependency: transitive description: @@ -855,50 +839,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: f62d7253edc197fe3c88d7c2ddab82d68f555e778d55390ccc3537eca8e8d637 + sha256: "28386bbe89ab5a7919a47cea99cdd1128e5a6e0bbd7eaafe20440ead84a15de3" url: "https://pub.dev" source: hosted - version: "1.4.3+1" - package_info_plus_linux: - dependency: transitive - description: - name: package_info_plus_linux - sha256: "04b575f44233d30edbb80a94e57cad9107aada334fc02aabb42b6becd13c43fc" - url: "https://pub.dev" - source: hosted - version: "1.0.5" - package_info_plus_macos: - dependency: transitive - description: - name: package_info_plus_macos - sha256: a2ad8b4acf4cd479d4a0afa5a74ea3f5b1c7563b77e52cc32b3ee6956d5482a6 - url: "https://pub.dev" - source: hosted - version: "1.3.0" + version: "4.0.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: f7a0c8f1e7e981bc65f8b64137a53fd3c195b18d429fba960babc59a5a1c7ae8 + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" url: "https://pub.dev" source: hosted - version: "1.0.2" - package_info_plus_web: - dependency: transitive - description: - name: package_info_plus_web - sha256: f0829327eb534789e0a16ccac8936a80beed4e2401c4d3a74f3f39094a822d3b - url: "https://pub.dev" - source: hosted - version: "1.0.6" - package_info_plus_windows: - dependency: transitive - description: - name: package_info_plus_windows - sha256: "79524f11c42dd9078b96d797b3cf79c0a2883a50c4920dc43da8562c115089bc" - url: "https://pub.dev" - source: hosted - version: "2.1.0" + version: "2.0.1" pasteboard: dependency: "direct main" description: @@ -911,10 +863,10 @@ packages: dependency: "direct main" description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_drawing: dependency: transitive description: @@ -935,34 +887,34 @@ packages: dependency: "direct main" description: name: path_provider - sha256: "04890b994ee89bfa80bf3080bfec40d5a92c5c7a785ebb02c13084a099d2b6f9" + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.0.15" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "019f18c9c10ae370b08dce1f3e3b73bc9f58e7f087bb5e921f06529438ac0ae7" + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" url: "https://pub.dev" source: hosted - version: "2.0.24" + version: "2.0.27" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "026b97a6c29da75181a37aae2eba9227f5fe13cb2838c6b975ce209328b8ab4e" + sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.2.3" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 url: "https://pub.dev" source: hosted - version: "2.1.10" + version: "2.1.11" path_provider_platform_interface: dependency: transitive description: @@ -975,10 +927,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130 + sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.1.6" pedantic: dependency: transitive description: @@ -999,18 +951,18 @@ packages: dependency: transitive description: name: permission_handler_android - sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2" + sha256: d8cc6a62ded6d0f49c6eac337e080b066ee3bce4d405bd9439a61e1f1927bfe8 url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.2.1" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: "9c370ef6a18b1c4b2f7f35944d644a56aa23576f23abee654cf73968de93f163" + sha256: ee96ac32f5a8e6f80756e25b25b9f8e535816c8e6665a96b6d70681f8c4f7e85 url: "https://pub.dev" source: hosted - version: "9.0.7" + version: "9.0.8" permission_handler_platform_interface: dependency: transitive description: @@ -1031,18 +983,18 @@ packages: dependency: transitive description: name: petitparser - sha256: "2ebb289dc4764ec397f5cd3ca9881c6d17196130a7d646ed022a0dd9c2e25a71" + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.4.0" photo_manager: dependency: transitive description: name: photo_manager - sha256: "55d50ad1b8f984c57fa7c4bd4980f4760e80d3d9355263cf72624a6ff1bf2b5b" + sha256: bdc4ab1fa9fb064d8ccfea6ab44119f55b220293d7ce2e19eb5a5f998db86c88 url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.6.0" platform: dependency: transitive description: @@ -1087,18 +1039,18 @@ 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" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.3" quiver: dependency: transitive description: @@ -1135,74 +1087,74 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: ee6257848f822b8481691f20c3e6d2bfee2e9eccb2a3d249907fcfb198c55b41 + sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022" url: "https://pub.dev" source: hosted - version: "2.0.18" + version: "2.1.1" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: ad423a80fe7b4e48b50d6111b3ea1027af0e959e49d485712e134863d9c1c521 + sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749" url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.1.4" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "1e755f8583229f185cfca61b1d80fb2344c9d660e1c69ede5450d8f478fa5310" + sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.2.2" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "3a59ed10890a8409ad0faad7bb2957dab4b92b8fbe553257b05d30ed8af2c707" + sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.2.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "824bfd02713e37603b2bdade0842e47d56e7db32b1dcdd1cae533fb88e2913fc" + sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: "0dc2633f215a3d4aa3184c9b2c5766f4711e4e5a6b256e62aafee41f89f1bfb8" + sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.1.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "71bcd669bb9cdb6b39f22c4a7728b6d49e934f6cba73157ffa5a54f1eed67436" + sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.2.0" shelf: dependency: transitive description: name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" shell: dependency: transitive description: @@ -1228,26 +1180,26 @@ packages: dependency: transitive description: name: sqflite - sha256: b3a8307b9519af28518e271e548594bdc435225fc77e8fb22e71a296c69281cf + sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9 url: "https://pub.dev" source: hosted - version: "2.0.3+1" + version: "2.2.8+4" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "4aa3b917d48f9a3161419efa4a901e33a38721bf9a7465e7e07d2d6ef8895276" + sha256: e77abf6ff961d69dfef41daccbb66b51e9983cdd5cb35bf30733598057401555 url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.5" stack_trace: dependency: transitive description: name: stack_trace - sha256: f8d9f247e2f9f90e32d1495ff32dac7e4ae34ffa7194c5ff8fcc0fd0e52df774 + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: @@ -1268,82 +1220,50 @@ packages: dependency: transitive description: name: string_scanner - sha256: "862015c5db1f3f3c4ea3b94dc2490363a84262994b88902315ed74be1155612f" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" synchronized: dependency: transitive description: name: synchronized - sha256: "7b530acd9cb7c71b0019a1e7fa22c4105e675557a4400b6a401c71c5e0ade1ac" + sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" url: "https://pub.dev" source: hosted - version: "3.0.0+3" - system_info2: - dependency: transitive - description: - name: system_info2 - sha256: "90621f3ba586e1f268e38cc7951b172cd4d997e43dc1fbed12eb334c8a22a886" - url: "https://pub.dev" - source: hosted - version: "2.0.4" + version: "3.1.0" tencent_cloud_chat_sdk: dependency: transitive description: name: tencent_cloud_chat_sdk - sha256: "765a93262a41080e155ce5b8a6ca20147a81c7d306f7f87444077c5eaae87e08" + sha256: f98bdb55164051e2b196cac6e2e79e60248ed8351dc5a91d25568712ccb15839 url: "https://pub.dev" source: hosted - version: "5.1.5" + version: "5.1.7" tencent_cloud_uikit_core: dependency: "direct main" description: name: tencent_cloud_uikit_core - sha256: "829dfde0c4fbdae019ba233f7f2c299e7cbd18c3ae20ecfe3ab4a43084a33064" + sha256: "0131874c7b15e181001c94f8a668f0ccae3006dea6e70d4e42e5531b63313a27" url: "https://pub.dev" source: hosted - version: "1.0.2" - tencent_extended_text: - dependency: "direct main" - description: - name: tencent_extended_text - sha256: "2904d064eeb9d3395f7d31bdc9f168ee75e7783f20161b1a6eb4647677a56721" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - tencent_extended_text_field: - dependency: "direct main" - description: - name: tencent_extended_text_field - sha256: "4bb5bb3863792b7cee48d76cd100b0084906baa2bf4e1a917283f5de62076b0b" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - tencent_extended_text_library: - dependency: transitive - description: - name: tencent_extended_text_library - sha256: d6dad4e4e426e6319db809267f160082c44a334716e9f8593fac56d65ae75545 - url: "https://pub.dev" - source: hosted - version: "1.0.0" + version: "1.0.4" tencent_im_base: dependency: "direct main" description: name: tencent_im_base - sha256: "516356a80f43b94a6c0719b54e4c641cb1f164830b2b3e887d175ae862ebab3f" + sha256: "9b8e712bf27ffae9b686ec532ee8417b8263eba8bab04f105e28a95de1807322" url: "https://pub.dev" source: hosted - version: "1.0.51" + version: "1.0.57" tencent_im_sdk_plugin_platform_interface: dependency: transitive description: name: tencent_im_sdk_plugin_platform_interface - sha256: "04043582f1af698b4abe12d53cd0f043466228fae712677688988d8ff7bfc1f1" + sha256: "6a1f053567246148ad40667f2ab71d82bcee0d5d0c12e587340d2796c342b87e" url: "https://pub.dev" source: hosted - version: "0.3.19" + version: "0.3.21" tencent_keyboard_visibility: dependency: "direct main" description: @@ -1368,14 +1288,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.1" - tencent_wechat_camera_picker: - dependency: "direct main" - description: - name: tencent_wechat_camera_picker - sha256: "6a6fd12d61ad2ef17273a226a165fe0b5e3ef5c7e49779de38503e4f4b6e3ef1" - url: "https://pub.dev" - source: hosted - version: "3.6.5+2" term_glyph: dependency: transitive description: @@ -1384,6 +1296,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + url: "https://pub.dev" + source: hosted + version: "0.5.1" tim_ui_kit_sticker_plugin: dependency: "direct main" description: @@ -1420,18 +1340,18 @@ packages: 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: "direct main" description: name: universal_html - sha256: ed4f24120c9b1b4721d44e439f7a47d09d9f1b7b868bc84c9d6d373a4a8732af + sha256: f2e0ff0c4af8e4bbda4d273ca4a11be4055414f478fad5c161609b74790ff696 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" universal_io: dependency: transitive description: @@ -1444,42 +1364,42 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "75f2846facd11168d007529d6cd8fcb2b750186bea046af9711f10b907e1587e" + sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 url: "https://pub.dev" source: hosted - version: "6.1.10" + version: "6.1.11" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "845530e5e05db5500c1a4c1446785d60cbd8f9bd45e21e7dd643a3273bb4bbd1" + sha256: eed4e6a1164aa9794409325c3b707ff424d4d1c2a785e7db67f8bbda00e36e51 url: "https://pub.dev" source: hosted - version: "6.0.25" + version: "6.0.35" 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: "206fb8334a700ef7754d6a9ed119e7349bc830448098f21a69bf1b4ed038cabc" + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "0ef2b4f97942a16523e51256b799e9aa1843da6c60c55eefbfa9dbc2dcb8331a" + sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.5" url_launcher_platform_interface: dependency: transitive description: @@ -1492,18 +1412,18 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "81fe91b6c4f84f222d186a9d23c73157dc4c8e1c71489c4d08be1ad3b228f1aa" + sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab" url: "https://pub.dev" source: hosted - version: "2.0.16" + version: "2.0.17" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: a83ba3607a507758669cfafb03f9de09bf6e6280c14d9b9cb18f013e406dcacd + sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" uuid: dependency: "direct main" description: @@ -1524,58 +1444,50 @@ packages: dependency: "direct main" description: name: video_player - sha256: "868a139229acb5018d22aded3eb9cb4767ff43a8216573c086b6c535a4957481" + sha256: de95f0e9405f29b5582573d4166132e71f83b3158aac14e8ee5767a54f4f1fbd url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.6.1" video_player_android: dependency: transitive description: name: video_player_android - sha256: dc31c60ae591aa3ccb2d460c3690ceceb86cbb826e73428d817a37650dc4e229 + sha256: ae1c7d9a71c236a1bf9e567bd7ed4c90887e389a5f233b2192593f7f7395005c url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.8" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: "5df5411ff9d316f1dcbfee284e9838aa686e314f2a722b15c02cb7ce40ef9446" + sha256: "4c274e439f349a0ee5cb3c42978393ede173a443b98f50de6ffe6900eaa19216" url: "https://pub.dev" source: hosted - version: "2.3.9" + version: "2.4.6" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - sha256: "72ba04ad0eff76123c6d782ac46621cb8be476a89c33c89173fce982b6ec049b" + sha256: a8c4dcae2a7a6e7cc1d7f9808294d968eca1993af34a98e95b9bdfa959bec684 url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "6.1.0" video_player_web: dependency: transitive description: name: video_player_web - sha256: fb3bbeaf0302cb0c31340ebd6075487939aa1fe3b379d1a8784ef852b679940e + sha256: "44ce41424d104dfb7cf6982cc6b84af2b007a24d126406025bf40de5d481c74c" url: "https://pub.dev" source: hosted - version: "2.0.15" - wakelock: + version: "2.0.16" + wakelock_for_us: dependency: transitive description: - name: wakelock - sha256: "769ecf42eb2d07128407b50cb93d7c10bd2ee48f0276ef0119db1d25cc2f87db" + name: wakelock_for_us + sha256: b73bfa90e5e764f41155063ae92fbd1e3a04ee6372e65ff7d288d2c3057f9498 url: "https://pub.dev" source: hosted - version: "0.6.2" - wakelock_macos: - dependency: transitive - description: - name: wakelock_macos - sha256: "047c6be2f88cb6b76d02553bca5a3a3b95323b15d30867eca53a19a0a319d4cd" - url: "https://pub.dev" - source: hosted - version: "0.4.0" + version: "0.6.3" wakelock_platform_interface: dependency: transitive description: @@ -1584,54 +1496,54 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" - wakelock_web: - dependency: transitive - description: - name: wakelock_web - sha256: "1b256b811ee3f0834888efddfe03da8d18d0819317f20f6193e2922b41a501b5" - url: "https://pub.dev" - source: hosted - version: "0.4.0" - wakelock_windows: - dependency: transitive - description: - name: wakelock_windows - sha256: "857f77b3fe6ae82dd045455baa626bc4b93cb9bb6c86bf3f27c182167c3a5567" - url: "https://pub.dev" - source: hosted - version: "0.2.1" watcher: dependency: transitive description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" wechat_assets_picker: dependency: "direct main" description: name: wechat_assets_picker - sha256: "49184fbc83f855bade59961566a6323a2015634ece1f889de5af6fa133a10706" + sha256: "5aeac81c6a28e1142a2c9ba9ee802b909c2dad9186d9a58dbe4eb74493af4743" url: "https://pub.dev" source: hosted - version: "7.3.4" + version: "8.5.0" + wechat_camera_picker: + dependency: "direct main" + description: + name: wechat_camera_picker + sha256: d8108ea33b1ed25933770199d08d64c210a2854bc6a326fd058a2f34dca8bf46 + url: "https://pub.dev" + source: hosted + version: "3.8.0" win32: dependency: transitive description: name: win32 - sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4 + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "4.1.4" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae" + url: "https://pub.dev" + source: hosted + version: "1.1.0" xdg_directories: dependency: transitive description: @@ -1644,18 +1556,18 @@ packages: dependency: transitive description: name: xml - sha256: ac0e3f4bf00ba2708c33fbabbbe766300e509f8c82dbd4ab6525039813f7e2fb + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.3.0" yaml: 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: ">=2.17.0 <3.0.0" - flutter: ">=3.0.0" + dart: ">=3.0.0 <4.0.0" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 47a3703..711fb42 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.0.0 +version: 2.1.0 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 @@ -14,23 +14,23 @@ platforms: windows: environment: - sdk: ">=2.17.0 <3.0.0" - flutter: ">=3.0.0" + sdk: '>=3.0.0 <4.0.0' + flutter: ">=3.10.0" dependencies: flutter: sdk: flutter adaptive_action_sheet: ^2.0.1 provider: ^6.0.1 - intl: ^0.17.0 + intl: ^0.18.0 get_it: ^7.2.0 dotted_border: ^2.0.0+2 flutter_svg: ^1.0.0 image_picker: ^0.8.5+3 - file_picker: ^5.2.9 + file_picker: ^5.3.0 tencent_super_tooltip: ^0.0.1 video_player: ^2.4.2 - chewie: ^1.3.2 + chewie_for_us: ^1.5.0 flutter_slidable_for_tencent_im: ^1.4.0 flutter_plugin_record_plus: ^0.0.15 azlistview_all_platforms: ^2.1.2 @@ -41,13 +41,13 @@ dependencies: cached_network_image: ^3.2.0 shared_preferences: ^2.0.13 scroll_to_index: ^2.1.1 - wechat_assets_picker: ^7.2.0 - tencent_wechat_camera_picker: ^3.6.5 + wechat_assets_picker: ^8.5.0 + wechat_camera_picker: ^3.8.0 flutter_easyrefresh: ^2.2.1 - extended_image: ^6.0.2+1 - tencent_extended_text_field: ^1.0.0 - tencent_extended_text: ^1.0.0 - package_info_plus: ^1.4.0 + extended_image: ^8.0.1 + extended_text_field: ^12.0.0 + extended_text: ^11.0.0 + package_info_plus: ^4.0.1 loading_animation_widget: ^1.1.0+3 permission_handler: ^10.2.0 tuple: ^2.0.0 @@ -64,14 +64,14 @@ dependencies: 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.51 + tencent_im_base: ^1.0.57 fc_native_video_thumbnail_for_us: ^0.4.8+1 audioplayers: ^3.0.1 path: ^1.8.1 tencent_cloud_uikit_core: ^1.0.2 pasteboard: ^0.2.0 desktop_drop: ^0.4.1 - device_info_plus: ^4.1.3 + device_info_plus: ^9.0.1 cross_file: ^0.3.3+4 diff_match_patch: ^0.4.1 @@ -89,6 +89,7 @@ flutter: uses-material-design: true assets: - images/ + - images/svg/ # - assets/custom_face_resource/4349/ # To add assets to your package, add an assets section, like this: diff --git a/test/tencent_cloud_chat_uikit_test.dart b/test/tencent_cloud_chat_uikit_test.dart new file mode 100644 index 0000000..a5eb090 --- /dev/null +++ b/test/tencent_cloud_chat_uikit_test.dart @@ -0,0 +1,4 @@ + +void main() { + +}