Upgrade UIKit to 2.1.3+1
This commit is contained in:
parent
085be1c0b4
commit
2fefab6196
25
CHANGELOG.md
25
CHANGELOG.md
|
|
@ -1,3 +1,28 @@
|
||||||
|
## 2.1.3+1
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* Introduced [a new custom internationalization language scheme](https://www.tencentcloud.com/document/product/1047/52154?from=pub) that supports adding language packs, adding or modifying entries, and makes customizing i18n more accessible. This feature helps your app achieve a more convenient globalization process and easier customer acquisition worldwide.
|
||||||
|
* Provided a seamless experience for previewing large images and playing videos within desktop environments (applications and web) by avoiding frequent page transitions. Enhanced the user experience for image previews and video playback. Please note that video playback is currently supported only on the web and not in desktop applications.
|
||||||
|
* Supported to integrate with the new online customer service plugin (tencent_cloud_chat_customer_service_plugin).
|
||||||
|
* Added two new life cycle hooks, `messageDidSend` and `messageShouldMount` to `ChatLifeCycle`.
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
* Optimized the usage, interface, and interaction of the sticker panel.
|
||||||
|
* Enhanced mobile video playback interaction and UI.
|
||||||
|
* Refined the error prompt when sending a 0 KB file fails.
|
||||||
|
* Enabled users to close modals on desktop by clicking the bottom gray overlay area.
|
||||||
|
* Improved the UI and interaction of image and video messages in the message list.
|
||||||
|
* Added the ability to open self-sent file messages without downloading.
|
||||||
|
* Optimized the download status animation of file messages on the web.
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Fixed an issue preventing mobile image previews from being dragged after zooming.
|
||||||
|
* Resolved an issue that might cause the message selection status not to be removed after canceling a message forward action.
|
||||||
|
* Addressed an issue that might cause the microphone usage not to end after sending a voice message, which means the microphone was not released.
|
||||||
|
|
||||||
## 2.1.2
|
## 2.1.2
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|
|
||||||
37
README.md
37
README.md
|
|
@ -1,4 +1,41 @@
|
||||||
|
<style>
|
||||||
|
.button-9 {
|
||||||
|
appearance: button;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
background-color: #1d52d9;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-width: 0;
|
||||||
|
box-shadow: rgba(50, 50, 93, .1) 0 0 0 1px inset,rgba(50, 50, 93, .1) 0 2px 5px 0,rgba(0, 0, 0, .07) 0 1px 1px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: -apple-system,system-ui,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif;
|
||||||
|
font-size: 100%;
|
||||||
|
height: 44px;
|
||||||
|
line-height: 1.15;
|
||||||
|
margin: 12px 0 0;
|
||||||
|
outline: none;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0 20px;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: none;
|
||||||
|
transform: translateZ(0);
|
||||||
|
transition: all .2s,box-shadow .08s ease-in;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
touch-action: manipulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-9:disabled {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-9:focus {
|
||||||
|
box-shadow: rgba(50, 50, 93, .1) 0 0 0 1px inset, rgba(50, 50, 93, .2) 0 6px 15px 0, rgba(0, 0, 0, .1) 0 2px 2px 0, rgba(50, 151, 211, .3) 0 0 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <audioplayers_linux/audioplayers_linux_plugin.h>
|
#include <audioplayers_linux/audioplayers_linux_plugin.h>
|
||||||
#include <desktop_drop/desktop_drop_plugin.h>
|
#include <desktop_drop/desktop_drop_plugin.h>
|
||||||
|
#include <file_selector_linux/file_selector_plugin.h>
|
||||||
#include <pasteboard/pasteboard_plugin.h>
|
#include <pasteboard/pasteboard_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
|
|
@ -18,6 +19,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) desktop_drop_registrar =
|
g_autoptr(FlPluginRegistrar) desktop_drop_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopDropPlugin");
|
||||||
desktop_drop_plugin_register_with_registrar(desktop_drop_registrar);
|
desktop_drop_plugin_register_with_registrar(desktop_drop_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||||
|
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
||||||
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
audioplayers_linux
|
audioplayers_linux
|
||||||
desktop_drop
|
desktop_drop
|
||||||
|
file_selector_linux
|
||||||
pasteboard
|
pasteboard
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import audioplayers_darwin
|
||||||
import desktop_drop
|
import desktop_drop
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
import fc_native_video_thumbnail
|
import fc_native_video_thumbnail
|
||||||
|
import file_selector_macos
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import pasteboard
|
import pasteboard
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
|
|
@ -22,6 +23,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin"))
|
DesktopDropPlugin.register(with: registry.registrar(forPlugin: "DesktopDropPlugin"))
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
FcNativeVideoThumbnailPlugin.register(with: registry.registrar(forPlugin: "FcNativeVideoThumbnailPlugin"))
|
FcNativeVideoThumbnailPlugin.register(with: registry.registrar(forPlugin: "FcNativeVideoThumbnailPlugin"))
|
||||||
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
||||||
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -9,6 +9,7 @@
|
||||||
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
||||||
#include <desktop_drop/desktop_drop_plugin.h>
|
#include <desktop_drop/desktop_drop_plugin.h>
|
||||||
#include <fc_native_video_thumbnail/fc_native_video_thumbnail_plugin_c_api.h>
|
#include <fc_native_video_thumbnail/fc_native_video_thumbnail_plugin_c_api.h>
|
||||||
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
#include <pasteboard/pasteboard_plugin.h>
|
#include <pasteboard/pasteboard_plugin.h>
|
||||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
@ -20,6 +21,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
registry->GetRegistrarForPlugin("DesktopDropPlugin"));
|
registry->GetRegistrarForPlugin("DesktopDropPlugin"));
|
||||||
FcNativeVideoThumbnailPluginCApiRegisterWithRegistrar(
|
FcNativeVideoThumbnailPluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FcNativeVideoThumbnailPluginCApi"));
|
registry->GetRegistrarForPlugin("FcNativeVideoThumbnailPluginCApi"));
|
||||||
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
PasteboardPluginRegisterWithRegistrar(
|
PasteboardPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
||||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
audioplayers_windows
|
audioplayers_windows
|
||||||
desktop_drop
|
desktop_drop
|
||||||
fc_native_video_thumbnail
|
fc_native_video_thumbnail
|
||||||
|
file_selector_windows
|
||||||
pasteboard
|
pasteboard
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_class.dart';
|
||||||
|
|
||||||
typedef MessageFunction = Future<V2TimMessage?> Function(V2TimMessage message);
|
typedef MessageFunction = Future<V2TimMessage?> Function(V2TimMessage message);
|
||||||
|
|
||||||
|
typedef MessageFunctionNullCallback = Function(V2TimValueCallback<V2TimMessage> res);
|
||||||
|
|
||||||
typedef MessageFunctionOptional = Future<V2TimMessage?> Function(
|
typedef MessageFunctionOptional = Future<V2TimMessage?> Function(
|
||||||
V2TimMessage message);
|
V2TimMessage message);
|
||||||
|
|
||||||
|
|
@ -46,10 +48,17 @@ abstract class DefaultLifeCycle {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<bool> defaultBooleanSolution(dynamic) async {
|
static Future<bool> defaultAsyncBooleanSolution(dynamic) async {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool defaultBooleanSolution(dynamic) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultNullCallbackSolution(dynamic) {
|
||||||
|
}
|
||||||
|
|
||||||
static Future<bool> defaultAddFriend(
|
static Future<bool> defaultAddFriend(
|
||||||
String userID, String? remark, String? friendGroup, String? addWording,
|
String userID, String? remark, String? friendGroup, String? addWording,
|
||||||
[BuildContext? context]) async {
|
[BuildContext? context]) async {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,6 @@ class BlockListLifeCycle {
|
||||||
FutureBool Function(List<String> userIDList) shouldDeleteFromBlockList;
|
FutureBool Function(List<String> userIDList) shouldDeleteFromBlockList;
|
||||||
|
|
||||||
BlockListLifeCycle({
|
BlockListLifeCycle({
|
||||||
this.shouldDeleteFromBlockList = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldDeleteFromBlockList = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/base_life_cycle.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/base_life_cycle.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
|
|
||||||
class ChatLifeCycle {
|
class ChatLifeCycle {
|
||||||
/// Before a new message will be added to historical message list from long connection.
|
/// Before a new message will be added to historical message list from long connection.
|
||||||
|
|
@ -12,6 +13,9 @@ class ChatLifeCycle {
|
||||||
/// Returns null can block the message from sending.
|
/// Returns null can block the message from sending.
|
||||||
MessageFunction messageWillSend;
|
MessageFunction messageWillSend;
|
||||||
|
|
||||||
|
/// After a new message been sent.
|
||||||
|
MessageFunctionNullCallback messageDidSend;
|
||||||
|
|
||||||
/// After getting the latest message list from API,
|
/// After getting the latest message list from API,
|
||||||
/// and before historical message list will be rendered.
|
/// and before historical message list will be rendered.
|
||||||
/// You may add or delete some messages here.
|
/// You may add or delete some messages here.
|
||||||
|
|
@ -27,14 +31,20 @@ class ChatLifeCycle {
|
||||||
/// You can make a second confirmation here by a modal, etc.
|
/// You can make a second confirmation here by a modal, etc.
|
||||||
FutureBool Function(String conversationID) shouldClearHistoricalMessageList;
|
FutureBool Function(String conversationID) shouldClearHistoricalMessageList;
|
||||||
|
|
||||||
|
|
||||||
|
/// Before rendering a message to message list.
|
||||||
|
bool Function(V2TimMessage msgID) messageShouldMount;
|
||||||
|
|
||||||
ChatLifeCycle({
|
ChatLifeCycle({
|
||||||
this.shouldClearHistoricalMessageList =
|
this.shouldClearHistoricalMessageList =
|
||||||
DefaultLifeCycle.defaultBooleanSolution,
|
DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldDeleteMessage = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldDeleteMessage = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
|
this.messageDidSend = DefaultLifeCycle.defaultNullCallbackSolution,
|
||||||
this.didGetHistoricalMessageList =
|
this.didGetHistoricalMessageList =
|
||||||
DefaultLifeCycle.defaultMessageListSolution,
|
DefaultLifeCycle.defaultMessageListSolution,
|
||||||
this.messageWillSend = DefaultLifeCycle.defaultMessageSolution,
|
this.messageWillSend = DefaultLifeCycle.defaultMessageSolution,
|
||||||
this.modifiedMessageWillMount = DefaultLifeCycle.defaultMessageSolution,
|
this.modifiedMessageWillMount = DefaultLifeCycle.defaultMessageSolution,
|
||||||
this.newMessageWillMount = DefaultLifeCycle.defaultMessageSolution,
|
this.newMessageWillMount = DefaultLifeCycle.defaultMessageSolution,
|
||||||
|
this.messageShouldMount = DefaultLifeCycle.defaultBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class ConversationLifeCycle {
|
||||||
this.conversationListWillMount =
|
this.conversationListWillMount =
|
||||||
DefaultLifeCycle.defaultConversationListSolution,
|
DefaultLifeCycle.defaultConversationListSolution,
|
||||||
this.shouldClearHistoricalMessageForConversation =
|
this.shouldClearHistoricalMessageForConversation =
|
||||||
DefaultLifeCycle.defaultBooleanSolution,
|
DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldDeleteConversation = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldDeleteConversation = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ class NewContactLifeCycle {
|
||||||
|
|
||||||
NewContactLifeCycle({
|
NewContactLifeCycle({
|
||||||
this.shouldAcceptContactApplication =
|
this.shouldAcceptContactApplication =
|
||||||
DefaultLifeCycle.defaultBooleanSolution,
|
DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldRefuseContactApplication =
|
this.shouldRefuseContactApplication =
|
||||||
DefaultLifeCycle.defaultBooleanSolution,
|
DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ class ProfileLifeCycle {
|
||||||
FutureBool Function(String userID) didRemarkUpdated;
|
FutureBool Function(String userID) didRemarkUpdated;
|
||||||
|
|
||||||
ProfileLifeCycle({
|
ProfileLifeCycle({
|
||||||
this.didRemarkUpdated = DefaultLifeCycle.defaultBooleanSolution,
|
this.didRemarkUpdated = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.didGetFriendInfo = DefaultLifeCycle.defaultFriendInfoSolution,
|
this.didGetFriendInfo = DefaultLifeCycle.defaultFriendInfoSolution,
|
||||||
this.shouldAddToBlockList = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldAddToBlockList = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldAddFriend = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldAddFriend = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
this.shouldDeleteFriend = DefaultLifeCycle.defaultBooleanSolution,
|
this.shouldDeleteFriend = DefaultLifeCycle.defaultAsyncBooleanSolution,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_cloud_custom_data.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_cloud_custom_data.dart';
|
||||||
import 'package:tencent_im_base/tencent_im_base.dart';
|
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||||
|
|
@ -173,4 +174,14 @@ class TUIChatModelTools {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> hasZeroSize(String filePath) async {
|
||||||
|
try {
|
||||||
|
final file = File(filePath);
|
||||||
|
final fileSize = await file.length();
|
||||||
|
return fileSize == 0;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
// ignore: unnecessary_import
|
// ignore: unnecessary_import
|
||||||
|
|
@ -177,16 +178,18 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
setInputField = onChangeInputField;
|
setInputField = onChangeInputField;
|
||||||
conversationType = convType;
|
conversationType = convType;
|
||||||
conversationID = convID;
|
conversationID = convID;
|
||||||
|
|
||||||
|
_groupType = null;
|
||||||
|
isGroupExist = true;
|
||||||
|
_groupInfo = null;
|
||||||
|
groupMemberList?.clear();
|
||||||
|
selfMemberInfo = null;
|
||||||
|
|
||||||
if (conversationType == ConvType.group) {
|
if (conversationType == ConvType.group) {
|
||||||
globalModel.refreshGroupApplicationList();
|
globalModel.refreshGroupApplicationList();
|
||||||
getGroupInfo(groupID ?? convID);
|
loadGroupInfo(groupID ?? convID);
|
||||||
loadGroupMemberList(groupID: groupID ?? convID);
|
loadGroupMemberList(groupID: groupID ?? convID);
|
||||||
} else {
|
} else {
|
||||||
_groupType = null;
|
|
||||||
isGroupExist = true;
|
|
||||||
_groupInfo = null;
|
|
||||||
groupMemberList?.clear();
|
|
||||||
selfMemberInfo = null;
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
if (conversationType == ConvType.c2c) {
|
if (conversationType == ConvType.c2c) {
|
||||||
|
|
@ -482,18 +485,6 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadGroupInfo(String groupID) async {
|
|
||||||
final groupInfo =
|
|
||||||
await _groupServices.getGroupsInfo(groupIDList: [groupID]);
|
|
||||||
if (groupInfo != null) {
|
|
||||||
final groupRes = groupInfo.first;
|
|
||||||
if (groupRes.resultCode == 0) {
|
|
||||||
_groupInfo = groupRes.groupInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> loadGroupMemberList(
|
Future<void> loadGroupMemberList(
|
||||||
{required String groupID, int count = 100, String? seq}) async {
|
{required String groupID, int count = 100, String? seq}) async {
|
||||||
final String? nextSeq = await _loadGroupMemberListFunction(
|
final String? nextSeq = await _loadGroupMemberListFunction(
|
||||||
|
|
@ -503,7 +494,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
groupID: groupID, count: count, seq: nextSeq);
|
groupID: groupID, count: count, seq: nextSeq);
|
||||||
} else {
|
} else {
|
||||||
selfMemberInfo = groupMemberList
|
selfMemberInfo = groupMemberList
|
||||||
?.firstWhere((e) => e?.userID == selfModel.loginInfo?.userID);
|
?.firstWhereOrNull((e) => e?.userID == selfModel.loginInfo?.userID);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -513,38 +504,49 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
if (seq == null || seq == "" || seq == "0") {
|
if (seq == null || seq == "" || seq == "0") {
|
||||||
groupMemberList?.clear();
|
groupMemberList?.clear();
|
||||||
}
|
}
|
||||||
final res = await _groupServices.getGroupMemberList(
|
try {
|
||||||
groupID: groupID,
|
final res = await _groupServices.getGroupMemberList(
|
||||||
filter: GroupMemberFilterTypeEnum.V2TIM_GROUP_MEMBER_FILTER_ALL,
|
groupID: groupID,
|
||||||
count: count,
|
filter: GroupMemberFilterTypeEnum.V2TIM_GROUP_MEMBER_FILTER_ALL,
|
||||||
nextSeq: seq ?? groupMemberListSeq);
|
count: count,
|
||||||
final groupMemberListRes = res.data;
|
nextSeq: seq ?? groupMemberListSeq);
|
||||||
if (res.code == 0 && groupMemberListRes != null) {
|
final groupMemberListRes = res.data;
|
||||||
final groupMemberListTemp = groupMemberListRes.memberInfoList ?? [];
|
if (res.code == 0 && groupMemberListRes != null) {
|
||||||
groupMemberList = [...?groupMemberList, ...groupMemberListTemp];
|
final groupMemberListTemp = groupMemberListRes.memberInfoList ?? [];
|
||||||
groupMemberListSeq = groupMemberListRes.nextSeq ?? "0";
|
groupMemberList = [...?groupMemberList, ...groupMemberListTemp];
|
||||||
} else if (res.code == 10010) {
|
groupMemberListSeq = groupMemberListRes.nextSeq ?? "0";
|
||||||
isGroupExist = false;
|
} else if (res.code == 10010) {
|
||||||
} else if (res.code == 10007) {
|
isGroupExist = false;
|
||||||
isNotAMember = true;
|
} else if (res.code == 10007) {
|
||||||
|
isNotAMember = true;
|
||||||
|
}
|
||||||
|
return groupMemberListRes?.nextSeq;
|
||||||
|
} catch (e) {
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
return groupMemberListRes?.nextSeq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupInfo(String groupID) async {
|
Future<(V2TimGroupInfo?, GroupReceiptAllowType?)> loadGroupInfo(
|
||||||
final res = await _groupServices.getGroupsInfo(groupIDList: [groupID]);
|
String groupID) async {
|
||||||
if (res != null) {
|
final groupInfoList =
|
||||||
final groupRes = res.first;
|
await _groupServices.getGroupsInfo(groupIDList: [groupID]);
|
||||||
|
if (groupInfoList != null && groupInfoList.isNotEmpty) {
|
||||||
|
final groupRes = groupInfoList.first;
|
||||||
if (groupRes.resultCode == 0) {
|
if (groupRes.resultCode == 0) {
|
||||||
|
_groupInfo = groupRes.groupInfo;
|
||||||
|
|
||||||
const groupTypeMap = {
|
const groupTypeMap = {
|
||||||
"Meeting": GroupReceiptAllowType.meeting,
|
"Meeting": GroupReceiptAllowType.meeting,
|
||||||
"Public": GroupReceiptAllowType.public,
|
"Public": GroupReceiptAllowType.public,
|
||||||
"Work": GroupReceiptAllowType.work
|
"Work": GroupReceiptAllowType.work
|
||||||
};
|
};
|
||||||
_groupInfo = groupRes.groupInfo;
|
|
||||||
_groupType = groupTypeMap[groupRes.groupInfo?.groupType];
|
_groupType = groupTypeMap[groupRes.groupInfo?.groupType];
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
return (_groupInfo, _groupType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return (null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateMessageFromController(
|
Future<void> updateMessageFromController(
|
||||||
|
|
@ -584,6 +586,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
}) async {
|
}) async {
|
||||||
String receiver = convType == ConvType.c2c ? convID : '';
|
String receiver = convType == ConvType.c2c ? convID : '';
|
||||||
String groupID = convType == ConvType.group ? convID : '';
|
String groupID = convType == ConvType.group ? convID : '';
|
||||||
|
if (convType == ConvType.group && _groupType == null) {
|
||||||
|
await loadGroupInfo(groupID);
|
||||||
|
}
|
||||||
final oldGroupType = _groupType != null
|
final oldGroupType = _groupType != null
|
||||||
? GroupReceptAllowType.values[_groupType!.index]
|
? GroupReceptAllowType.values[_groupType!.index]
|
||||||
: null;
|
: null;
|
||||||
|
|
@ -624,6 +629,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
globalModel.updateMessage(
|
globalModel.updateMessage(
|
||||||
sendMsgRes, convID, id, convType, groupType, setInputField);
|
sendMsgRes, convID, id, convType, groupType, setInputField);
|
||||||
}
|
}
|
||||||
|
if(lifeCycle?.messageDidSend != null){
|
||||||
|
lifeCycle!.messageDidSend(sendMsgRes);
|
||||||
|
}
|
||||||
|
|
||||||
return sendMsgRes;
|
return sendMsgRes;
|
||||||
}
|
}
|
||||||
|
|
@ -875,6 +883,9 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
globalModel.updateMessage(sendMsgRes, convID,
|
globalModel.updateMessage(sendMsgRes, convID,
|
||||||
messageInfoWithSender.id ?? "", convType, groupType, setInputField);
|
messageInfoWithSender.id ?? "", convType, groupType, setInputField);
|
||||||
|
if(lifeCycle?.messageDidSend != null){
|
||||||
|
lifeCycle!.messageDidSend(sendMsgRes);
|
||||||
|
}
|
||||||
return sendMsgRes;
|
return sendMsgRes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1017,6 +1028,14 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
dynamic inputElement,
|
dynamic inputElement,
|
||||||
required String convID,
|
required String convID,
|
||||||
required ConvType convType}) async {
|
required ConvType convType}) async {
|
||||||
|
if (await tools.hasZeroSize(filePath ?? "")) {
|
||||||
|
final CoreServicesImpl _coreServices = serviceLocator<CoreServicesImpl>();
|
||||||
|
_coreServices.callOnCallback(TIMCallback(
|
||||||
|
type: TIMCallbackType.INFO,
|
||||||
|
infoRecommendText: "不支持 0KB 文件的传输",
|
||||||
|
infoCode: 6660417));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
final fileMessageInfo = await _messageService.createFileMessage(
|
final fileMessageInfo = await _messageService.createFileMessage(
|
||||||
inputElement: inputElement,
|
inputElement: inputElement,
|
||||||
fileName: fileName ?? filePath?.split('/').last ?? "",
|
fileName: fileName ?? filePath?.split('/').last ?? "",
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
ChatLifeCycle? _lifeCycle;
|
ChatLifeCycle? _lifeCycle;
|
||||||
bool _isDownloading = false;
|
bool _isDownloading = false;
|
||||||
final List<Map<String, String>> _waitingDownloadList =
|
final List<Map<String, String>> _waitingDownloadList =
|
||||||
List.empty(growable: true); // example {"savePath":"","url":"",msgId:""}
|
List.empty(growable: true); // example {"savePath":"","url":"",msgId:""}
|
||||||
int _totalUnreadCount = 0;
|
int _totalUnreadCount = 0;
|
||||||
String localKeyPrefix = "TUIKit_conversation_stored_";
|
String localKeyPrefix = "TUIKit_conversation_stored_";
|
||||||
String localMsgIDListKey = "TUIKit_conversation_list";
|
String localMsgIDListKey = "TUIKit_conversation_list";
|
||||||
|
|
@ -62,7 +62,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
List<V2TimGroupApplication>? _groupApplicationList;
|
List<V2TimGroupApplication>? _groupApplicationList;
|
||||||
String Function(V2TimMessage message)? _abstractMessageBuilder;
|
String Function(V2TimMessage message)? _abstractMessageBuilder;
|
||||||
final Map<String, int> _c2cMessageEditStatusMap =
|
final Map<String, int> _c2cMessageEditStatusMap =
|
||||||
Map.from({}); // 0 normal 1 sending
|
Map.from({}); // 0 normal 1 sending
|
||||||
final Map<String, bool> _c2cMessageFromUserActiveMap = Map.from({});
|
final Map<String, bool> _c2cMessageFromUserActiveMap = Map.from({});
|
||||||
final Map<String, Timer> _c2cMessageActiveTimer = Map.from({});
|
final Map<String, Timer> _c2cMessageActiveTimer = Map.from({});
|
||||||
bool _showC2cMessageEditStatus = true;
|
bool _showC2cMessageEditStatus = true;
|
||||||
|
|
@ -102,6 +102,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
|
|
||||||
Map<String, String> get currentDownLoad => _waitingDownloadList.first;
|
Map<String, String> get currentDownLoad => _waitingDownloadList.first;
|
||||||
|
|
||||||
|
int getWaitingListLength() {
|
||||||
|
return _waitingDownloadList.length;
|
||||||
|
}
|
||||||
|
|
||||||
void addWaitingList(String msgID) {
|
void addWaitingList(String msgID) {
|
||||||
print("add to waiting list success");
|
print("add to waiting list success");
|
||||||
bool contains = false;
|
bool contains = false;
|
||||||
|
|
@ -191,15 +195,17 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
Map<String, V2TimMessageReceipt> get messageReadReceiptMap =>
|
Map<String, V2TimMessageReceipt> get messageReadReceiptMap =>
|
||||||
_messageReadReceiptMap;
|
_messageReadReceiptMap;
|
||||||
|
|
||||||
String get currentSelectedConv => _currentConversationList.isNotEmpty
|
String get currentSelectedConv =>
|
||||||
? _currentConversationList[_currentConversationList.length - 1]
|
_currentConversationList.isNotEmpty
|
||||||
|
? _currentConversationList[_currentConversationList.length - 1]
|
||||||
.conversationID
|
.conversationID
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
ConvType? get currentSelectedConvType => _currentConversationList.isNotEmpty
|
ConvType? get currentSelectedConvType =>
|
||||||
? _currentConversationList[_currentConversationList.length - 1]
|
_currentConversationList.isNotEmpty
|
||||||
|
? _currentConversationList[_currentConversationList.length - 1]
|
||||||
.conversationType
|
.conversationType
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
setCurrentConversation(CurrentConversation value) {
|
setCurrentConversation(CurrentConversation value) {
|
||||||
_currentConversationList.add(value);
|
_currentConversationList.add(value);
|
||||||
|
|
@ -235,13 +241,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
_c2cMessageStatusShowTimer[userID] =
|
_c2cMessageStatusShowTimer[userID] =
|
||||||
Timer.periodic(const Duration(seconds: 5), (timer) {
|
Timer.periodic(const Duration(seconds: 5), (timer) {
|
||||||
_c2cMessageEditStatusMap[userID] = 0;
|
_c2cMessageEditStatusMap[userID] = 0;
|
||||||
Timer? t = _c2cMessageStatusShowTimer[userID];
|
Timer? t = _c2cMessageStatusShowTimer[userID];
|
||||||
if (t != null && t.isActive) {
|
if (t != null && t.isActive) {
|
||||||
// 取消当前的定时器
|
// 取消当前的定时器
|
||||||
t.cancel();
|
t.cancel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
@ -326,10 +332,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
prefs.remove(localMsgIDListKey);
|
prefs.remove(localMsgIDListKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateMessageFromController(
|
Future<void> updateMessageFromController({required String msgID,
|
||||||
{required String msgID,
|
required String conversationID,
|
||||||
required String conversationID,
|
required ConvType conversationType}) async {
|
||||||
required ConvType conversationType}) async {
|
|
||||||
final TUIChatModelTools tools = serviceLocator<TUIChatModelTools>();
|
final TUIChatModelTools tools = serviceLocator<TUIChatModelTools>();
|
||||||
V2TimMessage? newMessage = await tools.getExistingMessageByID(
|
V2TimMessage? newMessage = await tools.getExistingMessageByID(
|
||||||
msgID: msgID,
|
msgID: msgID,
|
||||||
|
|
@ -343,11 +348,11 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
Future<bool> refreshCurrentHistoryListForConversation(
|
Future<bool> refreshCurrentHistoryListForConversation(
|
||||||
{HistoryMsgGetTypeEnum getType =
|
{HistoryMsgGetTypeEnum getType =
|
||||||
HistoryMsgGetTypeEnum.V2TIM_GET_CLOUD_OLDER_MSG,
|
HistoryMsgGetTypeEnum.V2TIM_GET_CLOUD_OLDER_MSG,
|
||||||
int lastMsgSeq = -1,
|
int lastMsgSeq = -1,
|
||||||
required int count,
|
required int count,
|
||||||
String? lastMsgID,
|
String? lastMsgID,
|
||||||
required String convID,
|
required String convID,
|
||||||
required ConvType convType}) async {
|
required ConvType convType}) async {
|
||||||
final currentHistoryMsgList = messageListMap[convID];
|
final currentHistoryMsgList = messageListMap[convID];
|
||||||
final response = await _messageService.getHistoryMessageList(
|
final response = await _messageService.getHistoryMessageList(
|
||||||
count: count,
|
count: count,
|
||||||
|
|
@ -389,7 +394,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
|
|
||||||
_preLoadImage(List<V2TimMessage> msgList) {
|
_preLoadImage(List<V2TimMessage> msgList) {
|
||||||
List<V2TimMessage> needPreViewList =
|
List<V2TimMessage> needPreViewList =
|
||||||
msgList.sublist(0, max(0, min(5, msgList.length - 1)));
|
msgList.sublist(0, max(0, min(5, msgList.length - 1)));
|
||||||
for (var msgItem in needPreViewList) {
|
for (var msgItem in needPreViewList) {
|
||||||
V2TimImage? getImageFromList(V2TimImageTypesEnum imgType) {
|
V2TimImage? getImageFromList(V2TimImageTypesEnum imgType) {
|
||||||
V2TimImage? img = MessageUtils.getImageFromImgList(
|
V2TimImage? img = MessageUtils.getImageFromImgList(
|
||||||
|
|
@ -407,12 +412,12 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
|
|
||||||
image.resolve(configuration).addListener(
|
image.resolve(configuration).addListener(
|
||||||
ImageStreamListener((ImageInfo image, bool synchronousCall) {
|
ImageStreamListener((ImageInfo image, bool synchronousCall) {
|
||||||
final tempImg = image.image;
|
final tempImg = image.image;
|
||||||
_preloadImageMap[msgItem.seq! +
|
_preloadImageMap[msgItem.seq! +
|
||||||
msgItem.timestamp.toString() +
|
msgItem.timestamp.toString() +
|
||||||
(msgItem.msgID ?? "")] = tempImg;
|
(msgItem.msgID ?? "")] = tempImg;
|
||||||
print("cacheImage ${msgItem.msgID}");
|
print("cacheImage ${msgItem.msgID}");
|
||||||
}));
|
}));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("cacheImage error ${msgItem.msgID}");
|
print("cacheImage error ${msgItem.msgID}");
|
||||||
}
|
}
|
||||||
|
|
@ -513,13 +518,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
_c2cMessageActiveTimer[msg.sender ?? ""] =
|
_c2cMessageActiveTimer[msg.sender ?? ""] =
|
||||||
Timer.periodic(const Duration(seconds: 30), (timer) {
|
Timer.periodic(const Duration(seconds: 30), (timer) {
|
||||||
_c2cMessageFromUserActiveMap[msg.sender ?? ""] = false;
|
_c2cMessageFromUserActiveMap[msg.sender ?? ""] = false;
|
||||||
Timer? t = _c2cMessageActiveTimer[msg.sender ?? ""];
|
Timer? t = _c2cMessageActiveTimer[msg.sender ?? ""];
|
||||||
if (t != null && t.isActive) {
|
if (t != null && t.isActive) {
|
||||||
// 取消当前的定时器
|
// 取消当前的定时器
|
||||||
t.cancel();
|
t.cancel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -537,14 +542,14 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
V2TimMsgCreateInfoResult? res = await _messageService.createCustomMessage(
|
V2TimMsgCreateInfoResult? res = await _messageService.createCustomMessage(
|
||||||
data: json.encode({
|
data: json.encode({
|
||||||
"businessID": "user_typing_status",
|
"businessID": "user_typing_status",
|
||||||
"typingStatus": isEditing == true ? 1 : 0,
|
"typingStatus": isEditing == true ? 1 : 0,
|
||||||
"userAction": 14,
|
"userAction": 14,
|
||||||
"version": 0,
|
"version": 0,
|
||||||
"actionParam": isEditing == true
|
"actionParam": isEditing == true
|
||||||
? "EIMAMSG_InputStatus_Ing"
|
? "EIMAMSG_InputStatus_Ing"
|
||||||
: "EIMAMSG_InputStatus_End"
|
: "EIMAMSG_InputStatus_End"
|
||||||
}));
|
}));
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
_sendMessage(
|
_sendMessage(
|
||||||
id: res.id!,
|
id: res.id!,
|
||||||
|
|
@ -559,9 +564,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
void refreshGroupApplicationList() async {
|
void refreshGroupApplicationList() async {
|
||||||
final res = await _groupServices.getGroupApplicationList();
|
final res = await _groupServices.getGroupApplicationList();
|
||||||
_groupApplicationList = res.data?.groupApplicationList?.map((item) {
|
_groupApplicationList = res.data?.groupApplicationList?.map((item) {
|
||||||
final V2TimGroupApplication applicationItem = item!;
|
final V2TimGroupApplication applicationItem = item!;
|
||||||
return applicationItem;
|
return applicationItem;
|
||||||
}).toList() ??
|
}).toList() ??
|
||||||
[];
|
[];
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
@ -657,14 +662,17 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
final activeMessageList = _messageListMap[convID ?? currentSelectedConv];
|
final activeMessageList = _messageListMap[convID ?? currentSelectedConv];
|
||||||
if (activeMessageList != null) {
|
if (activeMessageList != null) {
|
||||||
final findeIndex =
|
final findeIndex =
|
||||||
activeMessageList.indexWhere((element) => element.msgID == msgID);
|
activeMessageList.indexWhere((element) => element.msgID == msgID);
|
||||||
if (findeIndex != -1) {
|
if (findeIndex != -1) {
|
||||||
final findeIndex =
|
final findeIndex =
|
||||||
activeMessageList.indexWhere((element) => element.msgID == msgID);
|
activeMessageList.indexWhere((element) => element.msgID == msgID);
|
||||||
if (findeIndex != -1) {
|
if (findeIndex != -1) {
|
||||||
final targetItem = activeMessageList[findeIndex];
|
final targetItem = activeMessageList[findeIndex];
|
||||||
targetItem.status = MessageStatus.V2TIM_MSG_STATUS_LOCAL_REVOKED;
|
targetItem.status = MessageStatus.V2TIM_MSG_STATUS_LOCAL_REVOKED;
|
||||||
targetItem.id = DateTime.now().millisecondsSinceEpoch.toString();
|
targetItem.id = DateTime
|
||||||
|
.now()
|
||||||
|
.millisecondsSinceEpoch
|
||||||
|
.toString();
|
||||||
activeMessageList[findeIndex] = targetItem;
|
activeMessageList[findeIndex] = targetItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -674,7 +682,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageModified(V2TimMessage modifiedMessage, [String? convID]) async {
|
onMessageModified(V2TimMessage modifiedMessage, [String? convID]) async {
|
||||||
modifiedMessage.id = DateTime.now().millisecondsSinceEpoch.toString();
|
modifiedMessage.id = DateTime
|
||||||
|
.now()
|
||||||
|
.millisecondsSinceEpoch
|
||||||
|
.toString();
|
||||||
final String? exactId = TencentUtils.checkString(modifiedMessage.userID) ??
|
final String? exactId = TencentUtils.checkString(modifiedMessage.userID) ??
|
||||||
TencentUtils.checkString(modifiedMessage.groupID);
|
TencentUtils.checkString(modifiedMessage.groupID);
|
||||||
final activeMessageList = _messageListMap[convID ?? exactId];
|
final activeMessageList = _messageListMap[convID ?? exactId];
|
||||||
|
|
@ -729,33 +740,78 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
print("message progress: $progress");
|
print("message progress: $progress");
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageDownloadProgressCallback(
|
Future<void> onMessageDownloadProgressCallback(
|
||||||
V2TimMessageDownloadProgress messageProgress) async {
|
V2TimMessageDownloadProgress messageProgress) async {
|
||||||
if (messageProgress.isFinish) {
|
print(messageProgress.toJson());
|
||||||
setMessageProgress(messageProgress.msgID, 100);
|
final currentProgress = getMessageProgress(messageProgress.msgID);
|
||||||
setFileMessageLocation(messageProgress.msgID, messageProgress.path);
|
|
||||||
downloadFile();
|
if (messageProgress.isFinish && currentProgress < 100) {
|
||||||
if (messageProgress.type == 0) {
|
V2TimMessage? message = await _findAndRetrieveMessage(
|
||||||
final messages = await _messageService
|
messageProgress.msgID);
|
||||||
.findMessages(messageIDList: [messageProgress.msgID]);
|
_handleFinishedDownload(messageProgress, message);
|
||||||
final V2TimMessage? message = messages?.first;
|
|
||||||
if (message != null) {
|
|
||||||
updateAsyncMessage(
|
|
||||||
message,
|
|
||||||
TencentUtils.checkString(message.userID) ??
|
|
||||||
TencentUtils.checkString(message.groupID) ??
|
|
||||||
"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (messageProgress.totalSize != -1) {
|
|
||||||
int progress =
|
_updateProgressIfNeeded(messageProgress, currentProgress);
|
||||||
(messageProgress.currentSize / messageProgress.totalSize * 100)
|
}
|
||||||
.ceil();
|
|
||||||
if (progress > 1) {
|
Future<V2TimMessage?> _findAndRetrieveMessage(String messageId) async {
|
||||||
setMessageProgress(messageProgress.msgID, progress);
|
final messages = await _messageService.findMessages(
|
||||||
|
messageIDList: [messageId]);
|
||||||
|
return messages?.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleFinishedDownload(V2TimMessageDownloadProgress messageProgress,
|
||||||
|
V2TimMessage? message) {
|
||||||
|
if (message != null) {
|
||||||
|
bool isImageType = message.elemType ==
|
||||||
|
MessageElemType.V2TIM_ELEM_TYPE_IMAGE;
|
||||||
|
bool isVideoType = message.elemType ==
|
||||||
|
MessageElemType.V2TIM_ELEM_TYPE_VIDEO;
|
||||||
|
if (!isImageType && !isVideoType) {
|
||||||
|
_updateMessageLocationAndDownloadFile(messageProgress);
|
||||||
|
} else if ((isImageType && messageProgress.type == 0) || isVideoType) {
|
||||||
|
Future.delayed(const Duration(seconds: 1), () =>
|
||||||
|
_updateMessageAndDownloadFile(message, messageProgress));
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
_updateMessageLocationAndDownloadFile(messageProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateMessageAndDownloadFile(V2TimMessage message,
|
||||||
|
V2TimMessageDownloadProgress messageProgress) {
|
||||||
|
updateAsyncMessage(
|
||||||
|
message,
|
||||||
|
TencentUtils.checkString(message.userID) ??
|
||||||
|
TencentUtils.checkString(message.groupID) ??
|
||||||
|
"");
|
||||||
|
|
||||||
|
_updateMessageLocationAndDownloadFile(messageProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateMessageLocationAndDownloadFile(
|
||||||
|
V2TimMessageDownloadProgress messageProgress) {
|
||||||
|
setFileMessageLocation(messageProgress.msgID, messageProgress.path);
|
||||||
|
setMessageProgress(messageProgress.msgID, 100);
|
||||||
|
downloadFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateProgressIfNeeded(V2TimMessageDownloadProgress messageProgress,
|
||||||
|
int currentProgress) {
|
||||||
|
try{
|
||||||
|
if (messageProgress.totalSize != -1 && !messageProgress.isFinish) {
|
||||||
|
int progress = min(99,
|
||||||
|
(messageProgress.currentSize / messageProgress.totalSize * 100)
|
||||||
|
.floor());
|
||||||
|
if (progress > 1 && progress > currentProgress) {
|
||||||
|
setMessageProgress(messageProgress.msgID, progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(e){
|
||||||
|
print("calculate error: ${messageProgress.toJson()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -842,11 +898,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
final TUIChatModelTools tools = serviceLocator<TUIChatModelTools>();
|
final TUIChatModelTools tools = serviceLocator<TUIChatModelTools>();
|
||||||
List<V2TimMessage> currentHistoryMsgList = _messageListMap[convID] ?? [];
|
List<V2TimMessage> currentHistoryMsgList = _messageListMap[convID] ?? [];
|
||||||
V2TimMsgCreateInfoResult? textMessageInfo =
|
V2TimMsgCreateInfoResult? textMessageInfo =
|
||||||
await _messageService.createTextMessage(text: text);
|
await _messageService.createTextMessage(text: text);
|
||||||
|
|
||||||
textMessageInfo = await _messageService.createTextAtMessage(
|
textMessageInfo = await _messageService.createTextAtMessage(
|
||||||
text: text +
|
text: text +
|
||||||
" @${TencentUtils.checkString(messageBeenReplied.nickName) ?? TencentUtils.checkString(messageBeenReplied.sender) ?? TencentUtils.checkString(messageBeenReplied.userID)}",
|
"\n@${TencentUtils.checkString(messageBeenReplied.nickName) ??
|
||||||
|
TencentUtils.checkString(messageBeenReplied.sender) ??
|
||||||
|
TencentUtils.checkString(messageBeenReplied.userID)}",
|
||||||
atUserList: [
|
atUserList: [
|
||||||
TencentUtils.checkString(messageBeenReplied.sender) ??
|
TencentUtils.checkString(messageBeenReplied.sender) ??
|
||||||
TencentUtils.checkString(messageBeenReplied.userID) ??
|
TencentUtils.checkString(messageBeenReplied.userID) ??
|
||||||
|
|
@ -857,7 +915,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
|
|
||||||
if (messageInfo != null) {
|
if (messageInfo != null) {
|
||||||
final messageInfoWithSender = messageInfo.sender == null
|
final messageInfoWithSender = messageInfo.sender == null
|
||||||
? tools.setUserInfoForMessage(messageInfo, messageInfo.id ?? textMessageInfo.id ?? "")
|
? tools.setUserInfoForMessage(
|
||||||
|
messageInfo, messageInfo.id ?? textMessageInfo.id ?? "")
|
||||||
: messageInfo;
|
: messageInfo;
|
||||||
|
|
||||||
final hasNickName = messageBeenReplied.nickName != null &&
|
final hasNickName = messageBeenReplied.nickName != null &&
|
||||||
|
|
@ -898,8 +957,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> setLocalCustomData(
|
Future<bool> setLocalCustomData(String msgID, String localCustomData,
|
||||||
String msgID, String localCustomData, String conversationID) async {
|
String conversationID) async {
|
||||||
final res = await _messageService.setLocalCustomData(
|
final res = await _messageService.setLocalCustomData(
|
||||||
msgID: msgID, localCustomData: localCustomData);
|
msgID: msgID, localCustomData: localCustomData);
|
||||||
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
||||||
|
|
@ -918,8 +977,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> setLocalCustomInt(
|
Future<bool> setLocalCustomInt(String msgID, int localCustomInt,
|
||||||
String msgID, int localCustomInt, String conversationID) async {
|
String conversationID) async {
|
||||||
final res = await _messageService.setLocalCustomInt(
|
final res = await _messageService.setLocalCustomInt(
|
||||||
msgID: msgID, localCustomInt: localCustomInt);
|
msgID: msgID, localCustomInt: localCustomInt);
|
||||||
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
||||||
|
|
@ -956,7 +1015,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
String receiver = convType == ConvType.c2c ? convID : '';
|
String receiver = convType == ConvType.c2c ? convID : '';
|
||||||
String groupID = convType == ConvType.group ? convID : '';
|
String groupID = convType == ConvType.group ? convID : '';
|
||||||
final oldGroupType =
|
final oldGroupType =
|
||||||
groupType != null ? GroupReceptAllowType.values[groupType.index] : null;
|
groupType != null ? GroupReceptAllowType.values[groupType.index] : null;
|
||||||
final sendMsgRes = await _messageService.sendMessage(
|
final sendMsgRes = await _messageService.sendMessage(
|
||||||
id: id,
|
id: id,
|
||||||
receiver: receiver,
|
receiver: receiver,
|
||||||
|
|
@ -964,8 +1023,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
chatConfig.isShowGroupReadingStatus &&
|
chatConfig.isShowGroupReadingStatus &&
|
||||||
convType == ConvType.group &&
|
convType == ConvType.group &&
|
||||||
((chatConfig.groupReadReceiptPermissionList != null &&
|
((chatConfig.groupReadReceiptPermissionList != null &&
|
||||||
chatConfig.groupReadReceiptPermissionList!
|
chatConfig.groupReadReceiptPermissionList!
|
||||||
.contains(groupType)) ||
|
.contains(groupType)) ||
|
||||||
(chatConfig.groupReadReceiptPermisionList != null &&
|
(chatConfig.groupReadReceiptPermisionList != null &&
|
||||||
chatConfig.groupReadReceiptPermisionList!
|
chatConfig.groupReadReceiptPermisionList!
|
||||||
.contains(oldGroupType))),
|
.contains(oldGroupType))),
|
||||||
|
|
@ -985,6 +1044,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
if (isEditStatusMessage == false) {
|
if (isEditStatusMessage == false) {
|
||||||
updateMessage(sendMsgRes, convID, id, convType, groupType, setInputField);
|
updateMessage(sendMsgRes, convID, id, convType, groupType, setInputField);
|
||||||
}
|
}
|
||||||
|
if(_lifeCycle?.messageDidSend != null){
|
||||||
|
_lifeCycle!.messageDidSend(sendMsgRes);
|
||||||
|
}
|
||||||
|
|
||||||
return sendMsgRes;
|
return sendMsgRes;
|
||||||
}
|
}
|
||||||
|
|
@ -998,8 +1060,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMessage(
|
updateMessage(V2TimValueCallback<V2TimMessage> sendMsgRes,
|
||||||
V2TimValueCallback<V2TimMessage> sendMsgRes,
|
|
||||||
String convID,
|
String convID,
|
||||||
String id,
|
String id,
|
||||||
ConvType convType,
|
ConvType convType,
|
||||||
|
|
@ -1014,10 +1075,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
final findIdIndex =
|
final findIdIndex =
|
||||||
currentHistoryMsgList.indexWhere((element) => element.id == id);
|
currentHistoryMsgList.indexWhere((element) => element.id == id);
|
||||||
final targetIndex = findIdIndex == -1
|
final targetIndex = findIdIndex == -1
|
||||||
? currentHistoryMsgList
|
? currentHistoryMsgList
|
||||||
.indexWhere((element) => element.msgID == sendMsgResData.msgID)
|
.indexWhere((element) => element.msgID == sendMsgResData.msgID)
|
||||||
: findIdIndex;
|
: findIdIndex;
|
||||||
if (targetIndex != -1) {
|
if (targetIndex != -1) {
|
||||||
currentHistoryMsgList[targetIndex] = sendMsgResData;
|
currentHistoryMsgList[targetIndex] = sendMsgResData;
|
||||||
|
|
@ -1028,13 +1089,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
loadingMessage[convID]!.removeWhere((element) => element.id == id);
|
loadingMessage[convID]!.removeWhere((element) => element.id == id);
|
||||||
}
|
}
|
||||||
final oldGroupType =
|
final oldGroupType =
|
||||||
groupType != null ? GroupReceptAllowType.values[groupType.index] : null;
|
groupType != null ? GroupReceptAllowType.values[groupType.index] : null;
|
||||||
if (chatConfig.isShowGroupReadingStatus &&
|
if (chatConfig.isShowGroupReadingStatus &&
|
||||||
convType == ConvType.group &&
|
convType == ConvType.group &&
|
||||||
sendMsgRes.data?.msgID != null &&
|
sendMsgRes.data?.msgID != null &&
|
||||||
((chatConfig.groupReadReceiptPermissionList != null &&
|
((chatConfig.groupReadReceiptPermissionList != null &&
|
||||||
chatConfig.groupReadReceiptPermissionList!
|
chatConfig.groupReadReceiptPermissionList!
|
||||||
.contains(groupType)) ||
|
.contains(groupType)) ||
|
||||||
(chatConfig.groupReadReceiptPermisionList != null &&
|
(chatConfig.groupReadReceiptPermisionList != null &&
|
||||||
chatConfig.groupReadReceiptPermisionList!
|
chatConfig.groupReadReceiptPermisionList!
|
||||||
.contains(oldGroupType)))) {
|
.contains(oldGroupType)))) {
|
||||||
|
|
@ -1045,11 +1106,12 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateAsyncMessage(
|
void updateAsyncMessage(V2TimMessage message,
|
||||||
V2TimMessage message,
|
String convID,) {
|
||||||
String convID,
|
message.id = DateTime
|
||||||
) {
|
.now()
|
||||||
message.id = DateTime.now().millisecondsSinceEpoch.toString();
|
.millisecondsSinceEpoch
|
||||||
|
.toString();
|
||||||
|
|
||||||
final activeMessageList = _messageListMap[convID];
|
final activeMessageList = _messageListMap[convID];
|
||||||
if (activeMessageList == null || activeMessageList.isEmpty) {
|
if (activeMessageList == null || activeMessageList.isEmpty) {
|
||||||
|
|
@ -1068,18 +1130,19 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<V2TimMessage>? getMessageList(String conversationID) {
|
List<V2TimMessage>? getMessageList(String conversationID) {
|
||||||
final list = messageListMap[conversationID]?.reversed.toList() ?? [];
|
final list = (messageListMap[conversationID]?.reversed.toList() ?? [])
|
||||||
|
.where((element) => _lifeCycle?.messageShouldMount(element) ?? true);
|
||||||
final List<V2TimMessage> listWithTimestamp = [];
|
final List<V2TimMessage> listWithTimestamp = [];
|
||||||
final interval = chatConfig.timeDividerConfig?.timeInterval ?? 300;
|
final interval = chatConfig.timeDividerConfig?.timeInterval ?? 300;
|
||||||
for (var item in list) {
|
for (var item in list) {
|
||||||
{
|
{
|
||||||
if (listWithTimestamp.isEmpty ||
|
if (listWithTimestamp.isEmpty ||
|
||||||
(listWithTimestamp[listWithTimestamp.length - 1].timestamp !=
|
(listWithTimestamp[listWithTimestamp.length - 1].timestamp !=
|
||||||
null &&
|
null &&
|
||||||
item.timestamp != null &&
|
item.timestamp != null &&
|
||||||
(item.timestamp! -
|
(item.timestamp! -
|
||||||
listWithTimestamp[listWithTimestamp.length - 1]
|
listWithTimestamp[listWithTimestamp.length - 1]
|
||||||
.timestamp! >
|
.timestamp! >
|
||||||
interval))) {
|
interval))) {
|
||||||
listWithTimestamp.add(V2TimMessage(
|
listWithTimestamp.add(V2TimMessage(
|
||||||
userID: '',
|
userID: '',
|
||||||
|
|
@ -1098,7 +1161,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
|
|
||||||
HistoryMessagePosition getMessageListPosition(String? conversationID) {
|
HistoryMessagePosition getMessageListPosition(String? conversationID) {
|
||||||
final HistoryMessagePosition? position =
|
final HistoryMessagePosition? position =
|
||||||
_historyMessagePositionMap[conversationID];
|
_historyMessagePositionMap[conversationID];
|
||||||
if (position == null) {
|
if (position == null) {
|
||||||
_historyMessagePositionMap[conversationID ?? currentSelectedConv] =
|
_historyMessagePositionMap[conversationID ?? currentSelectedConv] =
|
||||||
HistoryMessagePosition.bottom;
|
HistoryMessagePosition.bottom;
|
||||||
|
|
@ -1108,8 +1171,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMessageListPosition(
|
void setMessageListPosition(String conversationID,
|
||||||
String conversationID, HistoryMessagePosition position) {
|
HistoryMessagePosition position) {
|
||||||
_historyMessagePositionMap[conversationID] = position;
|
_historyMessagePositionMap[conversationID] = position;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,8 +151,8 @@ class TUIConversationViewModel extends ChangeNotifier {
|
||||||
final isRefresh = _nextSeq == "0";
|
final isRefresh = _nextSeq == "0";
|
||||||
final conversationResult = await _conversationService.getConversationList(
|
final conversationResult = await _conversationService.getConversationList(
|
||||||
nextSeq: _nextSeq, count: count);
|
nextSeq: _nextSeq, count: count);
|
||||||
_nextSeq = conversationResult!.nextSeq ?? "";
|
_nextSeq = conversationResult?.nextSeq ?? "";
|
||||||
final conversationList = conversationResult.conversationList;
|
final conversationList = conversationResult?.conversationList;
|
||||||
if (conversationList != null) {
|
if (conversationList != null) {
|
||||||
if (conversationList.isEmpty || conversationList.length < count) {
|
if (conversationList.isEmpty || conversationList.length < count) {
|
||||||
_haveMoreData = false;
|
_haveMoreData = false;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// ignore_for_file: avoid_print
|
// ignore_for_file: avoid_print
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/common_utils.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||||
import 'package:tencent_im_base/tencent_im_base.dart';
|
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart';
|
||||||
|
|
@ -14,7 +16,7 @@ import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_config.dar
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support.dart'
|
import 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support.dart'
|
||||||
if (dart.library.html) 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support_implement.dart';
|
if (dart.library.html) 'package:tencent_cloud_chat_uikit/data_services/core/web_support/uikit_web_support_implement.dart';
|
||||||
|
|
||||||
typedef EmptyAvatarBuilder = Widget Function(BuildContext context);
|
typedef EmptyAvatarBuilder = Widget Function(BuildContext context);
|
||||||
|
|
||||||
|
|
@ -61,7 +63,7 @@ class CoreServicesImpl implements CoreServices {
|
||||||
|
|
||||||
setGlobalConfig(TIMUIKitConfig? config) {
|
setGlobalConfig(TIMUIKitConfig? config) {
|
||||||
final TUISelfInfoViewModel selfInfoViewModel =
|
final TUISelfInfoViewModel selfInfoViewModel =
|
||||||
serviceLocator<TUISelfInfoViewModel>();
|
serviceLocator<TUISelfInfoViewModel>();
|
||||||
final TUISettingModel settingModel = serviceLocator<TUISettingModel>();
|
final TUISettingModel settingModel = serviceLocator<TUISettingModel>();
|
||||||
selfInfoViewModel.globalConfig = config;
|
selfInfoViewModel.globalConfig = config;
|
||||||
settingModel.init();
|
settingModel.init();
|
||||||
|
|
@ -73,21 +75,20 @@ class CoreServicesImpl implements CoreServices {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool?> init(
|
Future<bool?> init({
|
||||||
{
|
/// Callback from TUIKit invoke, includes IM SDK API error, notify information, Flutter error.
|
||||||
/// Callback from TUIKit invoke, includes IM SDK API error, notify information, Flutter error.
|
ValueChanged<TIMCallback>? onTUIKitCallbackListener,
|
||||||
ValueChanged<TIMCallback>? onTUIKitCallbackListener,
|
required int sdkAppID,
|
||||||
required int sdkAppID,
|
required LogLevelEnum loglevel,
|
||||||
required LogLevelEnum loglevel,
|
required V2TimSDKListener listener,
|
||||||
required V2TimSDKListener listener,
|
LanguageEnum? language,
|
||||||
LanguageEnum? language,
|
String? extraLanguage,
|
||||||
String? extraLanguage,
|
TIMUIKitConfig? config,
|
||||||
TIMUIKitConfig? config,
|
|
||||||
|
|
||||||
/// Specify the current device platform, mobile or desktop, based on your needs.
|
/// Specify the current device platform, mobile or desktop, based on your needs.
|
||||||
/// TUIKit will automatically determine the platform if no specification is provided. DeviceType? platform,
|
/// TUIKit will automatically determine the platform if no specification is provided. DeviceType? platform,
|
||||||
DeviceType? platform,
|
DeviceType? platform,
|
||||||
VoidCallback? onWebLoginSuccess}) async {
|
VoidCallback? onWebLoginSuccess}) async {
|
||||||
if (platform != null) {
|
if (platform != null) {
|
||||||
TUIKitScreenUtils.deviceType = platform;
|
TUIKitScreenUtils.deviceType = platform;
|
||||||
}
|
}
|
||||||
|
|
@ -166,13 +167,13 @@ class CoreServicesImpl implements CoreServices {
|
||||||
|
|
||||||
void addInitListener() {
|
void addInitListener() {
|
||||||
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
||||||
serviceLocator<TUIFriendShipViewModel>();
|
serviceLocator<TUIFriendShipViewModel>();
|
||||||
final TUIConversationViewModel tuiConversationViewModel =
|
final TUIConversationViewModel tuiConversationViewModel =
|
||||||
serviceLocator<TUIConversationViewModel>();
|
serviceLocator<TUIConversationViewModel>();
|
||||||
final TUIChatGlobalModel tuiChatViewModel =
|
final TUIChatGlobalModel tuiChatViewModel =
|
||||||
serviceLocator<TUIChatGlobalModel>();
|
serviceLocator<TUIChatGlobalModel>();
|
||||||
final TUIGroupListenerModel tuiGroupListenerModel =
|
final TUIGroupListenerModel tuiGroupListenerModel =
|
||||||
serviceLocator<TUIGroupListenerModel>();
|
serviceLocator<TUIGroupListenerModel>();
|
||||||
|
|
||||||
tuiFriendShipViewModel.addFriendListener();
|
tuiFriendShipViewModel.addFriendListener();
|
||||||
tuiConversationViewModel.setConversationListener();
|
tuiConversationViewModel.setConversationListener();
|
||||||
|
|
@ -182,13 +183,13 @@ class CoreServicesImpl implements CoreServices {
|
||||||
|
|
||||||
void removeListener() {
|
void removeListener() {
|
||||||
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
||||||
serviceLocator<TUIFriendShipViewModel>();
|
serviceLocator<TUIFriendShipViewModel>();
|
||||||
final TUIConversationViewModel tuiConversationViewModel =
|
final TUIConversationViewModel tuiConversationViewModel =
|
||||||
serviceLocator<TUIConversationViewModel>();
|
serviceLocator<TUIConversationViewModel>();
|
||||||
final TUIChatGlobalModel tuiChatViewModel =
|
final TUIChatGlobalModel tuiChatViewModel =
|
||||||
serviceLocator<TUIChatGlobalModel>();
|
serviceLocator<TUIChatGlobalModel>();
|
||||||
final TUIGroupListenerModel tuiGroupListenerModel =
|
final TUIGroupListenerModel tuiGroupListenerModel =
|
||||||
serviceLocator<TUIGroupListenerModel>();
|
serviceLocator<TUIGroupListenerModel>();
|
||||||
|
|
||||||
tuiFriendShipViewModel.removeFriendshipListener();
|
tuiFriendShipViewModel.removeFriendshipListener();
|
||||||
tuiConversationViewModel.removeConversationListener();
|
tuiConversationViewModel.removeConversationListener();
|
||||||
|
|
@ -203,15 +204,16 @@ class CoreServicesImpl implements CoreServices {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
print(
|
print(
|
||||||
"TUIKit Callback: ${callbackValue.type} - ${callbackValue.stackTrace}");
|
"TUIKit Callback: ${callbackValue.type} - ${callbackValue
|
||||||
|
.stackTrace}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initDataModel() {
|
initDataModel() {
|
||||||
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
||||||
serviceLocator<TUIFriendShipViewModel>();
|
serviceLocator<TUIFriendShipViewModel>();
|
||||||
final TUIConversationViewModel tuiConversationViewModel =
|
final TUIConversationViewModel tuiConversationViewModel =
|
||||||
serviceLocator<TUIConversationViewModel>();
|
serviceLocator<TUIConversationViewModel>();
|
||||||
|
|
||||||
tuiFriendShipViewModel.initFriendShipModel();
|
tuiFriendShipViewModel.initFriendShipModel();
|
||||||
tuiConversationViewModel.initConversation();
|
tuiConversationViewModel.initConversation();
|
||||||
|
|
@ -219,11 +221,11 @@ class CoreServicesImpl implements CoreServices {
|
||||||
|
|
||||||
clearData() {
|
clearData() {
|
||||||
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
||||||
serviceLocator<TUIFriendShipViewModel>();
|
serviceLocator<TUIFriendShipViewModel>();
|
||||||
final TUIConversationViewModel tuiConversationViewModel =
|
final TUIConversationViewModel tuiConversationViewModel =
|
||||||
serviceLocator<TUIConversationViewModel>();
|
serviceLocator<TUIConversationViewModel>();
|
||||||
final TUIChatGlobalModel tuiChatViewModel =
|
final TUIChatGlobalModel tuiChatViewModel =
|
||||||
serviceLocator<TUIChatGlobalModel>();
|
serviceLocator<TUIChatGlobalModel>();
|
||||||
|
|
||||||
tuiFriendShipViewModel.clearData();
|
tuiFriendShipViewModel.clearData();
|
||||||
tuiConversationViewModel.clearData();
|
tuiConversationViewModel.clearData();
|
||||||
|
|
@ -233,18 +235,18 @@ class CoreServicesImpl implements CoreServices {
|
||||||
updateUserStatusList(List<V2TimUserStatus> newUserStatusList) {
|
updateUserStatusList(List<V2TimUserStatus> newUserStatusList) {
|
||||||
try {
|
try {
|
||||||
final TUISelfInfoViewModel selfInfoViewModel =
|
final TUISelfInfoViewModel selfInfoViewModel =
|
||||||
serviceLocator<TUISelfInfoViewModel>();
|
serviceLocator<TUISelfInfoViewModel>();
|
||||||
if (selfInfoViewModel.globalConfig?.isShowOnlineStatus == false) {
|
if (selfInfoViewModel.globalConfig?.isShowOnlineStatus == false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
final TUIFriendShipViewModel tuiFriendShipViewModel =
|
||||||
serviceLocator<TUIFriendShipViewModel>();
|
serviceLocator<TUIFriendShipViewModel>();
|
||||||
final currentUserStatusList = tuiFriendShipViewModel.userStatusList;
|
final currentUserStatusList = tuiFriendShipViewModel.userStatusList;
|
||||||
|
|
||||||
for (int i = 0; i < newUserStatusList.length; i++) {
|
for (int i = 0; i < newUserStatusList.length; i++) {
|
||||||
final int indexInCurrentUserList = currentUserStatusList.indexWhere(
|
final int indexInCurrentUserList = currentUserStatusList.indexWhere(
|
||||||
(element) => element.userID == newUserStatusList[i].userID);
|
(element) => element.userID == newUserStatusList[i].userID);
|
||||||
if (indexInCurrentUserList == -1) {
|
if (indexInCurrentUserList == -1) {
|
||||||
currentUserStatusList.add(newUserStatusList[i]);
|
currentUserStatusList.add(newUserStatusList[i]);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -285,28 +287,50 @@ class CoreServicesImpl implements CoreServices {
|
||||||
isLoginSuccess = true;
|
isLoginSuccess = true;
|
||||||
addInitListener();
|
addInitListener();
|
||||||
initDataModel();
|
initDataModel();
|
||||||
|
|
||||||
|
if (TencentUtils.checkString(_userID) == null) {
|
||||||
|
V2TimValueCallback<String> getLoginUserRes =
|
||||||
|
await TencentImSDKPlugin.v2TIMManager.getLoginUser();
|
||||||
|
if (getLoginUserRes.code == 0) {
|
||||||
|
_userID = getLoginUserRes.data ?? "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getUsersInfoWithRetry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getUsersInfoWithRetry() async {
|
||||||
|
V2TimValueCallback<List<V2TimUserFullInfo>>? res;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
while (!success) {
|
||||||
|
res = await getUsersInfo(userIDList: [_userID]);
|
||||||
|
if (res.code == 0 &&
|
||||||
|
res.data != null &&
|
||||||
|
res.data!.isNotEmpty &&
|
||||||
|
res.data!.firstWhereOrNull((element) => element.userID == _userID) !=
|
||||||
|
null) {
|
||||||
|
success = true;
|
||||||
|
} else {
|
||||||
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_loginInfo =
|
||||||
|
res?.data!.firstWhereOrNull((element) => element.userID == _userID);
|
||||||
final TUISelfInfoViewModel selfInfoViewModel =
|
final TUISelfInfoViewModel selfInfoViewModel =
|
||||||
serviceLocator<TUISelfInfoViewModel>();
|
serviceLocator<TUISelfInfoViewModel>();
|
||||||
getUsersInfo(userIDList: [_userID]).then((res) => {
|
if (_loginInfo != null) {
|
||||||
if (res.code == 0)
|
selfInfoViewModel.setLoginInfo(_loginInfo);
|
||||||
{
|
}
|
||||||
_loginInfo = res.data![0],
|
|
||||||
selfInfoViewModel.setLoginInfo(_loginInfo!)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated
|
// Deprecated
|
||||||
void didLoginOut() {
|
void didLoginOut() {
|
||||||
removeListener();
|
removeListener();
|
||||||
clearData();
|
clearData();
|
||||||
getUsersInfo(userIDList: [_userID]).then((res) => {
|
_loginInfo = null;
|
||||||
if (res.code == 0)
|
serviceLocator<TUISelfInfoViewModel>().setLoginInfo(_loginInfo);
|
||||||
{
|
|
||||||
_loginInfo = res.data![0],
|
|
||||||
serviceLocator<TUISelfInfoViewModel>().setLoginInfo(_loginInfo!)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -350,10 +374,10 @@ class CoreServicesImpl implements CoreServices {
|
||||||
return TencentImSDKPlugin.v2TIMManager
|
return TencentImSDKPlugin.v2TIMManager
|
||||||
.getOfflinePushManager()
|
.getOfflinePushManager()
|
||||||
.setOfflinePushConfig(
|
.setOfflinePushConfig(
|
||||||
businessID: businessID?.toDouble() ?? 0,
|
businessID: businessID?.toDouble() ?? 0,
|
||||||
token: token,
|
token: token,
|
||||||
isTPNSToken: isTPNSToken,
|
isTPNSToken: isTPNSToken,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,6 @@ class GroupServicesImpl extends GroupServices {
|
||||||
count: count,
|
count: count,
|
||||||
offset: offset);
|
offset: offset);
|
||||||
if (res.code != 0) {
|
if (res.code != 0) {
|
||||||
|
|
||||||
_coreService.callOnCallback(TIMCallback(
|
_coreService.callOnCallback(TIMCallback(
|
||||||
type: TIMCallbackType.API_ERROR,
|
type: TIMCallbackType.API_ERROR,
|
||||||
errorMsg: res.desc,
|
errorMsg: res.desc,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -689,5 +689,13 @@
|
||||||
"k_066fxsz": "查看文件夹",
|
"k_066fxsz": "查看文件夹",
|
||||||
"k_0k432y2": "无法发送,包含文件夹",
|
"k_0k432y2": "无法发送,包含文件夹",
|
||||||
"k_002wb4y": "会话",
|
"k_002wb4y": "会话",
|
||||||
"k_0od4qyh": "视频文件异常"
|
"k_0od4qyh": "视频文件异常",
|
||||||
|
"k_1bfkxg9": "不支持 0KB 文件的传输",
|
||||||
|
"k_0vvsw7g": "文件处理异常",
|
||||||
|
"k_06e224q": "[消息被管理员撤回]",
|
||||||
|
"k_1u1mjcl": "[消息被撤回]",
|
||||||
|
"k_1qcqxea": "选择多个会话",
|
||||||
|
"k_1qgmc20": "选择一个会话",
|
||||||
|
"k_1d8nx6f": "在新窗口中打开",
|
||||||
|
"k_1hz05ax": "正在下载原始资源,请稍候..."
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
||||||
// ignore_for_file: avoid_print
|
// ignore_for_file: avoid_print, empty_catches
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
import 'package:scroll_to_index/scroll_to_index.dart';
|
||||||
|
|
@ -139,11 +139,13 @@ class TIMUIKitChatController {
|
||||||
assert(groupID != null || convType != ConvType.group);
|
assert(groupID != null || convType != ConvType.group);
|
||||||
assert(userID != null || convType != ConvType.c2c);
|
assert(userID != null || convType != ConvType.c2c);
|
||||||
if (isNavigateToMessageListBottom && scrollController != null) {
|
if (isNavigateToMessageListBottom && scrollController != null) {
|
||||||
scrollController!.animateTo(
|
try{
|
||||||
scrollController!.position.minScrollExtent,
|
scrollController?.animateTo(
|
||||||
duration: const Duration(milliseconds: 200),
|
scrollController!.position.minScrollExtent,
|
||||||
curve: Curves.ease,
|
duration: const Duration(milliseconds: 200),
|
||||||
);
|
curve: Curves.ease,
|
||||||
|
);
|
||||||
|
}catch(e){}
|
||||||
}
|
}
|
||||||
return globalChatModel.sendMessageFromController(
|
return globalChatModel.sendMessageFromController(
|
||||||
priority: priority,
|
priority: priority,
|
||||||
|
|
@ -160,11 +162,13 @@ class TIMUIKitChatController {
|
||||||
} else if (model != null) {
|
} else if (model != null) {
|
||||||
/// Sends a message to the current conversation specified on `TIMUIKitChat`. 发送到 `TIMUIKitChat` 中指定的当前对话。
|
/// Sends a message to the current conversation specified on `TIMUIKitChat`. 发送到 `TIMUIKitChat` 中指定的当前对话。
|
||||||
if (isNavigateToMessageListBottom && scrollController != null) {
|
if (isNavigateToMessageListBottom && scrollController != null) {
|
||||||
scrollController?.animateTo(
|
try{
|
||||||
scrollController!.position.minScrollExtent,
|
scrollController?.animateTo(
|
||||||
duration: const Duration(milliseconds: 200),
|
scrollController!.position.minScrollExtent,
|
||||||
curve: Curves.ease,
|
duration: const Duration(milliseconds: 200),
|
||||||
);
|
curve: Curves.ease,
|
||||||
|
);
|
||||||
|
}catch(e){}
|
||||||
}
|
}
|
||||||
return model!.sendMessageFromController(
|
return model!.sendMessageFromController(
|
||||||
priority: priority,
|
priority: priority,
|
||||||
|
|
@ -230,11 +234,13 @@ class TIMUIKitChatController {
|
||||||
assert(groupID != null || convType != ConvType.group);
|
assert(groupID != null || convType != ConvType.group);
|
||||||
assert(userID != null || convType != ConvType.c2c);
|
assert(userID != null || convType != ConvType.c2c);
|
||||||
if (isNavigateToMessageListBottom && scrollController != null) {
|
if (isNavigateToMessageListBottom && scrollController != null) {
|
||||||
scrollController!.animateTo(
|
try{
|
||||||
scrollController!.position.minScrollExtent,
|
scrollController?.animateTo(
|
||||||
duration: const Duration(milliseconds: 200),
|
scrollController!.position.minScrollExtent,
|
||||||
curve: Curves.ease,
|
duration: const Duration(milliseconds: 200),
|
||||||
);
|
curve: Curves.ease,
|
||||||
|
);
|
||||||
|
}catch(e){}
|
||||||
}
|
}
|
||||||
return globalChatModel.sendReplyMessageFromController(
|
return globalChatModel.sendReplyMessageFromController(
|
||||||
text: messageText,
|
text: messageText,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// ignore_for_file: prefer_typing_uninitialized_variables
|
// ignore_for_file: prefer_typing_uninitialized_variables
|
||||||
|
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:tencent_im_base/i18n/i18n_utils.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
|
|
||||||
class TimeAgo {
|
class TimeAgo {
|
||||||
List<String> dayMap() {
|
List<String> dayMap() {
|
||||||
|
|
|
||||||
|
|
@ -1413,7 +1413,7 @@ class _TIMUIKItHistoryMessageListItemState
|
||||||
widget.message.elemType == 6 &&
|
widget.message.elemType == 6 &&
|
||||||
isDownloadWaiting)
|
isDownloadWaiting)
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(top: 2),
|
margin: const EdgeInsets.only(top: 46, right: 10),
|
||||||
child: LoadingAnimationWidget.threeArchedCircle(
|
child: LoadingAnimationWidget.threeArchedCircle(
|
||||||
color: theme.weakTextColor ?? Colors.grey,
|
color: theme.weakTextColor ?? Colors.grey,
|
||||||
size: 20,
|
size: 20,
|
||||||
|
|
@ -1566,7 +1566,7 @@ class _TIMUIKItHistoryMessageListItemState
|
||||||
widget.message.elemType == 6 &&
|
widget.message.elemType == 6 &&
|
||||||
isDownloadWaiting)
|
isDownloadWaiting)
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(top: 24, left: 6),
|
margin: const EdgeInsets.only(top: 46, left: 10),
|
||||||
child: LoadingAnimationWidget.threeArchedCircle(
|
child: LoadingAnimationWidget.threeArchedCircle(
|
||||||
color: theme.weakTextColor ?? Colors.grey,
|
color: theme.weakTextColor ?? Colors.grey,
|
||||||
size: 20,
|
size: 20,
|
||||||
|
|
|
||||||
|
|
@ -104,24 +104,14 @@ class TIMUIKitMessageTooltipState
|
||||||
}
|
}
|
||||||
if (PlatformUtils().isDesktop) {
|
if (PlatformUtils().isDesktop) {
|
||||||
if (widget.message.fileElem != null) {
|
if (widget.message.fileElem != null) {
|
||||||
if (globalModal.getMessageProgress(widget.message.msgID) == 100) {
|
String savePath = TencentUtils.checkString(
|
||||||
String savePath =
|
globalModal.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
||||||
globalModal.getFileMessageLocation(widget.message.msgID);
|
widget.message.fileElem?.path ??
|
||||||
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);
|
File f = File(savePath);
|
||||||
if (f.existsSync() && widget.message.msgID != null) {
|
if (f.existsSync() && widget.message.msgID != null) {
|
||||||
filePath = savePath;
|
filePath = savePath;
|
||||||
globalModal.setMessageProgress(widget.message.msgID!, 100);
|
|
||||||
isShowOpenFile = true;
|
isShowOpenFile = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -399,14 +389,14 @@ class TIMUIKitMessageTooltipState
|
||||||
}
|
}
|
||||||
|
|
||||||
_onOpenDesktop(String path) {
|
_onOpenDesktop(String path) {
|
||||||
if (PlatformUtils().isDesktop) {
|
try {
|
||||||
OpenFile.open(path);
|
if (PlatformUtils().isDesktop && !PlatformUtils().isWindows) {
|
||||||
} else {
|
launchUrl(Uri.file(path));
|
||||||
launchUrl(
|
} else {
|
||||||
Uri.parse(path),
|
OpenFile.open(path);
|
||||||
mode: LaunchMode.externalApplication,
|
}
|
||||||
);
|
// ignore: empty_catches
|
||||||
}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTap(String operation, TUIChatSeparateViewModel model) async {
|
_onTap(String operation, TUIChatSeparateViewModel model) async {
|
||||||
|
|
@ -415,32 +405,40 @@ class TIMUIKitMessageTooltipState
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case "open":
|
case "open":
|
||||||
if (widget.message.fileElem != null) {
|
if (widget.message.fileElem != null) {
|
||||||
_onOpenDesktop(widget.message.fileElem!.localUrl ??
|
_onOpenDesktop(TencentUtils.checkString(
|
||||||
|
globalModal.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
||||||
widget.message.fileElem?.path ??
|
widget.message.fileElem?.path ??
|
||||||
"");
|
"");
|
||||||
} else if (widget.message.imageElem != null) {
|
} else if (widget.message.imageElem != null) {
|
||||||
_onOpenDesktop(widget.message.imageElem!.imageList?[0]?.localUrl ??
|
_onOpenDesktop(TencentUtils.checkString(
|
||||||
widget.message.imageElem?.path ??
|
widget.message.imageElem!.imageList?[0]?.localUrl) ??
|
||||||
|
TencentUtils.checkString(widget.message.imageElem?.path) ??
|
||||||
"");
|
"");
|
||||||
} else if (widget.message.videoElem != null) {
|
} else if (widget.message.videoElem != null) {
|
||||||
_onOpenDesktop(widget.message.videoElem!.localVideoUrl ??
|
_onOpenDesktop(TencentUtils.checkString(
|
||||||
widget.message.videoElem?.videoPath ??
|
widget.message.videoElem!.localVideoUrl) ??
|
||||||
|
TencentUtils.checkString(widget.message.videoElem?.videoPath) ??
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "finder":
|
case "finder":
|
||||||
String savePath = "";
|
String savePath = "";
|
||||||
if (widget.message.fileElem != null) {
|
if (widget.message.fileElem != null) {
|
||||||
savePath = (widget.message.fileElem!.localUrl ??
|
savePath = (TencentUtils.checkString(
|
||||||
|
globalModal.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
||||||
widget.message.fileElem?.path ??
|
widget.message.fileElem?.path ??
|
||||||
"");
|
"");
|
||||||
} else if (widget.message.imageElem != null) {
|
} else if (widget.message.imageElem != null) {
|
||||||
savePath = (widget.message.imageElem!.imageList?[0]?.localUrl ??
|
savePath = (TencentUtils.checkString(
|
||||||
widget.message.imageElem?.path ??
|
widget.message.imageElem!.imageList?[0]?.localUrl) ??
|
||||||
|
TencentUtils.checkString(widget.message.imageElem?.path) ??
|
||||||
"");
|
"");
|
||||||
} else if (widget.message.videoElem != null) {
|
} else if (widget.message.videoElem != null) {
|
||||||
savePath = (widget.message.videoElem!.localVideoUrl ??
|
savePath = (TencentUtils.checkString(
|
||||||
widget.message.videoElem?.videoPath ??
|
widget.message.videoElem!.localVideoUrl) ??
|
||||||
|
TencentUtils.checkString(widget.message.videoElem?.videoPath) ??
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
final String fileDir = path.dirname(savePath);
|
final String fileDir = path.dirname(savePath);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import 'package:tencent_cloud_chat_uikit/data_services/group/group_services.dart
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||||
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar_title.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitAppBar/tim_uikit_appbar_title.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.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_base.dart';
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tencent_im_base/i18n/i18n_utils.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
|
|
||||||
class TIMUIKitAppBarTitle extends StatelessWidget {
|
class TIMUIKitAppBarTitle extends StatelessWidget {
|
||||||
final Widget? title;
|
final Widget? title;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'dart:math';
|
||||||
|
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:loading_animation_widget/loading_animation_widget.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/permission.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/permission.dart';
|
||||||
import 'package:tencent_open_file/tencent_open_file.dart';
|
import 'package:tencent_open_file/tencent_open_file.dart';
|
||||||
|
|
@ -49,10 +50,12 @@ class TIMUIKitFileElem extends StatefulWidget {
|
||||||
|
|
||||||
class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
String filePath = "";
|
String filePath = "";
|
||||||
bool isDownloading = false;
|
bool isWebDownloading = false;
|
||||||
final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>();
|
final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>();
|
||||||
int downloadProgress = 0;
|
int downloadProgress = 0;
|
||||||
late V2TimAdvancedMsgListener advancedMsgListener;
|
late V2TimAdvancedMsgListener advancedMsgListener;
|
||||||
|
final GlobalKey containerKey = GlobalKey();
|
||||||
|
double? containerHeight;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
|
@ -75,18 +78,18 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
(V2TimMessageDownloadProgress messageProgress) async {
|
(V2TimMessageDownloadProgress messageProgress) async {
|
||||||
if (messageProgress.msgID == widget.message.msgID) {
|
if (messageProgress.msgID == widget.message.msgID) {
|
||||||
if (messageProgress.isFinish) {
|
if (messageProgress.isFinish) {
|
||||||
if(mounted){
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
downloadProgress = 100;
|
downloadProgress = 100;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(mounted){
|
final currentProgress =
|
||||||
|
(messageProgress.currentSize / messageProgress.totalSize * 100)
|
||||||
|
.floor();
|
||||||
|
if (mounted && currentProgress > downloadProgress) {
|
||||||
setState(() {
|
setState(() {
|
||||||
downloadProgress = (messageProgress.currentSize /
|
downloadProgress = currentProgress;
|
||||||
messageProgress.totalSize *
|
|
||||||
100)
|
|
||||||
.ceil();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,30 +113,22 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
String savePath = TencentUtils.checkString(
|
||||||
if (model.getMessageProgress(widget.messageID) == 100 ||
|
model.getFileMessageLocation(widget.messageID)) ??
|
||||||
downloadProgress == 100) {
|
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
||||||
String savePath =
|
widget.message.fileElem?.path ??
|
||||||
TencentUtils.checkString(widget.message.fileElem!.localUrl) ??
|
'';
|
||||||
model.getFileMessageLocation(widget.messageID);
|
|
||||||
File f = File(savePath);
|
|
||||||
if (f.existsSync() && widget.messageID != null) {
|
|
||||||
filePath = savePath;
|
|
||||||
setState(() {
|
|
||||||
downloadProgress = 100;
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String savePath = widget.message.fileElem!.localUrl ?? '';
|
|
||||||
File f = File(savePath);
|
File f = File(savePath);
|
||||||
if (f.existsSync() && widget.messageID != null) {
|
if (f.existsSync() && widget.messageID != null) {
|
||||||
filePath = savePath;
|
filePath = savePath;
|
||||||
setState(() {
|
if (downloadProgress != 100) {
|
||||||
downloadProgress = 100;
|
setState(() {
|
||||||
});
|
downloadProgress = 100;
|
||||||
model.setMessageProgress(widget.messageID!, 100);
|
});
|
||||||
|
}
|
||||||
|
if (model.getMessageProgress(widget.messageID) != 100) {
|
||||||
|
model.setMessageProgress(widget.messageID!, 100);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -151,10 +146,12 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addUrlToWaitingPath() async {
|
addUrlToWaitingPath(TUITheme theme) async {
|
||||||
if (widget.messageID != null) {
|
if (widget.messageID != null) {
|
||||||
model.addWaitingList(widget.messageID!);
|
model.addWaitingList(widget.messageID!);
|
||||||
print("add path success");
|
}
|
||||||
|
if (model.getWaitingListLength() == 1) {
|
||||||
|
await downloadFile(theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,7 +192,25 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
await model.downloadFile();
|
await model.downloadFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> hasZeroSize(String filePath) async {
|
||||||
|
try {
|
||||||
|
final file = File(filePath);
|
||||||
|
final fileSize = await file.length();
|
||||||
|
return fileSize == 0;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tryOpenFile(context, theme) async {
|
tryOpenFile(context, theme) async {
|
||||||
|
if (!PlatformUtils().isWeb &&
|
||||||
|
(await hasZeroSize(filePath) || widget.message.status == 3)) {
|
||||||
|
onTIMCallback(TIMCallback(
|
||||||
|
type: TIMCallbackType.INFO,
|
||||||
|
infoRecommendText: "不支持 0KB 文件的传输",
|
||||||
|
infoCode: 6660417));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (PlatformUtils().isMobile) {
|
if (PlatformUtils().isMobile) {
|
||||||
if (PlatformUtils().isIOS) {
|
if (PlatformUtils().isIOS) {
|
||||||
if (!await Permissions.checkPermission(
|
if (!await Permissions.checkPermission(
|
||||||
|
|
@ -229,6 +244,11 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void downloadWebFile(String fileUrl) async {
|
void downloadWebFile(String fileUrl) async {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
isWebDownloading = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
String fileName = Uri.parse(fileUrl).pathSegments.last;
|
String fileName = Uri.parse(fileUrl).pathSegments.last;
|
||||||
try {
|
try {
|
||||||
http.Response response = await http.get(
|
http.Response response = await http.get(
|
||||||
|
|
@ -255,6 +275,11 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
..style.display = "none"
|
..style.display = "none"
|
||||||
..click();
|
..click();
|
||||||
}
|
}
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
isWebDownloading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -280,111 +305,144 @@ class _TIMUIKitFileElemState extends TIMUIKitState<TIMUIKitFileElem> {
|
||||||
final String fileName = widget.fileElem!.fileName!;
|
final String fileName = widget.fileElem!.fileName!;
|
||||||
fileFormat = fileName.split(".")[max(fileName.split(".").length - 1, 0)];
|
fileFormat = fileName.split(".")[max(fileName.split(".").length - 1, 0)];
|
||||||
}
|
}
|
||||||
return TIMUIKitMessageReactionWrapper(
|
final RenderBox? containerRenderBox =
|
||||||
chatModel: widget.chatModel,
|
containerKey.currentContext?.findRenderObject() as RenderBox?;
|
||||||
isShowJump: widget.isShowJump,
|
if (containerRenderBox != null) {
|
||||||
clearJump: widget.clearJump,
|
containerHeight = containerRenderBox.size.height;
|
||||||
isFromSelf: widget.message.isSelf ?? true,
|
}
|
||||||
isShowMessageReaction: widget.isShowMessageReaction ?? true,
|
|
||||||
message: widget.message,
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () async {
|
|
||||||
if (PlatformUtils().isWeb) {
|
|
||||||
downloadWebFile(widget.fileElem?.path ?? "");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (await hasFile()) {
|
|
||||||
if (received == 100) {
|
|
||||||
tryOpenFile(context, theme);
|
|
||||||
} else {
|
|
||||||
// 正在下载中,文件可能不完整
|
|
||||||
onTIMCallback(
|
|
||||||
TIMCallback(
|
|
||||||
type: TIMCallbackType.INFO,
|
|
||||||
infoRecommendText: TIM_t("正在下载中"),
|
|
||||||
infoCode: 6660411,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkIsWaiting()) {
|
return Row(
|
||||||
onTIMCallback(
|
key: containerKey,
|
||||||
TIMCallback(
|
mainAxisSize: MainAxisSize.min,
|
||||||
type: TIMCallbackType.INFO,
|
children: [
|
||||||
infoRecommendText: TIM_t("已加入待下载队列,其他文件下载中"),
|
if (widget.isSelf && isWebDownloading)
|
||||||
infoCode: 6660413),
|
Container(
|
||||||
);
|
margin: const EdgeInsets.only(top: 2),
|
||||||
return;
|
child: LoadingAnimationWidget.threeArchedCircle(
|
||||||
} else {
|
color: theme.weakTextColor ?? Colors.grey,
|
||||||
await addUrlToWaitingPath();
|
size: 20,
|
||||||
}
|
),
|
||||||
await downloadFile(theme);
|
),
|
||||||
},
|
TIMUIKitMessageReactionWrapper(
|
||||||
child: Container(
|
chatModel: widget.chatModel,
|
||||||
width: 237,
|
isShowJump: widget.isShowJump,
|
||||||
decoration: BoxDecoration(
|
clearJump: widget.clearJump,
|
||||||
border: Border.all(
|
isFromSelf: widget.message.isSelf ?? true,
|
||||||
color:
|
isShowMessageReaction: widget.isShowMessageReaction ?? true,
|
||||||
theme.weakDividerColor ?? CommonColor.weakDividerColor,
|
message: widget.message,
|
||||||
),
|
child: GestureDetector(
|
||||||
borderRadius: borderRadius),
|
onTap: () async {
|
||||||
child: Stack(children: [
|
try {
|
||||||
ClipRRect(
|
if (PlatformUtils().isWeb) {
|
||||||
//剪裁为圆角矩形
|
if (!isWebDownloading) {
|
||||||
borderRadius: borderRadius,
|
downloadWebFile(widget.fileElem?.path ?? "");
|
||||||
child: LinearProgressIndicator(
|
}
|
||||||
minHeight: 66,
|
return;
|
||||||
value: (received == 100 ? 0 : received) / 100,
|
}
|
||||||
backgroundColor: received == 100
|
if (await hasFile()) {
|
||||||
? theme.weakBackgroundColor
|
if (received == 100) {
|
||||||
: Colors.white,
|
tryOpenFile(context, theme);
|
||||||
valueColor: AlwaysStoppedAnimation(
|
} else {
|
||||||
theme.lightPrimaryMaterialColor.shade50)),
|
onTIMCallback(
|
||||||
),
|
TIMCallback(
|
||||||
Padding(
|
type: TIMCallbackType.INFO,
|
||||||
padding:
|
infoRecommendText: TIM_t("正在下载中"),
|
||||||
const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
infoCode: 6660411,
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: widget.isSelf
|
|
||||||
? MainAxisAlignment.end
|
|
||||||
: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
constraints:
|
|
||||||
const BoxConstraints(maxWidth: 160),
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (buildContext, boxConstraints) {
|
|
||||||
return CustomText(
|
|
||||||
fileName,
|
|
||||||
width: boxConstraints.maxWidth,
|
|
||||||
style: TextStyle(
|
|
||||||
color: theme.darkTextColor,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (fileSize != null)
|
|
||||||
Text(
|
|
||||||
showFileSize(fileSize),
|
|
||||||
// "${received > 0 ? (received / 1024).ceil() : (received / 1024).ceil()} KB",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14, color: theme.weakTextColor),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
TIMUIKitFileIcon(
|
|
||||||
fileFormat: fileFormat,
|
|
||||||
),
|
),
|
||||||
])),
|
);
|
||||||
]),
|
}
|
||||||
)));
|
return;
|
||||||
|
}
|
||||||
|
if (checkIsWaiting()) {
|
||||||
|
onTIMCallback(
|
||||||
|
TIMCallback(
|
||||||
|
type: TIMCallbackType.INFO,
|
||||||
|
infoRecommendText: TIM_t("已加入待下载队列,其他文件下载中"),
|
||||||
|
infoCode: 6660413),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
await addUrlToWaitingPath(theme);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
onTIMCallback(TIMCallback(
|
||||||
|
type: TIMCallbackType.INFO,
|
||||||
|
infoRecommendText: "文件处理异常",
|
||||||
|
infoCode: 6660416));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 237,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: theme.weakDividerColor ??
|
||||||
|
CommonColor.weakDividerColor,
|
||||||
|
),
|
||||||
|
borderRadius: borderRadius),
|
||||||
|
child: Stack(children: [
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: borderRadius,
|
||||||
|
child: LinearProgressIndicator(
|
||||||
|
minHeight: ((containerHeight) ?? 72) - 6,
|
||||||
|
value: (received == 100 ? 0 : received) / 100,
|
||||||
|
backgroundColor: received == 100
|
||||||
|
? theme.weakBackgroundColor
|
||||||
|
: Colors.white,
|
||||||
|
valueColor: AlwaysStoppedAnimation(
|
||||||
|
theme.lightPrimaryMaterialColor.shade50)),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 8, horizontal: 12),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: widget.isSelf
|
||||||
|
? MainAxisAlignment.end
|
||||||
|
: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
constraints:
|
||||||
|
const BoxConstraints(maxWidth: 160),
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (buildContext, boxConstraints) {
|
||||||
|
return CustomText(
|
||||||
|
fileName,
|
||||||
|
width: boxConstraints.maxWidth,
|
||||||
|
style: TextStyle(
|
||||||
|
color: theme.darkTextColor,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (fileSize != null)
|
||||||
|
Text(
|
||||||
|
showFileSize(fileSize),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: theme.weakTextColor),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
TIMUIKitFileIcon(
|
||||||
|
fileFormat: fileFormat,
|
||||||
|
),
|
||||||
|
])),
|
||||||
|
]),
|
||||||
|
))),
|
||||||
|
if (!widget.isSelf && isWebDownloading)
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 2),
|
||||||
|
child: LoadingAnimationWidget.threeArchedCircle(
|
||||||
|
color: theme.weakTextColor ?? Colors.grey,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import 'package:http/http.dart' as http;
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/message/message_services.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/message/message_services.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
||||||
import 'package:tencent_open_file/tencent_open_file.dart';
|
import 'package:tencent_open_file/tencent_open_file.dart';
|
||||||
import 'package:universal_html/html.dart' as html;
|
import 'package:universal_html/html.dart' as html;
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
@ -68,7 +69,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getBigPicUrl() {
|
String getOriginImgURL() {
|
||||||
// 实际拿的是原图
|
// 实际拿的是原图
|
||||||
V2TimImage? img = MessageUtils.getImageFromImgList(
|
V2TimImage? img = MessageUtils.getImageFromImgList(
|
||||||
widget.message.imageElem!.imageList,
|
widget.message.imageElem!.imageList,
|
||||||
|
|
@ -257,7 +258,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
return await _saveImageToLocal(context, path,
|
return await _saveImageToLocal(context, path,
|
||||||
isAsset: true, theme: theme);
|
isAsset: true, theme: theme);
|
||||||
} else {
|
} else {
|
||||||
String imgUrl = getBigPicUrl();
|
String imgUrl = getOriginImgURL();
|
||||||
if (widget.message.imageElem!.imageList![0]!.localUrl != '' &&
|
if (widget.message.imageElem!.imageList![0]!.localUrl != '' &&
|
||||||
widget.message.imageElem!.imageList![0]!.localUrl != null) {
|
widget.message.imageElem!.imageList![0]!.localUrl != null) {
|
||||||
File f = File(widget.message.imageElem!.imageList![0]!.localUrl!);
|
File f = File(widget.message.imageElem!.imageList![0]!.localUrl!);
|
||||||
|
|
@ -300,6 +301,14 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void launchDesktopFile(String path) {
|
||||||
|
if (PlatformUtils().isWindows) {
|
||||||
|
OpenFile.open(path);
|
||||||
|
} else {
|
||||||
|
launchUrl(Uri.file(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget errorPage(theme) => Container(
|
Widget errorPage(theme) => Container(
|
||||||
height: MediaQuery.of(context).size.height,
|
height: MediaQuery.of(context).size.height,
|
||||||
color: theme.black,
|
color: theme.black,
|
||||||
|
|
@ -310,16 +319,85 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
child: errorDisplay(context, theme),
|
child: errorDisplay(context, theme),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
bool checkIfDownloadSuccess() {
|
||||||
|
final localUrl = TencentUtils.checkString(
|
||||||
|
model.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
widget.message.imageElem!.imageList![0]!.localUrl;
|
||||||
|
return TencentUtils.checkString(localUrl) != null &&
|
||||||
|
File(localUrl!).existsSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onClickOpenImageInNewWindow() {
|
||||||
|
final localUrl = TencentUtils.checkString(
|
||||||
|
model.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
widget.message.imageElem!.imageList![0]!.localUrl;
|
||||||
|
Future.delayed(const Duration(milliseconds: 0), () async {
|
||||||
|
final isDownloaded = checkIfDownloadSuccess();
|
||||||
|
if (isDownloaded) {
|
||||||
|
launchDesktopFile(localUrl ?? "");
|
||||||
|
} else {
|
||||||
|
onTIMCallback(TIMCallback(
|
||||||
|
infoCode: 6660414,
|
||||||
|
infoRecommendText: TIM_t("正在下载原始资源,请稍候..."),
|
||||||
|
type: TIMCallbackType.INFO));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleOnTapPreviewImageOnDesktop({
|
||||||
|
double? positionRadio,
|
||||||
|
String? originImgUrl,
|
||||||
|
}) {
|
||||||
|
final localUrl = TencentUtils.checkString(
|
||||||
|
model.getFileMessageLocation(widget.message.msgID)) ??
|
||||||
|
widget.message.imageElem!.imageList![0]!.localUrl;
|
||||||
|
if (checkIfDownloadSuccess()) {
|
||||||
|
TUIKitWidePopup.showMedia(
|
||||||
|
aspectRatio: positionRadio,
|
||||||
|
context: context,
|
||||||
|
mediaLocalPath: localUrl ?? "",
|
||||||
|
onClickOrigin: () => _onClickOpenImageInNewWindow());
|
||||||
|
} else {
|
||||||
|
if (TencentUtils.checkString(originImgUrl) != null) {
|
||||||
|
TUIKitWidePopup.showMedia(
|
||||||
|
aspectRatio: positionRadio,
|
||||||
|
context: context,
|
||||||
|
mediaURL: originImgUrl,
|
||||||
|
onClickOrigin: () => _onClickOpenImageInNewWindow());
|
||||||
|
} else {
|
||||||
|
onTIMCallback(TIMCallback(
|
||||||
|
infoCode: 6660414,
|
||||||
|
infoRecommendText: TIM_t("正在下载中"),
|
||||||
|
type: TIMCallbackType.INFO));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget _renderNetworkImage(
|
Widget _renderNetworkImage(
|
||||||
dynamic heroTag, double? positionRadio, TUITheme? theme,
|
dynamic heroTag, double? positionRadio, TUITheme? theme,
|
||||||
{String? path, V2TimImage? originalImg, V2TimImage? smallImg}) {
|
{String? path, V2TimImage? originalImg, V2TimImage? smallImg}) {
|
||||||
try {
|
try {
|
||||||
final isDesktopScreen =
|
String originImgUrl = originalImg?.url ?? getOriginImgURL();
|
||||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
if (originImgUrl.isEmpty && smallImg?.url != null) {
|
||||||
String bigImgUrl = originalImg?.url ?? getBigPicUrl();
|
originImgUrl = smallImg!.url!;
|
||||||
if (bigImgUrl.isEmpty && smallImg?.url != null) {
|
|
||||||
bigImgUrl = smallImg!.url!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final imageWidget = Hero(
|
||||||
|
tag: heroTag,
|
||||||
|
child: PlatformUtils().isWeb
|
||||||
|
? Image.network(path ?? smallImg?.url ?? originalImg!.url!,
|
||||||
|
fit: BoxFit.contain)
|
||||||
|
: CachedNetworkImage(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
imageUrl: path ?? smallImg?.url ?? originalImg!.url!,
|
||||||
|
errorWidget: (context, error, stackTrace) => errorPage(theme),
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
cacheKey: smallImg?.uuid ?? originalImg!.uuid,
|
||||||
|
placeholder: (context, url) =>
|
||||||
|
Image(image: MemoryImage(kTransparentImage)),
|
||||||
|
fadeInDuration: const Duration(milliseconds: 0),
|
||||||
|
));
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
alignment: widget.message.isSelf ?? true
|
alignment: widget.message.isSelf ?? true
|
||||||
? AlignmentDirectional.topEnd
|
? AlignmentDirectional.topEnd
|
||||||
|
|
@ -327,40 +405,30 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
children: [
|
children: [
|
||||||
getImage(
|
getImage(
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
launchUrl(
|
TUIKitWidePopup.showMedia(
|
||||||
Uri.parse(widget.message.imageElem?.path ?? ""),
|
aspectRatio: positionRadio,
|
||||||
mode: LaunchMode.externalApplication,
|
context: context,
|
||||||
);
|
mediaURL: widget.message.imageElem?.path ?? "",
|
||||||
|
onClickOrigin: () => launchUrl(
|
||||||
|
Uri.parse(widget.message.imageElem?.path ?? ""),
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isDesktopScreen) {
|
if (PlatformUtils().isDesktop) {
|
||||||
if (TencentUtils.checkString(widget
|
_handleOnTapPreviewImageOnDesktop(
|
||||||
.message.imageElem!.imageList![0]!.localUrl) !=
|
positionRadio: positionRadio,
|
||||||
null &&
|
originImgUrl: originImgUrl,
|
||||||
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 {
|
} else {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
PageRouteBuilder(
|
PageRouteBuilder(
|
||||||
opaque: false, // set to false
|
opaque: false, // set to false
|
||||||
pageBuilder: (_, __, ___) => ImageScreen(
|
pageBuilder: (_, __, ___) => ImageScreen(
|
||||||
imageProvider: CachedNetworkImageProvider(
|
imageProvider: CachedNetworkImageProvider(
|
||||||
path ?? bigImgUrl,
|
path ?? originImgUrl,
|
||||||
cacheKey: widget.message.msgID,
|
cacheKey: widget.message.msgID,
|
||||||
),
|
),
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
|
|
@ -371,32 +439,12 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: positionRadio != null
|
||||||
constraints:
|
? AspectRatio(
|
||||||
const BoxConstraints(minWidth: 20, minHeight: 20),
|
aspectRatio: positionRadio,
|
||||||
child: Hero(
|
child: imageWidget,
|
||||||
tag: heroTag,
|
)
|
||||||
child: PlatformUtils().isWeb
|
: imageWidget,
|
||||||
? Image.network(
|
|
||||||
path ?? smallImg?.url ?? originalImg!.url!,
|
|
||||||
fit: BoxFit.contain)
|
|
||||||
:
|
|
||||||
// Image.network(smallImg?.url ?? ""),
|
|
||||||
CachedNetworkImage(
|
|
||||||
// width: double.infinity,
|
|
||||||
alignment: Alignment.topCenter,
|
|
||||||
imageUrl:
|
|
||||||
path ?? smallImg?.url ?? originalImg!.url!,
|
|
||||||
// use small image in message list as priority
|
|
||||||
errorWidget: (context, error, stackTrace) =>
|
|
||||||
errorPage(theme),
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
cacheKey: smallImg?.uuid ?? originalImg!.uuid,
|
|
||||||
placeholder: (context, url) =>
|
|
||||||
Image(image: MemoryImage(kTransparentImage)),
|
|
||||||
fadeInDuration: const Duration(milliseconds: 0),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
imageElem: e)
|
imageElem: e)
|
||||||
],
|
],
|
||||||
|
|
@ -436,6 +484,25 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
final isDesktopScreen =
|
final isDesktopScreen =
|
||||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||||
|
|
||||||
|
final imageWidget = Hero(
|
||||||
|
tag: heroTag,
|
||||||
|
child: preloadImage != null
|
||||||
|
? FittedBox(
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
child: RawImage(
|
||||||
|
image: preloadImage,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: FittedBox(
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
child: Image.file(
|
||||||
|
File(smallImage),
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
alignment: AlignmentDirectional.topStart,
|
alignment: AlignmentDirectional.topStart,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -450,11 +517,11 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (PlatformUtils().isDesktop) {
|
if (PlatformUtils().isDesktop) {
|
||||||
if (PlatformUtils().isWindows) {
|
TUIKitWidePopup.showMedia(
|
||||||
OpenFile.open(showImage);
|
aspectRatio: positionRadio,
|
||||||
} else {
|
mediaLocalPath: showImage,
|
||||||
launchUrl(Uri.file(showImage));
|
context: context,
|
||||||
}
|
onClickOrigin: () => launchDesktopFile(showImage));
|
||||||
} else {
|
} else {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
PageRouteBuilder(
|
PageRouteBuilder(
|
||||||
|
|
@ -470,22 +537,12 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: positionRadio != null
|
||||||
constraints:
|
? AspectRatio(
|
||||||
const BoxConstraints(minWidth: 20, minHeight: 20),
|
aspectRatio: positionRadio,
|
||||||
child: Hero(
|
child: imageWidget,
|
||||||
tag: heroTag,
|
)
|
||||||
child: preloadImage != null
|
: imageWidget),
|
||||||
? RawImage(
|
|
||||||
image: preloadImage,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
)
|
|
||||||
: Image.file(
|
|
||||||
File(smallImage),
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
imageElem: null)
|
imageElem: null)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
@ -623,6 +680,8 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
if (widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING) {
|
if (widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING) {
|
||||||
isSent = true;
|
isSent = true;
|
||||||
}
|
}
|
||||||
|
final isDesktopScreen =
|
||||||
|
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||||
final heroTag =
|
final heroTag =
|
||||||
"${widget.message.msgID ?? widget.message.id ?? widget.message.timestamp ?? DateTime.now().millisecondsSinceEpoch}${widget.isFrom}";
|
"${widget.message.msgID ?? widget.message.id ?? widget.message.timestamp ?? DateTime.now().millisecondsSinceEpoch}${widget.isFrom}";
|
||||||
|
|
||||||
|
|
@ -639,7 +698,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
builder: (BuildContext context, BoxConstraints constraints) {
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
return ConstrainedBox(
|
return ConstrainedBox(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
maxWidth: constraints.maxWidth * 0.5,
|
maxWidth: constraints.maxWidth * (isDesktopScreen ? 0.4 : 0.5),
|
||||||
minWidth: 64,
|
minWidth: 64,
|
||||||
maxHeight: 256,
|
maxHeight: 256,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/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/TIMUIKitMessageReaction/tim_uikit_message_reaction_wrapper.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/video_screen.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/video_screen.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
||||||
import 'package:tencent_open_file/tencent_open_file.dart';
|
import 'package:tencent_open_file/tencent_open_file.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
|
@ -166,6 +167,15 @@ class _TIMUIKitVideoElemState extends TIMUIKitState<TIMUIKitVideoElem> {
|
||||||
downloadMessageDetailAndSave();
|
downloadMessageDetailAndSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void launchDesktopFile(String path) {
|
||||||
|
if (PlatformUtils().isWindows) {
|
||||||
|
OpenFile.open(path);
|
||||||
|
} else {
|
||||||
|
launchUrl(Uri.file(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||||
final theme = value.theme;
|
final theme = value.theme;
|
||||||
|
|
@ -175,10 +185,14 @@ class _TIMUIKitVideoElemState extends TIMUIKitState<TIMUIKitVideoElem> {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
launchUrl(
|
final url = widget.message.videoElem?.videoUrl ?? widget.message.videoElem?.videoPath ?? "";
|
||||||
Uri.parse(widget.message.videoElem?.videoPath ?? ""),
|
TUIKitWidePopup.showMedia(
|
||||||
mode: LaunchMode.externalApplication,
|
context: context,
|
||||||
);
|
mediaURL: url,
|
||||||
|
onClickOrigin: () => launchUrl(
|
||||||
|
Uri.parse(url),
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (PlatformUtils().isDesktop) {
|
if (PlatformUtils().isDesktop) {
|
||||||
|
|
@ -188,19 +202,20 @@ class _TIMUIKitVideoElemState extends TIMUIKitState<TIMUIKitVideoElem> {
|
||||||
TencentUtils.checkString(videoElem.localVideoUrl);
|
TencentUtils.checkString(videoElem.localVideoUrl);
|
||||||
final videoPath = TencentUtils.checkString(videoElem.videoPath);
|
final videoPath = TencentUtils.checkString(videoElem.videoPath);
|
||||||
final videoUrl = videoElem.videoUrl;
|
final videoUrl = videoElem.videoUrl;
|
||||||
|
|
||||||
if (localVideoUrl != null) {
|
if (localVideoUrl != null) {
|
||||||
if (PlatformUtils().isWindows) {
|
launchDesktopFile(localVideoUrl);
|
||||||
OpenFile.open(localVideoUrl);
|
// todo
|
||||||
} else {
|
// TUIKitWidePopup.showMedia(
|
||||||
launchUrl(Uri.file(localVideoUrl));
|
// context: context,
|
||||||
}
|
// mediaPath: localVideoUrl,
|
||||||
|
// onClickOrigin: () => launchDesktopFile(localVideoUrl));
|
||||||
} else if (videoPath != null) {
|
} else if (videoPath != null) {
|
||||||
if (PlatformUtils().isWindows) {
|
launchDesktopFile(videoPath);
|
||||||
OpenFile.open(videoPath);
|
// todo
|
||||||
} else {
|
// TUIKitWidePopup.showMedia(
|
||||||
launchUrl(Uri.file(videoPath));
|
// context: context,
|
||||||
}
|
// mediaPath: videoPath,
|
||||||
|
// onClickOrigin: () => launchDesktopFile(videoPath));
|
||||||
} else if (TencentUtils.isTextNotEmpty(videoUrl)) {
|
} else if (TencentUtils.isTextNotEmpty(videoUrl)) {
|
||||||
onTIMCallback(TIMCallback(
|
onTIMCallback(TIMCallback(
|
||||||
infoCode: 6660414,
|
infoCode: 6660414,
|
||||||
|
|
|
||||||
|
|
@ -455,9 +455,16 @@ class _MorePanelState extends TIMUIKitState<MorePanel> {
|
||||||
TUITheme theme,
|
TUITheme theme,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
|
if (!await Permissions.checkPermission(
|
||||||
|
context,
|
||||||
|
Permission.camera.value,
|
||||||
|
theme,
|
||||||
|
)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!await Permissions.checkPermission(
|
if (!await Permissions.checkPermission(
|
||||||
context,
|
context,
|
||||||
Permission.camera.value,
|
Permission.photos.value,
|
||||||
theme,
|
theme,
|
||||||
)) {
|
)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ class TIMUIKitInputTextField extends StatefulWidget {
|
||||||
/// conversation id
|
/// conversation id
|
||||||
final String conversationID;
|
final String conversationID;
|
||||||
|
|
||||||
|
final TIMUIKitChatConfig? chatConfig;
|
||||||
|
|
||||||
/// conversation type
|
/// conversation type
|
||||||
final ConvType conversationType;
|
final ConvType conversationType;
|
||||||
|
|
||||||
|
|
@ -116,7 +118,8 @@ class TIMUIKitInputTextField extends StatefulWidget {
|
||||||
required this.currentConversation,
|
required this.currentConversation,
|
||||||
this.groupType,
|
this.groupType,
|
||||||
this.atMemberPanelScroll,
|
this.atMemberPanelScroll,
|
||||||
this.groupID})
|
this.groupID,
|
||||||
|
this.chatConfig})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -147,15 +150,51 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
currentCursor = value;
|
currentCursor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deleteStickerFromText() {
|
||||||
|
String originalText = textEditingController.text;
|
||||||
|
String text;
|
||||||
|
final cursorPosition =
|
||||||
|
currentCursor ?? originalText.length;
|
||||||
|
|
||||||
|
if (originalText == zeroWidthSpace) {
|
||||||
|
_handleSoftKeyBoardDelete();
|
||||||
|
} else if (originalText.isNotEmpty) {
|
||||||
|
if (cursorPosition == originalText.length) {
|
||||||
|
text = originalText.characters.skipLast(1).toString();
|
||||||
|
currentCursor = null;
|
||||||
|
} else if (cursorPosition > 0 && cursorPosition < originalText.length) {
|
||||||
|
final firstString = originalText.substring(0, cursorPosition - 2);
|
||||||
|
final secondString = originalText.substring(cursorPosition);
|
||||||
|
text = '$firstString$secondString';
|
||||||
|
if(currentCursor != null){
|
||||||
|
currentCursor = currentCursor! - 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text = originalText.characters.skipLast(1).toString();
|
||||||
|
currentCursor = null;
|
||||||
|
}
|
||||||
|
textEditingController.text = text;
|
||||||
|
|
||||||
|
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
||||||
|
textEditingController.selection = TextSelection.fromPosition(TextPosition(
|
||||||
|
offset: currentCursor ?? textEditingController.text.length));
|
||||||
|
focusNode.requestFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void addStickerToText(String sticker) {
|
void addStickerToText(String sticker) {
|
||||||
final oldText = textEditingController.text;
|
final currentText = textEditingController.text;
|
||||||
if (currentCursor != null && currentCursor! > -1) {
|
if (currentCursor != null &&
|
||||||
final firstString = oldText.substring(0, currentCursor);
|
currentCursor! > -1 &&
|
||||||
final secondString = oldText.substring(currentCursor!);
|
currentCursor! < currentText.length + 1) {
|
||||||
|
final firstString = currentText.substring(0, currentCursor);
|
||||||
|
final secondString = currentText.substring(currentCursor!);
|
||||||
currentCursor = currentCursor! + sticker.length;
|
currentCursor = currentCursor! + sticker.length;
|
||||||
textEditingController.text = "$firstString$sticker$secondString";
|
textEditingController.text = "$firstString$sticker$secondString";
|
||||||
} else {
|
} else {
|
||||||
textEditingController.text = "$oldText$sticker";
|
currentCursor = null;
|
||||||
|
textEditingController.text = "$currentText$sticker";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
||||||
|
|
@ -169,7 +208,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
return text.replaceAll(RegExp(r'\ufeff'), "");
|
return text.replaceAll(RegExp(r'\ufeff'), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future handleSetDraftText([String? id, ConvType? convType]) async {
|
Future handleSetDraftText(
|
||||||
|
{String? id, ConvType? convType, String? groupID}) async {
|
||||||
String text = textEditingController.text;
|
String text = textEditingController.text;
|
||||||
String convID = id ?? widget.conversationID;
|
String convID = id ?? widget.conversationID;
|
||||||
final isTopic = convID.contains("@TOPIC#");
|
final isTopic = convID.contains("@TOPIC#");
|
||||||
|
|
@ -180,25 +220,13 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
: "group_$convID");
|
: "group_$convID");
|
||||||
String draftText = _filterU200b(text);
|
String draftText = _filterU200b(text);
|
||||||
return await conversationModel.setConversationDraft(
|
return await conversationModel.setConversationDraft(
|
||||||
groupID: widget.groupID,
|
groupID: groupID ?? widget.groupID,
|
||||||
isTopic: isTopic,
|
isTopic: isTopic,
|
||||||
isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb,
|
isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb,
|
||||||
conversationID: conversationID,
|
conversationID: conversationID,
|
||||||
draftText: draftText);
|
draftText: draftText);
|
||||||
}
|
}
|
||||||
|
|
||||||
backSpaceText() {
|
|
||||||
String originalText = textEditingController.text;
|
|
||||||
dynamic text;
|
|
||||||
|
|
||||||
if (originalText == zeroWidthSpace) {
|
|
||||||
_handleSoftKeyBoardDelete();
|
|
||||||
} else {
|
|
||||||
text = originalText.characters.skipLast(1);
|
|
||||||
textEditingController.text = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 和onSubmitted一样,只是保持焦点的不同
|
// 和onSubmitted一样,只是保持焦点的不同
|
||||||
onEmojiSubmitted() {
|
onEmojiSubmitted() {
|
||||||
lastText = "";
|
lastText = "";
|
||||||
|
|
@ -592,6 +620,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
KeyEventResult handleDesktopKeyEvent(FocusNode node, RawKeyEvent event) {
|
KeyEventResult handleDesktopKeyEvent(FocusNode node, RawKeyEvent event) {
|
||||||
final activeIndex = widget.model.activeAtIndex;
|
final activeIndex = widget.model.activeAtIndex;
|
||||||
final showMemberList = widget.model.showAtMemberList;
|
final showMemberList = widget.model.showAtMemberList;
|
||||||
|
final isEneter = (event.physicalKey == PhysicalKeyboardKey.enter) ||
|
||||||
|
(event.physicalKey == PhysicalKeyboardKey.numpadEnter);
|
||||||
if (event.runtimeType == RawKeyDownEvent) {
|
if (event.runtimeType == RawKeyDownEvent) {
|
||||||
if (event.physicalKey == PhysicalKeyboardKey.backspace) {
|
if (event.physicalKey == PhysicalKeyboardKey.backspace) {
|
||||||
if (textEditingController.text.isEmpty && lastText.isEmpty) {
|
if (textEditingController.text.isEmpty && lastText.isEmpty) {
|
||||||
|
|
@ -602,7 +632,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
event.isAltPressed ||
|
event.isAltPressed ||
|
||||||
event.isControlPressed ||
|
event.isControlPressed ||
|
||||||
event.isMetaPressed) &&
|
event.isMetaPressed) &&
|
||||||
event.physicalKey == PhysicalKeyboardKey.enter) {
|
isEneter) {
|
||||||
final offset = textEditingController.selection.baseOffset;
|
final offset = textEditingController.selection.baseOffset;
|
||||||
textEditingController.text =
|
textEditingController.text =
|
||||||
'${lastText.substring(0, offset)}\n${lastText.substring(offset)}';
|
'${lastText.substring(0, offset)}\n${lastText.substring(offset)}';
|
||||||
|
|
@ -611,7 +641,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
lastText = textEditingController.text;
|
lastText = textEditingController.text;
|
||||||
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
} else if (event.physicalKey == PhysicalKeyboardKey.enter) {
|
} else if (isEneter) {
|
||||||
if (!_isComposingText) {
|
if (!_isComposingText) {
|
||||||
if (!isAddingAtSearchWords || widget.model.showAtMemberList.isEmpty) {
|
if (!isAddingAtSearchWords || widget.model.showAtMemberList.isEmpty) {
|
||||||
onSubmitted();
|
onSubmitted();
|
||||||
|
|
@ -707,7 +737,10 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
if (widget.conversationID != oldWidget.conversationID) {
|
if (widget.conversationID != oldWidget.conversationID) {
|
||||||
mentionedMembersMap.clear();
|
mentionedMembersMap.clear();
|
||||||
handleSetDraftText(oldWidget.conversationID, oldWidget.conversationType);
|
handleSetDraftText(
|
||||||
|
id: oldWidget.conversationID,
|
||||||
|
convType: oldWidget.conversationType,
|
||||||
|
groupID: oldWidget.groupID);
|
||||||
if (oldWidget.initText != widget.initText) {
|
if (oldWidget.initText != widget.initText) {
|
||||||
textEditingController.text = widget.initText ?? "";
|
textEditingController.text = widget.initText ?? "";
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -832,7 +865,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
defaultWidget: TIMUIKitTextFieldLayoutNarrow(
|
defaultWidget: TIMUIKitTextFieldLayoutNarrow(
|
||||||
onEmojiSubmitted: onEmojiSubmitted,
|
onEmojiSubmitted: onEmojiSubmitted,
|
||||||
onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted,
|
onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted,
|
||||||
backSpaceText: backSpaceText,
|
backSpaceText: deleteStickerFromText,
|
||||||
addStickerToText: addStickerToText,
|
addStickerToText: addStickerToText,
|
||||||
customStickerPanel: widget.customStickerPanel,
|
customStickerPanel: widget.customStickerPanel,
|
||||||
forbiddenText: forbiddenText,
|
forbiddenText: forbiddenText,
|
||||||
|
|
@ -864,11 +897,12 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
showMorePanel: widget.showMorePanel,
|
showMorePanel: widget.showMorePanel,
|
||||||
customEmojiStickerList: widget.customEmojiStickerList),
|
customEmojiStickerList: widget.customEmojiStickerList),
|
||||||
desktopWidget: TIMUIKitTextFieldLayoutWide(
|
desktopWidget: TIMUIKitTextFieldLayoutWide(
|
||||||
|
chatConfig: widget.chatConfig ?? widget.model.chatConfig,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
currentConversation: widget.currentConversation,
|
currentConversation: widget.currentConversation,
|
||||||
onEmojiSubmitted: onEmojiSubmitted,
|
onEmojiSubmitted: onEmojiSubmitted,
|
||||||
onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted,
|
onCustomEmojiFaceSubmitted: onCustomEmojiFaceSubmitted,
|
||||||
backSpaceText: backSpaceText,
|
backSpaceText: deleteStickerFromText,
|
||||||
addStickerToText: addStickerToText,
|
addStickerToText: addStickerToText,
|
||||||
customStickerPanel: widget.customStickerPanel,
|
customStickerPanel: widget.customStickerPanel,
|
||||||
forbiddenText: forbiddenText,
|
forbiddenText: forbiddenText,
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,8 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget {
|
||||||
/// show send audio icon
|
/// show send audio icon
|
||||||
final bool showSendAudio;
|
final bool showSendAudio;
|
||||||
|
|
||||||
|
final TIMUIKitChatConfig chatConfig;
|
||||||
|
|
||||||
/// on text changed
|
/// on text changed
|
||||||
final void Function(String)? onChanged;
|
final void Function(String)? onChanged;
|
||||||
|
|
||||||
|
|
@ -183,7 +185,8 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget {
|
||||||
required this.customEmojiStickerList,
|
required this.customEmojiStickerList,
|
||||||
this.controller,
|
this.controller,
|
||||||
required this.currentConversation,
|
required this.currentConversation,
|
||||||
required this.theme})
|
required this.theme,
|
||||||
|
required this.chatConfig})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -288,12 +291,10 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
TIM_t("回复 "),
|
TIM_t("回复 "),
|
||||||
style: TextStyle(
|
style: TextStyle(color: hexToColor("8f959e"), fontSize: 14),
|
||||||
color: hexToColor("8f959e"), fontSize: 14),
|
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
MessageUtils.getDisplayName(
|
MessageUtils.getDisplayName(widget.model.repliedMessage!),
|
||||||
widget.model.repliedMessage!),
|
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|
@ -367,7 +368,7 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
child: Container(
|
child: Container(
|
||||||
child: widget.customStickerPanel != null
|
child: widget.customStickerPanel != null
|
||||||
? widget.customStickerPanel!(
|
? widget.customStickerPanel!(
|
||||||
height: 400,
|
height: widget.chatConfig.desktopStickerPanelHeight,
|
||||||
width: 350,
|
width: 350,
|
||||||
sendTextMessage: () {
|
sendTextMessage: () {
|
||||||
widget.onEmojiSubmitted();
|
widget.onEmojiSubmitted();
|
||||||
|
|
@ -495,7 +496,8 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
final double? dx = (offset?.dx != null) ? offset!.dx : null;
|
final double? dx = (offset?.dx != null) ? offset!.dx : null;
|
||||||
final double? dy =
|
final double? dy =
|
||||||
(offset?.dy != null && alignBox?.size.height != null)
|
(offset?.dy != null && alignBox?.size.height != null)
|
||||||
? offset!.dy - 420
|
? offset!.dy -
|
||||||
|
(widget.chatConfig.desktopStickerPanelHeight + 20)
|
||||||
: null;
|
: null;
|
||||||
e.onClick((dx != null && dy != null) ? Offset(dx, dy) : null);
|
e.onClick((dx != null && dy != null) ? Offset(dx, dy) : null);
|
||||||
},
|
},
|
||||||
|
|
@ -813,8 +815,7 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
|
|
||||||
generateDefaultControlBarItems() {
|
generateDefaultControlBarItems() {
|
||||||
final DesktopControlBarConfig config =
|
final DesktopControlBarConfig config =
|
||||||
widget.model.chatConfig.desktopControlBarConfig ??
|
widget.chatConfig.desktopControlBarConfig ?? DesktopControlBarConfig();
|
||||||
DesktopControlBarConfig();
|
|
||||||
final List<DesktopControlBarItem> itemsList = [
|
final List<DesktopControlBarItem> itemsList = [
|
||||||
if (config.showStickerPanel)
|
if (config.showStickerPanel)
|
||||||
DesktopControlBarItem(
|
DesktopControlBarItem(
|
||||||
|
|
@ -898,7 +899,7 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
TUIChatSeparateViewModel model, TUITheme theme) {
|
TUIChatSeparateViewModel model, TUITheme theme) {
|
||||||
final List<DesktopControlBarItem> itemsList = [
|
final List<DesktopControlBarItem> itemsList = [
|
||||||
...defaultControlBarItems,
|
...defaultControlBarItems,
|
||||||
...(widget.model.chatConfig.additionalDesktopControlBarItems ?? [])
|
...(widget.chatConfig.additionalDesktopControlBarItems ?? [])
|
||||||
];
|
];
|
||||||
|
|
||||||
return generateBarIcons(itemsList, theme);
|
return generateBarIcons(itemsList, theme);
|
||||||
|
|
@ -1021,10 +1022,10 @@ class _TIMUIKitTextFieldLayoutWideState
|
||||||
child: ExtendedTextField(
|
child: ExtendedTextField(
|
||||||
scrollController: _scrollController,
|
scrollController: _scrollController,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
maxLines: widget
|
maxLines:
|
||||||
.model.chatConfig.desktopMessageInputFieldLines,
|
widget.chatConfig.desktopMessageInputFieldLines,
|
||||||
minLines: widget
|
minLines:
|
||||||
.model.chatConfig.desktopMessageInputFieldLines,
|
widget.chatConfig.desktopMessageInputFieldLines,
|
||||||
focusNode: widget.focusNode,
|
focusNode: widget.focusNode,
|
||||||
onChanged: debounceFunc,
|
onChanged: debounceFunc,
|
||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class TIMUIKitChat extends StatefulWidget {
|
||||||
|
|
||||||
/// use for customize avatar
|
/// use for customize avatar
|
||||||
final Widget Function(BuildContext context, V2TimMessage message)?
|
final Widget Function(BuildContext context, V2TimMessage message)?
|
||||||
userAvatarBuilder;
|
userAvatarBuilder;
|
||||||
|
|
||||||
/// Use for show conversation name.
|
/// Use for show conversation name.
|
||||||
/// This field is not necessary to be provided, when `conversation` is provided, unless you want to cover this field manually.
|
/// This field is not necessary to be provided, when `conversation` is provided, unless you want to cover this field manually.
|
||||||
|
|
@ -64,7 +64,7 @@ class TIMUIKitChat extends StatefulWidget {
|
||||||
|
|
||||||
/// Avatar and name in message reaction secondary tap callback.
|
/// Avatar and name in message reaction secondary tap callback.
|
||||||
final void Function(String userID, TapDownDetails tapDetails)?
|
final void Function(String userID, TapDownDetails tapDetails)?
|
||||||
onSecondaryTapAvatar;
|
onSecondaryTapAvatar;
|
||||||
|
|
||||||
@Deprecated(
|
@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")
|
"Nickname will not shows in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead")
|
||||||
|
|
@ -142,6 +142,8 @@ class TIMUIKitChat extends StatefulWidget {
|
||||||
|
|
||||||
final Widget? customAppBar;
|
final Widget? customAppBar;
|
||||||
|
|
||||||
|
final Widget? inputTopBuilder;
|
||||||
|
|
||||||
/// Custom emoji panel.
|
/// Custom emoji panel.
|
||||||
final CustomStickerPanel? customStickerPanel;
|
final CustomStickerPanel? customStickerPanel;
|
||||||
|
|
||||||
|
|
@ -154,46 +156,47 @@ class TIMUIKitChat extends StatefulWidget {
|
||||||
/// Custom text field
|
/// Custom text field
|
||||||
final Widget Function(BuildContext context)? textFieldBuilder;
|
final Widget Function(BuildContext context)? textFieldBuilder;
|
||||||
|
|
||||||
TIMUIKitChat({Key? key,
|
TIMUIKitChat(
|
||||||
this.groupID,
|
{Key? key,
|
||||||
required this.conversation,
|
this.groupID,
|
||||||
this.conversationID,
|
required this.conversation,
|
||||||
this.conversationType,
|
this.conversationID,
|
||||||
this.conversationShowName,
|
this.conversationType,
|
||||||
this.abstractMessageBuilder,
|
this.conversationShowName,
|
||||||
this.onTapAvatar,
|
this.abstractMessageBuilder,
|
||||||
@Deprecated(
|
this.onTapAvatar,
|
||||||
"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(
|
||||||
this.showTotalUnReadCount = false,
|
"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.messageItemBuilder,
|
this.showNickName = false,
|
||||||
@Deprecated(
|
this.showTotalUnReadCount = false,
|
||||||
"Please use [extraTipsActionItemBuilder] instead") this.exteraTipsActionItemBuilder,
|
this.messageItemBuilder,
|
||||||
this.extraTipsActionItemBuilder,
|
@Deprecated("Please use [extraTipsActionItemBuilder] instead")
|
||||||
this.draftText,
|
this.exteraTipsActionItemBuilder,
|
||||||
this.textFieldHintText,
|
this.extraTipsActionItemBuilder,
|
||||||
this.initFindingMsg,
|
this.draftText,
|
||||||
this.userAvatarBuilder,
|
this.textFieldHintText,
|
||||||
this.appBarConfig,
|
this.initFindingMsg,
|
||||||
this.controller,
|
this.userAvatarBuilder,
|
||||||
this.morePanelConfig,
|
this.appBarConfig,
|
||||||
this.customStickerPanel,
|
this.controller,
|
||||||
this.config = const TIMUIKitChatConfig(),
|
this.morePanelConfig,
|
||||||
this.tongueItemBuilder,
|
this.customStickerPanel,
|
||||||
this.groupAtInfoList,
|
this.config = const TIMUIKitChatConfig(),
|
||||||
this.mainHistoryListConfig,
|
this.tongueItemBuilder,
|
||||||
this.onDealWithGroupApplication,
|
this.groupAtInfoList,
|
||||||
this.toolTipsConfig,
|
this.mainHistoryListConfig,
|
||||||
this.lifeCycle,
|
this.onDealWithGroupApplication,
|
||||||
this.topFixWidget = const SizedBox(),
|
this.toolTipsConfig,
|
||||||
this.textFieldBuilder,
|
this.lifeCycle,
|
||||||
this.customEmojiStickerList = const [],
|
this.topFixWidget = const SizedBox(),
|
||||||
this.customAppBar,
|
this.textFieldBuilder,
|
||||||
this.onSecondaryTapAvatar,
|
this.customEmojiStickerList = const [],
|
||||||
this.customMessageHoverBarOnDesktop})
|
this.customAppBar,
|
||||||
|
this.inputTopBuilder,
|
||||||
|
this.onSecondaryTapAvatar,
|
||||||
|
this.customMessageHoverBarOnDesktop})
|
||||||
: super(key: key) {
|
: super(key: key) {
|
||||||
startTime = DateTime
|
startTime = DateTime.now().millisecondsSinceEpoch;
|
||||||
.now()
|
|
||||||
.millisecondsSinceEpoch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -203,15 +206,15 @@ class TIMUIKitChat extends StatefulWidget {
|
||||||
class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
TUIChatSeparateViewModel model = TUIChatSeparateViewModel();
|
TUIChatSeparateViewModel model = TUIChatSeparateViewModel();
|
||||||
final TUISelfInfoViewModel selfInfoViewModel =
|
final TUISelfInfoViewModel selfInfoViewModel =
|
||||||
serviceLocator<TUISelfInfoViewModel>();
|
serviceLocator<TUISelfInfoViewModel>();
|
||||||
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
|
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
|
||||||
final TUIConversationViewModel conversationViewModel =
|
final TUIConversationViewModel conversationViewModel =
|
||||||
serviceLocator<TUIConversationViewModel>();
|
serviceLocator<TUIConversationViewModel>();
|
||||||
TIMUIKitInputTextFieldController textFieldController =
|
TIMUIKitInputTextFieldController textFieldController =
|
||||||
TIMUIKitInputTextFieldController();
|
TIMUIKitInputTextFieldController();
|
||||||
bool isInit = false;
|
bool isInit = false;
|
||||||
final TUIChatGlobalModel chatGlobalModel =
|
final TUIChatGlobalModel chatGlobalModel =
|
||||||
serviceLocator<TUIChatGlobalModel>();
|
serviceLocator<TUIChatGlobalModel>();
|
||||||
bool _dragging = false;
|
bool _dragging = false;
|
||||||
|
|
||||||
final GlobalKey alignKey = GlobalKey();
|
final GlobalKey alignKey = GlobalKey();
|
||||||
|
|
@ -219,19 +222,13 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
|
|
||||||
late AutoScrollController autoController = AutoScrollController(
|
late AutoScrollController autoController = AutoScrollController(
|
||||||
viewportBoundaryGetter: () =>
|
viewportBoundaryGetter: () =>
|
||||||
Rect.fromLTRB(0, 0, 0, MediaQuery
|
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
|
||||||
.of(context)
|
|
||||||
.padding
|
|
||||||
.bottom),
|
|
||||||
axis: Axis.vertical,
|
axis: Axis.vertical,
|
||||||
);
|
);
|
||||||
|
|
||||||
late AutoScrollController atMemberPanelScroll = AutoScrollController(
|
late AutoScrollController atMemberPanelScroll = AutoScrollController(
|
||||||
viewportBoundaryGetter: () =>
|
viewportBoundaryGetter: () =>
|
||||||
Rect.fromLTRB(0, 0, 0, MediaQuery
|
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
|
||||||
.of(context)
|
|
||||||
.padding
|
|
||||||
.bottom),
|
|
||||||
axis: Axis.vertical,
|
axis: Axis.vertical,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -245,9 +242,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
model.onTapAvatar = widget.onTapAvatar;
|
model.onTapAvatar = widget.onTapAvatar;
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
if (kProfileMode) {
|
if (kProfileMode) {
|
||||||
widget.endTime = DateTime
|
widget.endTime = DateTime.now().millisecondsSinceEpoch;
|
||||||
.now()
|
|
||||||
.millisecondsSinceEpoch;
|
|
||||||
int timeSpend = widget.endTime - widget.startTime;
|
int timeSpend = widget.endTime - widget.startTime;
|
||||||
print("Page render time:$timeSpend ms");
|
print("Page render time:$timeSpend ms");
|
||||||
}
|
}
|
||||||
|
|
@ -300,8 +295,8 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
final topicInfoList = await TencentImSDKPlugin.v2TIMManager
|
final topicInfoList = await TencentImSDKPlugin.v2TIMManager
|
||||||
.getGroupManager()
|
.getGroupManager()
|
||||||
.getTopicInfoList(
|
.getTopicInfoList(
|
||||||
groupID: widget.groupID!,
|
groupID: widget.groupID!,
|
||||||
topicIDList: [widget.conversation.conversationID]);
|
topicIDList: [widget.conversation.conversationID]);
|
||||||
final topicInfo = topicInfoList.data?.first.topicInfo;
|
final topicInfo = topicInfoList.data?.first.topicInfo;
|
||||||
final draftText = topicInfo?.draftText;
|
final draftText = topicInfo?.draftText;
|
||||||
if (TencentUtils.checkString(draftText) != null) {
|
if (TencentUtils.checkString(draftText) != null) {
|
||||||
|
|
@ -367,7 +362,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||||
final TUITheme theme = value.theme;
|
final TUITheme theme = value.theme;
|
||||||
final closePanel =
|
final closePanel =
|
||||||
OptimizeUtils.throttle((_) => textFieldController.hideAllPanel(), 60);
|
OptimizeUtils.throttle((_) => textFieldController.hideAllPanel(), 60);
|
||||||
final isBuild = isInit;
|
final isBuild = isInit;
|
||||||
isInit = true;
|
isInit = true;
|
||||||
|
|
||||||
|
|
@ -386,7 +381,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
],
|
],
|
||||||
builder: (context, model, w) {
|
builder: (context, model, w) {
|
||||||
final TUIChatGlobalModel chatGlobalModel =
|
final TUIChatGlobalModel chatGlobalModel =
|
||||||
Provider.of<TUIChatGlobalModel>(context, listen: true);
|
Provider.of<TUIChatGlobalModel>(context, listen: true);
|
||||||
|
|
||||||
widget.controller?.model = model;
|
widget.controller?.model = model;
|
||||||
widget.controller?.textFieldController = textFieldController;
|
widget.controller?.textFieldController = textFieldController;
|
||||||
|
|
@ -396,14 +391,14 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
widget.onDealWithGroupApplication != null) {
|
widget.onDealWithGroupApplication != null) {
|
||||||
filteredApplicationList =
|
filteredApplicationList =
|
||||||
chatGlobalModel.groupApplicationList.where((item) {
|
chatGlobalModel.groupApplicationList.where((item) {
|
||||||
return (item.groupID == widget.conversationID) &&
|
return (item.groupID == widget.conversationID) &&
|
||||||
item.handleStatus == 0;
|
item.handleStatus == 0;
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
final selfUserID = selfInfoViewModel.loginInfo?.userID;
|
final selfUserID = selfInfoViewModel.loginInfo?.userID;
|
||||||
final TUIGroupListenerModel groupListenerModel =
|
final TUIGroupListenerModel groupListenerModel =
|
||||||
Provider.of<TUIGroupListenerModel>(context, listen: true);
|
Provider.of<TUIGroupListenerModel>(context, listen: true);
|
||||||
final NeedUpdate? needUpdate = groupListenerModel.needUpdate;
|
final NeedUpdate? needUpdate = groupListenerModel.needUpdate;
|
||||||
if (needUpdate != null &&
|
if (needUpdate != null &&
|
||||||
needUpdate.groupID == widget.conversationID) {
|
needUpdate.groupID == widget.conversationID) {
|
||||||
|
|
@ -429,13 +424,13 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
appBar: (widget.customAppBar == null)
|
appBar: (widget.customAppBar == null)
|
||||||
? TIMUIKitAppBar(
|
? TIMUIKitAppBar(
|
||||||
showTotalUnReadCount: widget.showTotalUnReadCount,
|
showTotalUnReadCount: widget.showTotalUnReadCount,
|
||||||
config: widget.appBarConfig,
|
config: widget.appBarConfig,
|
||||||
conversationShowName: _getTitle(),
|
conversationShowName: _getTitle(),
|
||||||
conversationID: _getConvID(),
|
conversationID: _getConvID(),
|
||||||
showC2cMessageEditStatus:
|
showC2cMessageEditStatus:
|
||||||
widget.config?.showC2cMessageEditStatus ?? true,
|
widget.config?.showC2cMessageEditStatus ?? true,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
body: DropTarget(
|
body: DropTarget(
|
||||||
onDragDone: (detail) {
|
onDragDone: (detail) {
|
||||||
|
|
@ -463,6 +458,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (widget.customAppBar != null) widget.customAppBar!,
|
if (widget.customAppBar != null) widget.customAppBar!,
|
||||||
if (filteredApplicationList.isNotEmpty)
|
if (filteredApplicationList.isNotEmpty)
|
||||||
|
|
@ -471,110 +467,110 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
if (widget.topFixWidget != null) widget.topFixWidget!,
|
if (widget.topFixWidget != null) widget.topFixWidget!,
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
color: theme.chatBgColor,
|
color: theme.chatBgColor,
|
||||||
child: Align(
|
child: Align(
|
||||||
key: alignKey,
|
key: alignKey,
|
||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
child: Listener(
|
child: Listener(
|
||||||
onPointerMove: closePanel,
|
onPointerMove: closePanel,
|
||||||
child: TIMUIKitHistoryMessageListContainer(
|
child: TIMUIKitHistoryMessageListContainer(
|
||||||
customMessageHoverBarOnDesktop: widget
|
customMessageHoverBarOnDesktop:
|
||||||
.customMessageHoverBarOnDesktop,
|
widget.customMessageHoverBarOnDesktop,
|
||||||
conversation: widget.conversation,
|
conversation: widget.conversation,
|
||||||
groupMemberInfo: model.groupMemberList
|
groupMemberInfo: model.groupMemberList
|
||||||
?.firstWhere(
|
?.firstWhere(
|
||||||
(element) =>
|
(element) =>
|
||||||
element?.userID == selfUserID,
|
element?.userID == selfUserID,
|
||||||
orElse: () => null),
|
orElse: () => null),
|
||||||
textFieldController: textFieldController,
|
textFieldController: textFieldController,
|
||||||
customEmojiStickerList:
|
customEmojiStickerList:
|
||||||
widget.customEmojiStickerList,
|
widget.customEmojiStickerList,
|
||||||
isUseDefaultEmoji:
|
isUseDefaultEmoji:
|
||||||
widget.config!.isUseDefaultEmoji,
|
widget.config!.isUseDefaultEmoji,
|
||||||
key: listContainerKey,
|
key: listContainerKey,
|
||||||
isAllowScroll: true,
|
isAllowScroll: true,
|
||||||
userAvatarBuilder: widget
|
userAvatarBuilder: widget.userAvatarBuilder,
|
||||||
.userAvatarBuilder,
|
toolTipsConfig: widget.toolTipsConfig,
|
||||||
toolTipsConfig: widget.toolTipsConfig,
|
groupAtInfoList: widget.groupAtInfoList,
|
||||||
groupAtInfoList: widget.groupAtInfoList,
|
tongueItemBuilder: widget.tongueItemBuilder,
|
||||||
tongueItemBuilder: widget
|
onLongPressForOthersHeadPortrait:
|
||||||
.tongueItemBuilder,
|
(String? userId, String? nickName) {
|
||||||
onLongPressForOthersHeadPortrait:
|
textFieldController.longPressToAt(
|
||||||
(String? userId, String? nickName) {
|
nickName, userId);
|
||||||
textFieldController.longPressToAt(
|
},
|
||||||
nickName, userId);
|
mainHistoryListConfig:
|
||||||
},
|
|
||||||
mainHistoryListConfig:
|
|
||||||
widget.mainHistoryListConfig,
|
widget.mainHistoryListConfig,
|
||||||
initFindingMsg: widget.initFindingMsg,
|
initFindingMsg: widget.initFindingMsg,
|
||||||
extraTipsActionItemBuilder:
|
extraTipsActionItemBuilder:
|
||||||
widget.extraTipsActionItemBuilder ??
|
widget.extraTipsActionItemBuilder ??
|
||||||
widget.exteraTipsActionItemBuilder,
|
widget.exteraTipsActionItemBuilder,
|
||||||
conversationType: _getConvType(),
|
conversationType: _getConvType(),
|
||||||
scrollController: autoController,
|
scrollController: autoController,
|
||||||
onSecondaryTapAvatar:
|
onSecondaryTapAvatar:
|
||||||
widget.onSecondaryTapAvatar,
|
widget.onSecondaryTapAvatar,
|
||||||
onTapAvatar: widget.onTapAvatar,
|
onTapAvatar: widget.onTapAvatar,
|
||||||
// ignore: deprecated_member_use_from_same_package
|
// ignore: deprecated_member_use_from_same_package
|
||||||
showNickName: widget.showNickName,
|
showNickName: widget.showNickName,
|
||||||
messageItemBuilder:
|
messageItemBuilder:
|
||||||
widget.messageItemBuilder,
|
widget.messageItemBuilder,
|
||||||
conversationID: _getConvID(),
|
conversationID: _getConvID(),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
)),
|
)),
|
||||||
|
widget.inputTopBuilder ?? Container(),
|
||||||
Selector<TUIChatSeparateViewModel, bool>(
|
Selector<TUIChatSeparateViewModel, bool>(
|
||||||
builder: (context, value, child) {
|
builder: (context, value, child) {
|
||||||
return value
|
return value
|
||||||
? MultiSelectPanel(
|
? MultiSelectPanel(
|
||||||
conversationType: _getConvType(),
|
conversationType: _getConvType(),
|
||||||
)
|
)
|
||||||
: (widget.textFieldBuilder != null
|
: (widget.textFieldBuilder != null
|
||||||
? widget.textFieldBuilder!(context)
|
? widget.textFieldBuilder!(context)
|
||||||
: TIMUIKitInputTextField(
|
: TIMUIKitInputTextField(
|
||||||
groupID: widget.groupID,
|
chatConfig: widget.config,
|
||||||
atMemberPanelScroll:
|
groupID: widget.groupID,
|
||||||
atMemberPanelScroll,
|
atMemberPanelScroll:
|
||||||
groupType:
|
atMemberPanelScroll,
|
||||||
widget.conversation.groupType,
|
groupType:
|
||||||
currentConversation:
|
widget.conversation.groupType,
|
||||||
widget.conversation,
|
currentConversation:
|
||||||
model: model,
|
widget.conversation,
|
||||||
controller: textFieldController,
|
model: model,
|
||||||
customEmojiStickerList:
|
controller: textFieldController,
|
||||||
widget.customEmojiStickerList,
|
customEmojiStickerList:
|
||||||
isUseDefaultEmoji:
|
widget.customEmojiStickerList,
|
||||||
widget.config!.isUseDefaultEmoji,
|
isUseDefaultEmoji:
|
||||||
customStickerPanel:
|
widget.config!.isUseDefaultEmoji,
|
||||||
widget.customStickerPanel,
|
customStickerPanel:
|
||||||
morePanelConfig:
|
widget.customStickerPanel,
|
||||||
widget.morePanelConfig,
|
morePanelConfig:
|
||||||
scrollController: autoController,
|
widget.morePanelConfig,
|
||||||
conversationID: _getConvID(),
|
scrollController: autoController,
|
||||||
conversationType: _getConvType(),
|
conversationID: _getConvID(),
|
||||||
initText: TencentUtils.checkString(
|
conversationType: _getConvType(),
|
||||||
widget.draftText) ??
|
initText: TencentUtils.checkString(
|
||||||
(PlatformUtils().isWeb
|
widget.draftText) ??
|
||||||
? TencentUtils.checkString(
|
(PlatformUtils().isWeb
|
||||||
conversationViewModel
|
? TencentUtils.checkString(
|
||||||
.getWebDraft(
|
conversationViewModel
|
||||||
conversationID: widget
|
.getWebDraft(
|
||||||
.conversation
|
conversationID: widget
|
||||||
.conversationID))
|
.conversation
|
||||||
: TencentUtils.checkString(
|
.conversationID))
|
||||||
widget.conversation
|
: TencentUtils.checkString(
|
||||||
.draftText)),
|
widget.conversation
|
||||||
hintText: widget.textFieldHintText,
|
.draftText)),
|
||||||
showMorePanel: widget.config
|
hintText: widget.textFieldHintText,
|
||||||
?.isAllowShowMorePanel ??
|
showMorePanel: widget.config
|
||||||
true,
|
?.isAllowShowMorePanel ??
|
||||||
showSendAudio: widget.config
|
true,
|
||||||
?.isAllowSoundMessage ??
|
showSendAudio: widget.config
|
||||||
true,
|
?.isAllowSoundMessage ??
|
||||||
showSendEmoji: widget
|
true,
|
||||||
.config?.isAllowEmojiPanel ??
|
showSendEmoji: widget
|
||||||
true,
|
.config?.isAllowEmojiPanel ??
|
||||||
));
|
true,
|
||||||
|
));
|
||||||
},
|
},
|
||||||
selector: (c, model) {
|
selector: (c, model) {
|
||||||
return model.isMultiSelect;
|
return model.isMultiSelect;
|
||||||
|
|
@ -603,13 +599,13 @@ class TIMUIKitChatProviderScope extends StatelessWidget {
|
||||||
final TUIChatGlobalModel globalModel = serviceLocator<TUIChatGlobalModel>();
|
final TUIChatGlobalModel globalModel = serviceLocator<TUIChatGlobalModel>();
|
||||||
TUIChatSeparateViewModel? model;
|
TUIChatSeparateViewModel? model;
|
||||||
final TUIGroupListenerModel groupListenerModel =
|
final TUIGroupListenerModel groupListenerModel =
|
||||||
serviceLocator<TUIGroupListenerModel>();
|
serviceLocator<TUIGroupListenerModel>();
|
||||||
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
|
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
|
||||||
final Widget? child;
|
final Widget? child;
|
||||||
|
|
||||||
/// You could get the model from here, and transfer it to other widget from TUIKit.
|
/// You could get the model from here, and transfer it to other widget from TUIKit.
|
||||||
final Widget Function(BuildContext, TUIChatSeparateViewModel, Widget?)
|
final Widget Function(BuildContext, TUIChatSeparateViewModel, Widget?)
|
||||||
builder;
|
builder;
|
||||||
final List<SingleChildWidget>? providers;
|
final List<SingleChildWidget>? providers;
|
||||||
|
|
||||||
/// `TIMUIKitChatController` needs to be provided if you use it outside.
|
/// `TIMUIKitChatController` needs to be provided if you use it outside.
|
||||||
|
|
@ -636,20 +632,21 @@ class TIMUIKitChatProviderScope extends StatelessWidget {
|
||||||
|
|
||||||
final AutoScrollController? scrollController;
|
final AutoScrollController? scrollController;
|
||||||
|
|
||||||
TIMUIKitChatProviderScope({Key? key,
|
TIMUIKitChatProviderScope(
|
||||||
this.child,
|
{Key? key,
|
||||||
this.providers,
|
this.child,
|
||||||
this.textFieldController,
|
this.providers,
|
||||||
required this.builder,
|
this.textFieldController,
|
||||||
this.model,
|
required this.builder,
|
||||||
this.groupID,
|
this.model,
|
||||||
this.isBuild,
|
this.groupID,
|
||||||
required this.conversationID,
|
this.isBuild,
|
||||||
required this.conversationType,
|
required this.conversationID,
|
||||||
this.controller,
|
required this.conversationType,
|
||||||
this.config,
|
this.controller,
|
||||||
this.lifeCycle,
|
this.config,
|
||||||
this.scrollController})
|
this.lifeCycle,
|
||||||
|
this.scrollController})
|
||||||
: super(key: key) {
|
: super(key: key) {
|
||||||
if (isBuild ?? false) {
|
if (isBuild ?? false) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -665,7 +662,7 @@ class TIMUIKitChatProviderScope extends StatelessWidget {
|
||||||
model?.initForEachConversation(
|
model?.initForEachConversation(
|
||||||
conversationType,
|
conversationType,
|
||||||
conversationID,
|
conversationID,
|
||||||
(String value) {
|
(String value) {
|
||||||
textFieldController?.textEditingController?.text = value;
|
textFieldController?.textEditingController?.text = value;
|
||||||
},
|
},
|
||||||
groupID: groupID,
|
groupID: groupID,
|
||||||
|
|
|
||||||
|
|
@ -199,9 +199,17 @@ class TIMUIKitChatConfig {
|
||||||
/// [Default]: false
|
/// [Default]: false
|
||||||
final bool isGroupAdminRecallEnabled;
|
final bool isGroupAdminRecallEnabled;
|
||||||
|
|
||||||
|
/// Defines the height of the sticker panel on desktop platforms.
|
||||||
|
/// If the height of the sticker list exceeds this container height,
|
||||||
|
/// the sticker list will automatically become scrollable.
|
||||||
|
///
|
||||||
|
/// [Default]: 400
|
||||||
|
final double desktopStickerPanelHeight;
|
||||||
|
|
||||||
const TIMUIKitChatConfig(
|
const TIMUIKitChatConfig(
|
||||||
{this.onTapLink,
|
{this.onTapLink,
|
||||||
this.timeDividerConfig,
|
this.timeDividerConfig,
|
||||||
|
this.desktopStickerPanelHeight = 400,
|
||||||
this.isGroupAdminRecallEnabled = false,
|
this.isGroupAdminRecallEnabled = false,
|
||||||
this.isAutoReportRead = true,
|
this.isAutoReportRead = true,
|
||||||
this.faceURIPrefix,
|
this.faceURIPrefix,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
import 'package:cross_file/cross_file.dart';
|
import 'package:cross_file/cross_file.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
@ -31,15 +32,27 @@ sendFileWithConfirmation(
|
||||||
required BuildContext context}) async {
|
required BuildContext context}) async {
|
||||||
bool isCanSend = true;
|
bool isCanSend = true;
|
||||||
|
|
||||||
files.map((e) => e.path).any((filePath) {
|
if (!PlatformUtils().isWeb) {
|
||||||
final directory = Directory(filePath);
|
files.map((e) => e.path).any((filePath) {
|
||||||
final isDirectoryExists = directory.existsSync();
|
final directory = Directory(filePath);
|
||||||
if (isDirectoryExists) {
|
final isDirectoryExists = directory.existsSync();
|
||||||
isCanSend = false;
|
if (isDirectoryExists) {
|
||||||
return false;
|
isCanSend = false;
|
||||||
}
|
return false;
|
||||||
return true;
|
}
|
||||||
});
|
return true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
files.map((e) => e.name).any((fileName) {
|
||||||
|
String fileExtension = path.extension(fileName);
|
||||||
|
bool hasNoExtension = fileExtension.isEmpty;
|
||||||
|
if (hasNoExtension) {
|
||||||
|
isCanSend = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!isCanSend) {
|
if (!isCanSend) {
|
||||||
TUIKitWidePopup.showSecondaryConfirmDialog(
|
TUIKitWidePopup.showSecondaryConfirmDialog(
|
||||||
|
|
@ -71,6 +84,9 @@ sendFileWithConfirmation(
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final file = files[index];
|
final file = files[index];
|
||||||
|
final fileName = PlatformUtils().isWeb
|
||||||
|
? file.name
|
||||||
|
: path.basename(file.path);
|
||||||
return Material(
|
return Material(
|
||||||
color: theme.wideBackgroundColor,
|
color: theme.wideBackgroundColor,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
|
|
@ -84,18 +100,13 @@ sendFileWithConfirmation(
|
||||||
children: [
|
children: [
|
||||||
TIMUIKitFileIcon(
|
TIMUIKitFileIcon(
|
||||||
size: 44,
|
size: 44,
|
||||||
fileFormat: path
|
fileFormat: fileName.split(
|
||||||
.extension(file.path)
|
".")[fileName.split(".").length - 1],
|
||||||
.split(".")[path
|
|
||||||
.extension(file.path)
|
|
||||||
.split(".")
|
|
||||||
.length -
|
|
||||||
1],
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
path.basename(file.path),
|
fileName,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: theme.darkTextColor),
|
color: theme.darkTextColor),
|
||||||
|
|
@ -154,9 +165,12 @@ Future<void> sendFiles(
|
||||||
ConvType conversationType,
|
ConvType conversationType,
|
||||||
BuildContext context) async {
|
BuildContext context) async {
|
||||||
for (final file in files) {
|
for (final file in files) {
|
||||||
|
final fileName = file.name;
|
||||||
|
final filePath = file.path;
|
||||||
await MessageUtils.handleMessageError(
|
await MessageUtils.handleMessageError(
|
||||||
model.sendFileMessage(
|
model.sendFileMessage(
|
||||||
filePath: file.path,
|
fileName: fileName,
|
||||||
|
filePath: filePath,
|
||||||
convID: _getConvID(conversation),
|
convID: _getConvID(conversation),
|
||||||
convType: conversationType),
|
convType: conversationType),
|
||||||
context);
|
context);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ class ForwardMessageScreen extends StatefulWidget {
|
||||||
{Key? key,
|
{Key? key,
|
||||||
this.isMergerForward = false,
|
this.isMergerForward = false,
|
||||||
required this.conversationType,
|
required this.conversationType,
|
||||||
required this.model, this.onClose})
|
required this.model,
|
||||||
|
this.onClose})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -74,19 +75,25 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
}
|
}
|
||||||
widget.model.updateMultiSelectStatus(false);
|
widget.model.updateMultiSelectStatus(false);
|
||||||
|
|
||||||
if(widget.onClose != null){
|
if (widget.onClose != null) {
|
||||||
widget.onClose!();
|
// widget.onClose!();
|
||||||
}else{
|
} else {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
widget.model.updateMultiSelectStatus(false);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||||
final isDesktopScreen =
|
final isDesktopScreen =
|
||||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||||
final TUITheme theme = value.theme;
|
final TUITheme theme = value.theme;
|
||||||
if(isDesktopScreen){
|
if (isDesktopScreen) {
|
||||||
isMultiSelect = true;
|
isMultiSelect = true;
|
||||||
return RecentForwardList(
|
return RecentForwardList(
|
||||||
isMultiSelect: isMultiSelect,
|
isMultiSelect: isMultiSelect,
|
||||||
|
|
@ -101,16 +108,17 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
}
|
}
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
TIM_t("选择"),
|
isMultiSelect ? TIM_t("选择多个会话") : TIM_t("选择一个会话"),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: theme.appbarTextColor,
|
color: theme.appbarTextColor,
|
||||||
fontSize: 17,
|
fontSize: 17,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
shadowColor: theme.weakBackgroundColor,
|
shadowColor: theme.weakBackgroundColor,
|
||||||
backgroundColor: theme.appbarBgColor ??
|
backgroundColor: theme.appbarBgColor ?? theme.primaryColor,
|
||||||
theme.primaryColor,
|
leadingWidth: 80,
|
||||||
leading: TextButton(
|
leading: TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (isMultiSelect) {
|
if (isMultiSelect) {
|
||||||
|
|
@ -120,9 +128,9 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
widget.model.updateMultiSelectStatus(false);
|
widget.model.updateMultiSelectStatus(false);
|
||||||
if(widget.onClose != null){
|
if (widget.onClose != null) {
|
||||||
widget.onClose!();
|
widget.onClose!();
|
||||||
}else{
|
} else {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +143,6 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
leadingWidth: 80,
|
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
@ -149,9 +156,9 @@ class _ForwardMessageScreenState extends TIMUIKitState<ForwardMessageScreen> {
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
!isMultiSelect ? TIM_t("多选") : TIM_t("完成"),
|
!isMultiSelect ? TIM_t("多选") : TIM_t("完成"),
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: theme.appbarTextColor,
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -122,124 +122,113 @@ class _ImageScreenState extends TIMUIKitState<ImageScreen>
|
||||||
},
|
},
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: close,
|
onTap: close,
|
||||||
child: ExtendedImageGesturePageView.builder(
|
child: HeroWidget(
|
||||||
scrollDirection: Axis.horizontal,
|
tag: widget.heroTag,
|
||||||
controller: ExtendedPageController(
|
slidePagekey: slidePagekey,
|
||||||
initialPage: 0,
|
child: ExtendedImage(
|
||||||
pageSpacing: 0,
|
image: widget.imageProvider,
|
||||||
shouldIgnorePointerWhenScrolling: false,
|
extendedImageGestureKey:
|
||||||
),
|
extendedImageGestureKey,
|
||||||
itemCount: 1,
|
enableSlideOutPage: true,
|
||||||
physics: const BouncingScrollPhysics(),
|
// fit: BoxFit.scaleDown,
|
||||||
itemBuilder: (context, index) {
|
initGestureConfigHandler: (state) {
|
||||||
return HeroWidget(
|
return GestureConfig(
|
||||||
tag: widget.heroTag,
|
minScale: 0.8,
|
||||||
slidePagekey: slidePagekey,
|
animationMinScale: 0.6,
|
||||||
child: ExtendedImage(
|
maxScale: 2 * fittedScale,
|
||||||
image: widget.imageProvider,
|
animationMaxScale: 2.5 * fittedScale,
|
||||||
extendedImageGestureKey:
|
speed: 1.0,
|
||||||
extendedImageGestureKey,
|
inertialSpeed: 100.0,
|
||||||
enableSlideOutPage: true,
|
initialScale: initialScale,
|
||||||
// fit: BoxFit.scaleDown,
|
initialAlignment:
|
||||||
initGestureConfigHandler: (state) {
|
InitialAlignment.topCenter,
|
||||||
return GestureConfig(
|
hitTestBehavior: HitTestBehavior.opaque,
|
||||||
minScale: 0.8,
|
);
|
||||||
animationMinScale: 0.6,
|
},
|
||||||
maxScale: 2 * fittedScale,
|
loadStateChanged: (ExtendedImageState state) {
|
||||||
animationMaxScale: 2.5 * fittedScale,
|
switch (state.extendedImageLoadState) {
|
||||||
speed: 1.0,
|
case LoadState.loading:
|
||||||
inertialSpeed: 100.0,
|
return Container(
|
||||||
initialScale: initialScale,
|
color: Colors.black,
|
||||||
initialAlignment:
|
child: const Center(
|
||||||
InitialAlignment.topCenter,
|
child: CircularProgressIndicator(
|
||||||
hitTestBehavior: HitTestBehavior.opaque,
|
color: Colors.white)));
|
||||||
);
|
case LoadState.completed:
|
||||||
},
|
final screenHeight =
|
||||||
loadStateChanged: (ExtendedImageState state) {
|
MediaQuery.of(context).size.height;
|
||||||
switch (state.extendedImageLoadState) {
|
final screenWidth =
|
||||||
case LoadState.loading:
|
MediaQuery.of(context).size.width;
|
||||||
return Container(
|
final imgHeight = state.extendedImageInfo
|
||||||
color: Colors.black,
|
?.image.height ??
|
||||||
child: const Center(
|
1;
|
||||||
child: CircularProgressIndicator(
|
final imgWidth = state
|
||||||
color: Colors.white)));
|
.extendedImageInfo?.image.width ??
|
||||||
case LoadState.completed:
|
0;
|
||||||
final screenHeight =
|
final imgRatio = imgWidth / imgHeight;
|
||||||
MediaQuery.of(context).size.height;
|
final screenRatio =
|
||||||
final screenWidth =
|
screenWidth / screenHeight;
|
||||||
MediaQuery.of(context).size.width;
|
final fitWidthScale =
|
||||||
final imgHeight = state.extendedImageInfo
|
screenRatio / imgRatio;
|
||||||
?.image.height ??
|
if (screenRatio > imgRatio) {
|
||||||
1;
|
// Long Image
|
||||||
final imgWidth = state
|
// initialScale = fitWidthScale;
|
||||||
.extendedImageInfo?.image.width ??
|
fittedScale = fitWidthScale;
|
||||||
0;
|
doubleTapScales[1] = fitWidthScale;
|
||||||
final imgRatio = imgWidth / imgHeight;
|
} else {
|
||||||
final screenRatio =
|
fittedScale =
|
||||||
screenWidth / screenHeight;
|
1 / fitWidthScale; // fittedHeight
|
||||||
final fitWidthScale =
|
doubleTapScales[1] = 1 / fitWidthScale;
|
||||||
screenRatio / imgRatio;
|
}
|
||||||
if (screenRatio > imgRatio) {
|
return GesturedImage(state,
|
||||||
// Long Image
|
key: extendedImageGestureKey);
|
||||||
// initialScale = fitWidthScale;
|
case LoadState.failed:
|
||||||
fittedScale = fitWidthScale;
|
break;
|
||||||
doubleTapScales[1] = fitWidthScale;
|
}
|
||||||
} else {
|
return null;
|
||||||
fittedScale =
|
},
|
||||||
1 / fitWidthScale; // fittedHeight
|
onDoubleTap: (ExtendedImageGestureState state) {
|
||||||
doubleTapScales[1] = 1 / fitWidthScale;
|
///you can use define pointerDownPosition as you can,
|
||||||
}
|
///default value is double tap pointer down postion.
|
||||||
return GesturedImage(state,
|
final Offset? pointerDownPosition =
|
||||||
key: extendedImageGestureKey);
|
state.pointerDownPosition;
|
||||||
case LoadState.failed:
|
final double? begin =
|
||||||
break;
|
state.gestureDetails!.totalScale;
|
||||||
}
|
double end;
|
||||||
return null;
|
|
||||||
},
|
|
||||||
onDoubleTap: (ExtendedImageGestureState state) {
|
|
||||||
///you can use define pointerDownPosition as you can,
|
|
||||||
///default value is double tap pointer down postion.
|
|
||||||
final Offset? pointerDownPosition =
|
|
||||||
state.pointerDownPosition;
|
|
||||||
final double? begin =
|
|
||||||
state.gestureDetails!.totalScale;
|
|
||||||
double end;
|
|
||||||
|
|
||||||
//remove old
|
//remove old
|
||||||
_doubleClickAnimation?.removeListener(
|
_doubleClickAnimation?.removeListener(
|
||||||
_doubleClickAnimationListener);
|
_doubleClickAnimationListener);
|
||||||
|
|
||||||
//stop pre
|
//stop pre
|
||||||
_doubleClickAnimationController.stop();
|
_doubleClickAnimationController.stop();
|
||||||
|
|
||||||
//reset to use
|
//reset to use
|
||||||
_doubleClickAnimationController.reset();
|
_doubleClickAnimationController.reset();
|
||||||
|
|
||||||
if (begin == doubleTapScales[0]) {
|
if (begin == doubleTapScales[0]) {
|
||||||
end = doubleTapScales[1];
|
end = doubleTapScales[1];
|
||||||
} else {
|
} else {
|
||||||
end = doubleTapScales[0];
|
end = doubleTapScales[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
_doubleClickAnimationListener = () {
|
_doubleClickAnimationListener = () {
|
||||||
//print(_animation.value);
|
//print(_animation.value);
|
||||||
state.handleDoubleTap(
|
state.handleDoubleTap(
|
||||||
scale: _doubleClickAnimation!.value,
|
scale: _doubleClickAnimation!.value,
|
||||||
doubleTapPosition: pointerDownPosition);
|
doubleTapPosition: pointerDownPosition);
|
||||||
};
|
};
|
||||||
_doubleClickAnimation =
|
_doubleClickAnimation =
|
||||||
_doubleClickAnimationController.drive(
|
_doubleClickAnimationController.drive(
|
||||||
Tween<double>(
|
Tween<double>(
|
||||||
begin: begin, end: end));
|
begin: begin, end: end));
|
||||||
|
|
||||||
_doubleClickAnimation!.addListener(
|
_doubleClickAnimation!.addListener(
|
||||||
_doubleClickAnimationListener);
|
_doubleClickAnimationListener);
|
||||||
|
|
||||||
_doubleClickAnimationController.forward();
|
_doubleClickAnimationController.forward();
|
||||||
},
|
},
|
||||||
mode: ExtendedImageMode.gesture,
|
mode: ExtendedImageMode.gesture,
|
||||||
));
|
)),
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -232,21 +232,23 @@ class MergerMessageScreenState extends TIMUIKitState<MergerMessageScreen> {
|
||||||
final faceUrl = message.faceUrl ?? "";
|
final faceUrl = message.faceUrl ?? "";
|
||||||
final showName = message.nickName ?? message.userID ?? "";
|
final showName = message.nickName ?? message.userID ?? "";
|
||||||
final theme = Provider.of<TUIThemeViewModel>(context).theme;
|
final theme = Provider.of<TUIThemeViewModel>(context).theme;
|
||||||
|
final isSelf = message.isSelf ?? false;
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(top: 20),
|
margin: const EdgeInsets.only(top: 20),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: isSelf ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
if(!isSelf) SizedBox(
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
child: Avatar(faceUrl: faceUrl, showName: showName),
|
child: Avatar(faceUrl: faceUrl, showName: showName),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
if(!isSelf) const SizedBox(
|
||||||
width: 12,
|
width: 12,
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: isSelf ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(showName,
|
Text(showName,
|
||||||
style: TextStyle(fontSize: 12, color: theme.weakTextColor)),
|
style: TextStyle(fontSize: 12, color: theme.weakTextColor)),
|
||||||
|
|
@ -258,7 +260,15 @@ class MergerMessageScreenState extends TIMUIKitState<MergerMessageScreen> {
|
||||||
child: _getMsgItem(message),
|
child: _getMsgItem(message),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
|
if(isSelf) const SizedBox(
|
||||||
|
width: 12,
|
||||||
|
),
|
||||||
|
if(isSelf) SizedBox(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
child: Avatar(faceUrl: faceUrl, showName: showName),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,10 @@ import 'dart:math';
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||||
import 'package:tencent_im_base/tencent_im_base.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
import 'package:extended_image/extended_image.dart';
|
import 'package:extended_image/extended_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||||
import 'package:universal_html/html.dart' as html;
|
import 'package:universal_html/html.dart' as html;
|
||||||
|
|
@ -21,11 +20,10 @@ import 'package:video_player/video_player.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
||||||
|
|
||||||
class VideoScreen extends StatefulWidget {
|
class VideoScreen extends StatefulWidget {
|
||||||
const VideoScreen(
|
const VideoScreen({required this.message,
|
||||||
{required this.message,
|
required this.heroTag,
|
||||||
required this.heroTag,
|
required this.videoElement,
|
||||||
required this.videoElement,
|
Key? key})
|
||||||
Key? key})
|
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
final V2TimMessage message;
|
final V2TimMessage message;
|
||||||
|
|
@ -40,13 +38,14 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
late VideoPlayerController videoPlayerController;
|
late VideoPlayerController videoPlayerController;
|
||||||
late ChewieController chewieController;
|
late ChewieController chewieController;
|
||||||
GlobalKey<ExtendedImageSlidePageState> slidePagekey =
|
GlobalKey<ExtendedImageSlidePageState> slidePagekey =
|
||||||
GlobalKey<ExtendedImageSlidePageState>();
|
GlobalKey<ExtendedImageSlidePageState>();
|
||||||
final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>();
|
final TUIChatGlobalModel model = serviceLocator<TUIChatGlobalModel>();
|
||||||
bool isInit = false;
|
bool isInit = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
initState() {
|
initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
setVideoMessage();
|
setVideoPlayerController();
|
||||||
// 允许横屏
|
// 允许横屏
|
||||||
SystemChrome.setPreferredOrientations([
|
SystemChrome.setPreferredOrientations([
|
||||||
DeviceOrientation.landscapeLeft,
|
DeviceOrientation.landscapeLeft,
|
||||||
|
|
@ -57,14 +56,16 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
//保存网络视频到本地
|
//保存网络视频到本地
|
||||||
Future<void> _saveNetworkVideo(
|
Future<void> _saveNetworkVideo(context,
|
||||||
context,
|
String videoUrl, {
|
||||||
String videoUrl, {
|
bool isAsset = true,
|
||||||
bool isAsset = true,
|
}) async {
|
||||||
}) async {
|
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
RegExp exp = RegExp(r"((\.){1}[^?]{2,4})");
|
RegExp exp = RegExp(r"((\.){1}[^?]{2,4})");
|
||||||
String? suffix = exp.allMatches(videoUrl).last.group(0);
|
String? suffix = exp
|
||||||
|
.allMatches(videoUrl)
|
||||||
|
.last
|
||||||
|
.group(0);
|
||||||
var xhr = html.HttpRequest();
|
var xhr = html.HttpRequest();
|
||||||
xhr.open('get', videoUrl);
|
xhr.open('get', videoUrl);
|
||||||
xhr.responseType = 'arraybuffer';
|
xhr.responseType = 'arraybuffer';
|
||||||
|
|
@ -78,7 +79,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
xhr.send();
|
xhr.send();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(PlatformUtils().isMobile){
|
if (PlatformUtils().isMobile) {
|
||||||
if (PlatformUtils().isIOS) {
|
if (PlatformUtils().isIOS) {
|
||||||
if (!await Permissions.checkPermission(
|
if (!await Permissions.checkPermission(
|
||||||
context,
|
context,
|
||||||
|
|
@ -91,17 +92,17 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
|
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
|
||||||
if ((androidInfo.version.sdkInt) >= 33) {
|
if ((androidInfo.version.sdkInt) >= 33) {
|
||||||
final videos = await Permissions.checkPermission(
|
final videos = await Permissions.checkPermission(
|
||||||
context,Permission.videos.value,
|
context, Permission.videos.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!videos){
|
if (!videos) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final storage = await Permissions.checkPermission(
|
final storage = await Permissions.checkPermission(
|
||||||
context, Permission.storage.value,
|
context, Permission.storage.value,
|
||||||
);
|
);
|
||||||
if(!storage){
|
if (!storage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -243,67 +244,41 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
setVideoMessage() async {
|
setVideoPlayerController() async {
|
||||||
// Using local path while sending
|
|
||||||
// VideoPlayerController player = widget.message.videoElem!.videoUrl == null ||
|
|
||||||
// widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING
|
|
||||||
// ? VideoPlayerController.file(File(
|
|
||||||
// widget.message.videoElem!.videoPath!,
|
|
||||||
// ))
|
|
||||||
// : (widget.message.videoElem?.localVideoUrl == null ||
|
|
||||||
// widget.message.videoElem?.localVideoUrl == "")
|
|
||||||
// ? VideoPlayerController.network(
|
|
||||||
// widget.message.videoElem!.videoUrl!,
|
|
||||||
// )
|
|
||||||
// : VideoPlayerController.file(File(
|
|
||||||
// widget.message.videoElem!.localVideoUrl!,
|
|
||||||
// ));
|
|
||||||
if (!PlatformUtils().isWeb) {
|
if (!PlatformUtils().isWeb) {
|
||||||
if (widget.message.msgID != null || widget.message.msgID != '') {
|
if (TencentUtils.checkString(widget.message.msgID) != null &&
|
||||||
if (model.getMessageProgress(widget.message.msgID) == 100) {
|
widget.videoElement.localVideoUrl == null) {
|
||||||
String savePath;
|
String savePath = model.getFileMessageLocation(widget.message.msgID);
|
||||||
if (widget.message.videoElem!.localVideoUrl != null &&
|
File f = File(savePath);
|
||||||
widget.message.videoElem!.localVideoUrl != '') {
|
if (f.existsSync()) {
|
||||||
savePath = widget.message.videoElem!.localVideoUrl!;
|
widget.videoElement.localVideoUrl = savePath;
|
||||||
} else {
|
|
||||||
savePath = model.getFileMessageLocation(widget.message.msgID);
|
|
||||||
}
|
|
||||||
File f = File(savePath);
|
|
||||||
if (f.existsSync()) {
|
|
||||||
widget.videoElement.localVideoUrl =
|
|
||||||
model.getFileMessageLocation(widget.message.msgID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoPlayerController player = PlatformUtils().isWeb
|
VideoPlayerController player = PlatformUtils().isWeb
|
||||||
? ((widget.videoElement.videoPath != null &&
|
? ((TencentUtils.checkString(widget.videoElement.videoPath) != null) ||
|
||||||
widget.videoElement.videoPath!.isNotEmpty) ||
|
widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING
|
||||||
widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING
|
? VideoPlayerController.networkUrl(
|
||||||
? VideoPlayerController.network(
|
Uri.parse(widget.videoElement.videoPath!),
|
||||||
widget.videoElement.videoPath!,
|
)
|
||||||
)
|
: (TencentUtils.checkString(widget.videoElement.localVideoUrl) == null)
|
||||||
: (widget.videoElement.localVideoUrl == null ||
|
? VideoPlayerController.networkUrl(
|
||||||
widget.videoElement.localVideoUrl == "")
|
Uri.parse(widget.videoElement.videoUrl!),
|
||||||
? VideoPlayerController.network(
|
)
|
||||||
widget.videoElement.videoUrl!,
|
: VideoPlayerController.networkUrl(
|
||||||
)
|
Uri.parse(widget.videoElement.localVideoUrl!),
|
||||||
: VideoPlayerController.network(
|
))
|
||||||
widget.videoElement.localVideoUrl!,
|
: (TencentUtils.checkString(widget.videoElement.videoPath) != null ||
|
||||||
))
|
widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING)
|
||||||
: (widget.videoElement.videoPath != null &&
|
? VideoPlayerController.file(File(widget.videoElement.videoPath!))
|
||||||
widget.videoElement.videoPath!.isNotEmpty) ||
|
: (TencentUtils.checkString(widget.videoElement.localVideoUrl) == null)
|
||||||
widget.message.status == MessageStatus.V2TIM_MSG_STATUS_SENDING
|
? VideoPlayerController.networkUrl(
|
||||||
? VideoPlayerController.file(File(widget.videoElement.videoPath!))
|
Uri.parse(widget.videoElement.videoUrl!),
|
||||||
: (widget.videoElement.localVideoUrl == null ||
|
)
|
||||||
widget.videoElement.localVideoUrl == "")
|
: VideoPlayerController.file(File(
|
||||||
? VideoPlayerController.network(
|
widget.videoElement.localVideoUrl!,
|
||||||
widget.videoElement.videoUrl!,
|
));
|
||||||
)
|
|
||||||
: VideoPlayerController.file(File(
|
|
||||||
widget.videoElement.localVideoUrl!,
|
|
||||||
));
|
|
||||||
await player.initialize();
|
await player.initialize();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
double w = getVideoWidth();
|
double w = getVideoWidth();
|
||||||
|
|
@ -315,7 +290,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
showControlsOnInitialize: false,
|
showControlsOnInitialize: false,
|
||||||
allowPlaybackSpeedChanging: false,
|
allowPlaybackSpeedChanging: false,
|
||||||
aspectRatio: w == 0 || h == 0 ? null : w / h,
|
aspectRatio: w == 0 || h == 0 ? null : w / h,
|
||||||
customControls: VideoCustomControls(downloadFn: () async{
|
customControls: VideoCustomControls(downloadFn: () async {
|
||||||
return await _saveVideo();
|
return await _saveVideo();
|
||||||
}));
|
}));
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -330,7 +305,7 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
didUpdateWidget(oldWidget) {
|
didUpdateWidget(oldWidget) {
|
||||||
if (oldWidget.videoElement.videoUrl != widget.videoElement.videoUrl ||
|
if (oldWidget.videoElement.videoUrl != widget.videoElement.videoUrl ||
|
||||||
oldWidget.videoElement.videoPath != widget.videoElement.videoPath) {
|
oldWidget.videoElement.videoPath != widget.videoElement.videoPath) {
|
||||||
setVideoMessage();
|
setVideoPlayerController();
|
||||||
}
|
}
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
}
|
}
|
||||||
|
|
@ -350,55 +325,70 @@ class _VideoScreenState extends TIMUIKitState<VideoScreen> {
|
||||||
@override
|
@override
|
||||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||||
return OrientationBuilder(builder: ((context, orientation) {
|
return OrientationBuilder(builder: ((context, orientation) {
|
||||||
return Scaffold(
|
return Material(
|
||||||
body: Container(
|
color: Colors.transparent,
|
||||||
color: Colors.transparent,
|
child: Container(
|
||||||
constraints: BoxConstraints.expand(
|
color: Colors.transparent,
|
||||||
height: MediaQuery.of(context).size.height,
|
constraints: BoxConstraints.expand(
|
||||||
),
|
height: MediaQuery
|
||||||
child: ExtendedImageSlidePage(
|
.of(context)
|
||||||
key: slidePagekey,
|
.size
|
||||||
slidePageBackgroundHandler: (Offset offset, Size size) {
|
.height,
|
||||||
if (orientation == Orientation.landscape) {
|
),
|
||||||
return Colors.black;
|
child: ExtendedImageSlidePage(
|
||||||
}
|
key: slidePagekey,
|
||||||
double opacity = 0.0;
|
slidePageBackgroundHandler: (Offset offset, Size size) {
|
||||||
opacity = offset.distance /
|
if (orientation == Orientation.landscape) {
|
||||||
(Offset(size.width, size.height).distance / 2.0);
|
return Colors.black;
|
||||||
return Colors.black
|
}
|
||||||
.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
|
double opacity = 0.0;
|
||||||
},
|
opacity = offset.distance /
|
||||||
slideType: SlideType.onlyImage,
|
(Offset(size.width, size.height).distance / 2.0);
|
||||||
child: ExtendedImageSlidePageHandler(
|
return Colors.black
|
||||||
child: Container(
|
.withOpacity(min(1.0, max(1.0 - opacity, 0.0)));
|
||||||
color: Colors.black,
|
},
|
||||||
child: isInit
|
slideType: SlideType.onlyImage,
|
||||||
? Chewie(
|
slideEndHandler: (Offset offset, {
|
||||||
controller: chewieController,
|
ExtendedImageSlidePageState? state,
|
||||||
)
|
ScaleEndDetails? details,
|
||||||
: const Center(
|
}) {
|
||||||
|
final vy = details?.velocity.pixelsPerSecond.dy ?? 0;
|
||||||
|
final oy = offset.dy;
|
||||||
|
if (vy > 300 || oy > 100) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
child: ExtendedImageSlidePageHandler(
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black,
|
||||||
|
child: isInit
|
||||||
|
? Chewie(
|
||||||
|
controller: chewieController,
|
||||||
|
)
|
||||||
|
: const Center(
|
||||||
child:
|
child:
|
||||||
CircularProgressIndicator(color: Colors.white))),
|
CircularProgressIndicator(color: Colors.white))),
|
||||||
heroBuilderForSlidingPage: (Widget result) {
|
heroBuilderForSlidingPage: (Widget result) {
|
||||||
return Hero(
|
return Hero(
|
||||||
tag: widget.heroTag,
|
tag: widget.heroTag,
|
||||||
child: result,
|
child: result,
|
||||||
flightShuttleBuilder: (BuildContext flightContext,
|
flightShuttleBuilder: (BuildContext flightContext,
|
||||||
Animation<double> animation,
|
Animation<double> animation,
|
||||||
HeroFlightDirection flightDirection,
|
HeroFlightDirection flightDirection,
|
||||||
BuildContext fromHeroContext,
|
BuildContext fromHeroContext,
|
||||||
BuildContext toHeroContext) {
|
BuildContext toHeroContext) {
|
||||||
final Hero hero =
|
final Hero hero =
|
||||||
(flightDirection == HeroFlightDirection.pop
|
(flightDirection == HeroFlightDirection.pop
|
||||||
? fromHeroContext.widget
|
? fromHeroContext.widget
|
||||||
: toHeroContext.widget) as Hero;
|
: toHeroContext.widget) as Hero;
|
||||||
|
|
||||||
return hero.child;
|
return hero.child;
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
)),
|
||||||
},
|
));
|
||||||
)),
|
|
||||||
));
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
|
// ignore_for_file: unused_import
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:chewie_for_us/chewie_for_us.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal_operation_key.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal_operation_key.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/drag_widget.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/drag_widget.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
class TUIKitWidePopup {
|
class TUIKitWidePopup {
|
||||||
static OverlayEntry? entry;
|
static OverlayEntry? entry;
|
||||||
|
|
@ -236,7 +244,7 @@ class TUIKitWidePopup {
|
||||||
|
|
||||||
if (isUseMaterialAlert) {
|
if (isUseMaterialAlert) {
|
||||||
return showDialog(
|
return showDialog(
|
||||||
barrierDismissible: false,
|
barrierDismissible: true,
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
|
|
@ -249,7 +257,8 @@ class TUIKitWidePopup {
|
||||||
content: contentWidget,
|
content: contentWidget,
|
||||||
),
|
),
|
||||||
onWillPop: () {
|
onWillPop: () {
|
||||||
return Future.value(false);
|
isShow = false;
|
||||||
|
return Future.value(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -276,4 +285,141 @@ class TUIKitWidePopup {
|
||||||
});
|
});
|
||||||
Overlay.of(context).insert(entry!);
|
Overlay.of(context).insert(entry!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void showMedia({
|
||||||
|
String? mediaLocalPath,
|
||||||
|
String? mediaURL,
|
||||||
|
required BuildContext context,
|
||||||
|
required VoidCallback onClickOrigin,
|
||||||
|
double? aspectRatio,
|
||||||
|
}) async {
|
||||||
|
assert((mediaLocalPath != null) || (mediaURL != null),
|
||||||
|
"At least one of mediaLocalPath or mediaURL must be provided.");
|
||||||
|
|
||||||
|
String _removeQueryString(String urlString) {
|
||||||
|
Uri uri = Uri.parse(urlString);
|
||||||
|
Uri cleanUri = Uri(
|
||||||
|
scheme: uri.scheme,
|
||||||
|
host: uri.host,
|
||||||
|
port: uri.port,
|
||||||
|
path: uri.path,
|
||||||
|
);
|
||||||
|
return cleanUri.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String mediaPath = mediaLocalPath ?? mediaURL ?? "";
|
||||||
|
final isLocalResource = mediaLocalPath != null;
|
||||||
|
|
||||||
|
String fileExtension = p
|
||||||
|
.extension(isLocalResource ? mediaPath : _removeQueryString(mediaPath));
|
||||||
|
bool isVideo =
|
||||||
|
['.mp4', '.avi', '.mov', '.flv', '.wmv'].contains(fileExtension);
|
||||||
|
|
||||||
|
VideoPlayerController? videoController;
|
||||||
|
ChewieController? chewieController;
|
||||||
|
Widget mediaWidget;
|
||||||
|
double? aspectRatioFinal = aspectRatio;
|
||||||
|
|
||||||
|
if (isVideo) {
|
||||||
|
if (isLocalResource) {
|
||||||
|
videoController = VideoPlayerController.file(File(mediaPath));
|
||||||
|
} else {
|
||||||
|
videoController = VideoPlayerController.networkUrl(Uri.parse(mediaPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
await videoController.initialize();
|
||||||
|
aspectRatioFinal = videoController.value.aspectRatio;
|
||||||
|
|
||||||
|
chewieController = ChewieController(
|
||||||
|
videoPlayerController: videoController,
|
||||||
|
aspectRatio: aspectRatioFinal,
|
||||||
|
autoPlay: true,
|
||||||
|
looping: false,
|
||||||
|
autoInitialize: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
mediaWidget = Chewie(controller: chewieController);
|
||||||
|
} else {
|
||||||
|
mediaWidget = FittedBox(
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
child: isLocalResource
|
||||||
|
? Image.file(File(mediaPath), fit: BoxFit.contain)
|
||||||
|
: Image.network(mediaPath, fit: BoxFit.contain),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
barrierDismissible: true,
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return WillPopScope(
|
||||||
|
child: AlertDialog(
|
||||||
|
surfaceTintColor: Colors.transparent,
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
titlePadding: const EdgeInsets.all(0),
|
||||||
|
contentPadding: const EdgeInsets.all(0),
|
||||||
|
content: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxWidth: MediaQuery.of(context).size.width * 0.85,
|
||||||
|
maxHeight: MediaQuery.of(context).size.height * 0.82,
|
||||||
|
),
|
||||||
|
child: aspectRatioFinal != null
|
||||||
|
? AspectRatio(
|
||||||
|
aspectRatio: aspectRatioFinal,
|
||||||
|
child: mediaWidget)
|
||||||
|
: mediaWidget,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
InkWell(
|
||||||
|
onTap: onClickOrigin,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 0),
|
||||||
|
child: Icon(
|
||||||
|
Icons.open_in_new,
|
||||||
|
size: 14,
|
||||||
|
color: Colors.grey.shade200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
// Custom Text Widget with designer baseline
|
||||||
|
Text(
|
||||||
|
TIM_t("在新窗口中打开"),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: Colors.grey.shade200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onWillPop: () {
|
||||||
|
if (isVideo) videoController?.dispose();
|
||||||
|
return Future.value(true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
358
pubspec.lock
358
pubspec.lock
|
|
@ -5,10 +5,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
|
sha256: "0816708f5fbcacca324d811297153fe3c8e047beb5c6752e12292d2974c17045"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "61.0.0"
|
version: "62.0.0"
|
||||||
adaptive_action_sheet:
|
adaptive_action_sheet:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -21,18 +21,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
|
sha256: "21862995c9932cd082f89d72ae5f5e2c110d1a0204ad06e4ebaee8307b76b834"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.13.0"
|
version: "6.0.0"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: args
|
name: args
|
||||||
sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
|
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1"
|
version: "2.4.2"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -117,10 +117,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build
|
name: build
|
||||||
sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc"
|
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.0"
|
version: "2.4.1"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -141,26 +141,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_resolvers
|
name: build_resolvers
|
||||||
sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95
|
sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.1"
|
||||||
build_runner:
|
build_runner:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "220ae4553e50d7c21a17c051afc7b183d28a24a420502e842f303f8e4e6edced"
|
sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.4"
|
version: "2.4.6"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_runner_core
|
name: build_runner_core
|
||||||
sha256: "88a57f2ac99849362e73878334caa9f06ee25f31d2adced882b8337838c84e1e"
|
sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.9"
|
version: "7.2.10"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -173,10 +173,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: "7dd62d9faf105c434f3d829bbe9c4be02ec67f5ed94832222116122df67c5452"
|
sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.6.0"
|
version: "8.6.1"
|
||||||
cached_network_image:
|
cached_network_image:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -213,10 +213,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: camera_android
|
name: camera_android
|
||||||
sha256: f83e406d34f5faa80bf0f5c3beee4b4c11da94a94e9621c1bb8e312988621b4b
|
sha256: f43d07f9d7228ea1ca87d22e30881bd68da4b78484a1fbd1f1408b412a41cefb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.10.8+2"
|
version: "0.10.8+3"
|
||||||
camera_avfoundation:
|
camera_avfoundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -285,10 +285,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: code_builder
|
name: code_builder
|
||||||
sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
|
sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.0"
|
version: "4.5.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -345,14 +345,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.5"
|
||||||
|
dart_internal:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_internal
|
||||||
|
sha256: dae3976f383beddcfcd07ad5291a422df2c8c0a8a03c52cda63ac7b4f26e0f4e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.8"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad
|
sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.2"
|
||||||
desktop_drop:
|
desktop_drop:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -365,10 +373,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: device_info_plus
|
name: device_info_plus
|
||||||
sha256: "499c61743e13909c13374a8c209075385858c614b9c0f2487b5f9995eeaf7369"
|
sha256: "2c35b6d1682b028e42d07b3aee4b98fa62996c10bc12cb651ec856a80d6a761b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.0.1"
|
version: "9.0.2"
|
||||||
device_info_plus_platform_interface:
|
device_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -397,42 +405,42 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: extended_image
|
name: extended_image
|
||||||
sha256: "73b7051722be79f9e8f8c120951fd9d3b22e6153fda6105c322fb88c066952d6"
|
sha256: e77d18f956649ba6e5ecebd0cb68542120886336a75ee673788145bd4c3f0767
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.1"
|
version: "8.0.2"
|
||||||
extended_image_library:
|
extended_image_library:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: extended_image_library
|
name: extended_image_library
|
||||||
sha256: f2eba5c8500c5a7ce1f0db703b787756cb3bc65cd3818636d5fe9a9ace011ee3
|
sha256: af3ff1c09c23ca7663f94272313d63499a6bd19121e99378e375e0cf2ac7a3e4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.5.1"
|
version: "3.5.2"
|
||||||
extended_text:
|
extended_text:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: extended_text
|
name: extended_text
|
||||||
sha256: "75ddf28ce7d5be33a050ff2179b6567b4b98e6225ad3e61e4c3748f7448c25f7"
|
sha256: dec14c9b36d9bbaaf007da5998f5dc72a2dbd5b877601d7b7970bb42524b3ced
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.0.0"
|
version: "11.0.1"
|
||||||
extended_text_field:
|
extended_text_field:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: extended_text_field
|
name: extended_text_field
|
||||||
sha256: "6cf8c090de4dc1e309cf3b24cb9448d7463c6c17926b628cf0954631bf4e56db"
|
sha256: e93248bb9b04a3e6c5e88a6a96e1c08cc765097657ab25aabe409e06a4f6760a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "12.0.0"
|
version: "12.0.1"
|
||||||
extended_text_library:
|
extended_text_library:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: extended_text_library
|
name: extended_text_library
|
||||||
sha256: "308b50cfcc8e3accf46a09cb692715fbd1097333817c15b0f7527de1766bc1ff"
|
sha256: c06fbd8e3b6eedadf50cd6c109bbbd80921a6c43e4422d3b4ec9d4cb36ce4555
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.0.1"
|
version: "11.0.2"
|
||||||
fast_i18n:
|
fast_i18n:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
|
@ -469,10 +477,42 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: file_picker
|
name: file_picker
|
||||||
sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf"
|
sha256: b1729fc96627dd44012d0a901558177418818d6bd428df59dcfeb594e5f66432
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.3.1"
|
version: "5.3.2"
|
||||||
|
file_selector_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_linux
|
||||||
|
sha256: "770eb1ab057b5ae4326d1c24cc57710758b9a46026349d021d6311bd27580046"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.2"
|
||||||
|
file_selector_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_macos
|
||||||
|
sha256: "7a6f1ae6107265664f3f7f89a66074882c4d506aef1441c9af313c1f7e6f41ce"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.3"
|
||||||
|
file_selector_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_platform_interface
|
||||||
|
sha256: "412705a646a0ae90f33f37acfae6a0f7cbc02222d6cd34e479421c3e74d3853c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.6.0"
|
||||||
|
file_selector_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_windows
|
||||||
|
sha256: "1372760c6b389842b77156203308940558a2817360154084368608413835fc26"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.3"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -498,10 +538,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_cache_manager
|
name: flutter_cache_manager
|
||||||
sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3"
|
sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.0"
|
version: "3.3.1"
|
||||||
flutter_easyrefresh:
|
flutter_easyrefresh:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -530,10 +570,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: dc6d5258653f6857135b32896ccda7f7af0c54dcec832495ad6835154c6c77c0
|
sha256: "4b1bfbb802d76320a1a46d9ce984106135093efd9d969765d07c2125af107bdf"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.15"
|
version: "0.6.17"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -562,10 +602,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_svg
|
name: flutter_svg
|
||||||
sha256: "6ff8c902c8056af9736de2689f63f81c42e2d642b9f4c79dbf8790ae48b63012"
|
sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.6"
|
version: "2.0.7"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
@ -607,10 +647,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: html
|
name: html
|
||||||
sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8"
|
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.3"
|
version: "0.15.4"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -647,50 +687,74 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: image_gallery_saver
|
name: image_gallery_saver
|
||||||
sha256: "009b7722cd8507fd72c7f2cb7cbc46d6e15ad0895469cfcc39a10f86e3556979"
|
sha256: "0aba74216a4d9b0561510cb968015d56b701ba1bd94aace26aacdd8ae5761816"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.3"
|
||||||
image_picker:
|
image_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: image_picker
|
name: image_picker
|
||||||
sha256: "9978d3510af4e6a902e545ce19229b926e6de6a1828d6134d3aab2e129a4d270"
|
sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.7+5"
|
version: "0.8.9"
|
||||||
image_picker_android:
|
image_picker_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_android
|
name: image_picker_android
|
||||||
sha256: c2f3c66400649bd132f721c88218945d6406f693092b2f741b79ae9cdb046e59
|
sha256: d2bab152deb2547ea6f53d82ebca9b7e77386bb706e5789e815d37e08ea475bb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.6+16"
|
version: "0.8.7+3"
|
||||||
image_picker_for_web:
|
image_picker_for_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_for_web
|
name: image_picker_for_web
|
||||||
sha256: "98f50d6b9f294c8ba35e25cc0d13b04bfddd25dbc8d32fa9d566a6572f2c081c"
|
sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.12"
|
version: "2.2.0"
|
||||||
image_picker_ios:
|
image_picker_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_ios
|
name: image_picker_ios
|
||||||
sha256: d779210bda268a03b57e923fb1e410f32f5c5e708ad256348bcbf1f44f558fd0
|
sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.7+4"
|
version: "0.8.8"
|
||||||
|
image_picker_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_linux
|
||||||
|
sha256: "02cbc21fe1706b97942b575966e5fbbeaac535e76deef70d3a242e4afb857831"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
|
image_picker_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_macos
|
||||||
|
sha256: cee2aa86c56780c13af2c77b5f2f72973464db204569e1ba2dd744459a065af4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
image_picker_platform_interface:
|
image_picker_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_picker_platform_interface
|
name: image_picker_platform_interface
|
||||||
sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8"
|
sha256: "7c7b96bb9413a9c28229e717e6fd1e3edd1cc5569c1778fcca060ecf729b65ee"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.3"
|
version: "2.8.0"
|
||||||
|
image_picker_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_windows
|
||||||
|
sha256: c3066601ea42113922232c7b7b3330a2d86f029f685bba99d82c30e799914952
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -775,10 +839,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.15"
|
version: "0.12.16"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -831,10 +895,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: package_info_plus
|
name: package_info_plus
|
||||||
sha256: "28386bbe89ab5a7919a47cea99cdd1128e5a6e0bbd7eaafe20440ead84a15de3"
|
sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.1"
|
version: "4.0.2"
|
||||||
package_info_plus_platform_interface:
|
package_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -919,58 +983,50 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_windows
|
name: path_provider_windows
|
||||||
sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6
|
sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.6"
|
version: "2.1.7"
|
||||||
pedantic:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: pedantic
|
|
||||||
sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.11.1"
|
|
||||||
permission_handler:
|
permission_handler:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: permission_handler
|
name: permission_handler
|
||||||
sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8"
|
sha256: "415af30ba76a84faccfe1eb251fe1e4fdc790f876924c65ad7d6ed7a1404bcd6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.2.0"
|
version: "10.4.2"
|
||||||
permission_handler_android:
|
permission_handler_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_android
|
name: permission_handler_android
|
||||||
sha256: d8cc6a62ded6d0f49c6eac337e080b066ee3bce4d405bd9439a61e1f1927bfe8
|
sha256: "3b61f3da3b1c83bc3fb6a2b431e8dab01d0e5b45f6a3d9c7609770ec88b2a89e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.2.1"
|
version: "10.3.0"
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_apple
|
name: permission_handler_apple
|
||||||
sha256: ee96ac32f5a8e6f80756e25b25b9f8e535816c8e6665a96b6d70681f8c4f7e85
|
sha256: "7a187b671a39919462af2b5e813148365b71a615979165a119868d667fe90c03"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.0.8"
|
version: "9.1.3"
|
||||||
permission_handler_platform_interface:
|
permission_handler_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_platform_interface
|
name: permission_handler_platform_interface
|
||||||
sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84"
|
sha256: "463a07cb7cc6c758a7a1c7da36ce666bb80a0b4b5e92df0fa36872e0ed456993"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.9.0"
|
version: "3.11.1"
|
||||||
permission_handler_windows:
|
permission_handler_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_windows
|
name: permission_handler_windows
|
||||||
sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b
|
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.2"
|
version: "0.1.3"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1079,58 +1135,58 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022"
|
sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.2.0"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749"
|
sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.2.0"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_foundation
|
name: shared_preferences_foundation
|
||||||
sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb
|
sha256: b046999bf0ff58f04c364491bb803dcfa8f42e47b19c75478f53d323684a8cc1
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.3.1"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_linux
|
name: shared_preferences_linux
|
||||||
sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa"
|
sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.0"
|
||||||
shared_preferences_platform_interface:
|
shared_preferences_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_platform_interface
|
name: shared_preferences_platform_interface
|
||||||
sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d
|
sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.0"
|
||||||
shared_preferences_web:
|
shared_preferences_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_web
|
name: shared_preferences_web
|
||||||
sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5"
|
sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.2.0"
|
||||||
shared_preferences_windows:
|
shared_preferences_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_windows
|
name: shared_preferences_windows
|
||||||
sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173"
|
sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.0"
|
||||||
shelf:
|
shelf:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1147,14 +1203,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
shell:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: shell
|
|
||||||
sha256: fd3b7b97e5e7f734138543d5815c6cb6cdd2a1645a0def8ac8e05577cddfbe03
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.0"
|
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
@ -1164,10 +1212,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_span
|
name: source_span
|
||||||
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.10.0"
|
||||||
sqflite:
|
sqflite:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1180,26 +1228,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
sha256: e77abf6ff961d69dfef41daccbb66b51e9983cdd5cb35bf30733598057401555
|
sha256: "8f7603f3f8f126740bc55c4ca2d1027aab4b74a1267a3e31ce51fe40e3b65b8f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.5"
|
version: "2.4.5+1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.0"
|
version: "1.11.1"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
stream_transform:
|
stream_transform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1224,6 +1272,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
|
tencent_chat_i18n_tool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tencent_chat_i18n_tool
|
||||||
|
sha256: ac8171d2574ed18babedd0cb67e937e255bf02fcb72f55408d033f74d4b11949
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3+2"
|
||||||
tencent_cloud_chat_sdk:
|
tencent_cloud_chat_sdk:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1236,18 +1292,18 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tencent_cloud_uikit_core
|
name: tencent_cloud_uikit_core
|
||||||
sha256: "0131874c7b15e181001c94f8a668f0ccae3006dea6e70d4e42e5531b63313a27"
|
sha256: "0a0f43e4c4241b25d12a9e9f0ee91922ac800a42229d97e3d21d16041ace3104"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.8"
|
||||||
tencent_im_base:
|
tencent_im_base:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tencent_im_base
|
name: tencent_im_base
|
||||||
sha256: "9b8e712bf27ffae9b686ec532ee8417b8263eba8bab04f105e28a95de1807322"
|
sha256: "0db83050452486571ee4ac07280a2fb4bbc07d297a54235b5cf12e46e79267d0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.57"
|
version: "2.0.1"
|
||||||
tencent_im_sdk_plugin_platform_interface:
|
tencent_im_sdk_plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1268,10 +1324,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tencent_open_file
|
name: tencent_open_file
|
||||||
sha256: "01f94f618da42e5593bbad0657fcd13cfc1c2360cca805d8cdfefe898cbe5429"
|
sha256: bb92d2f052c150a45942c564fba13d150a1b7b47525e6fdd74ccc58058ba5dcf
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.10"
|
version: "4.0.11"
|
||||||
tencent_super_tooltip:
|
tencent_super_tooltip:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1292,18 +1348,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
|
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.6.1"
|
||||||
tim_ui_kit_sticker_plugin:
|
tim_ui_kit_sticker_plugin:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tim_ui_kit_sticker_plugin
|
name: tim_ui_kit_sticker_plugin
|
||||||
sha256: "2a825d33076f319f6c1c87d58e2b0d650c9284ae4afd8efdc206f3e6f3582e64"
|
sha256: c9b0c1261bb51a5dee54bb50c6a106061b1bb10731b9c815fc5175afa60175e2
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.2.1"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1324,10 +1380,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tuple
|
name: tuple
|
||||||
sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1348,26 +1404,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: universal_io
|
name: universal_io
|
||||||
sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d"
|
sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.2"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3
|
sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.11"
|
version: "6.1.12"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: eed4e6a1164aa9794409325c3b707ff424d4d1c2a785e7db67f8bbda00e36e51
|
sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.35"
|
version: "6.0.36"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1396,26 +1452,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_platform_interface
|
name: url_launcher_platform_interface
|
||||||
sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370"
|
sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
url_launcher_web:
|
url_launcher_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
sha256: "6bb1e5d7fe53daf02a8fee85352432a40b1f868a81880e99ec7440113d5cfcab"
|
sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.17"
|
version: "2.0.18"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_windows
|
name: url_launcher_windows
|
||||||
sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771"
|
sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.6"
|
version: "3.0.7"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1428,26 +1484,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics
|
name: vector_graphics
|
||||||
sha256: b96f10cbdfcbd03a65758633a43e7d04574438f059b1043104b5d61b23d38a4f
|
sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.7"
|
||||||
vector_graphics_codec:
|
vector_graphics_codec:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics_codec
|
name: vector_graphics_codec
|
||||||
sha256: "57a8e6e24662a3bdfe3b3d61257db91768700c0b8f844e235877b56480f31c69"
|
sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.7"
|
||||||
vector_graphics_compiler:
|
vector_graphics_compiler:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_graphics_compiler
|
name: vector_graphics_compiler
|
||||||
sha256: "7430f5d834d0db4560d7b19863362cd892f1e52b43838553a3c5cdfc9ab28e5b"
|
sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.6"
|
version: "1.1.7"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1460,18 +1516,18 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: video_player
|
name: video_player
|
||||||
sha256: de95f0e9405f29b5582573d4166132e71f83b3158aac14e8ee5767a54f4f1fbd
|
sha256: "3fd106c74da32f336dc7feb65021da9b0207cb3124392935f1552834f7cce822"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.1"
|
version: "2.7.0"
|
||||||
video_player_android:
|
video_player_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: video_player_android
|
name: video_player_android
|
||||||
sha256: ae1c7d9a71c236a1bf9e567bd7ed4c90887e389a5f233b2192593f7f7395005c
|
sha256: f338a5a396c845f4632959511cad3542cdf3167e1b2a1a948ef07f7123c03608
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.8"
|
version: "2.4.9"
|
||||||
video_player_avfoundation:
|
video_player_avfoundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1500,10 +1556,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: wakelock_for_us
|
name: wakelock_for_us
|
||||||
sha256: b73bfa90e5e764f41155063ae92fbd1e3a04ee6372e65ff7d288d2c3057f9498
|
sha256: a5bdd445e51a617f7c24be8165230391447301f622aacd050038cee7b41989b4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.3"
|
version: "0.6.3+1"
|
||||||
wakelock_platform_interface:
|
wakelock_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1548,18 +1604,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
|
sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.4"
|
version: "5.0.5"
|
||||||
win32_registry:
|
win32_registry:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32_registry
|
name: win32_registry
|
||||||
sha256: "1c52f994bdccb77103a6231ad4ea331a244dbcef5d1f37d8462f713143b0bfae"
|
sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.1"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1585,5 +1641,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.0 <4.0.0"
|
dart: ">=3.0.0 <3.2.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.10.0"
|
||||||
|
|
|
||||||
10
pubspec.yaml
10
pubspec.yaml
|
|
@ -1,6 +1,6 @@
|
||||||
name: tencent_cloud_chat_uikit
|
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.
|
description: A powerful chat UI component library and business logic for Tencent Cloud Chat, creating seamless in-app chat modules for delightful user experiences.
|
||||||
version: 2.1.2
|
version: 2.1.3+1
|
||||||
homepage: https://www.tencentcloud.com/products/im?from=pub
|
homepage: https://www.tencentcloud.com/products/im?from=pub
|
||||||
repository: https://github.com/TencentCloud/tc-chat-uikit-flutter
|
repository: https://github.com/TencentCloud/tc-chat-uikit-flutter
|
||||||
documentation: https://comm.qq.com/im/doc/flutter/en/TUIKit/readme.html
|
documentation: https://comm.qq.com/im/doc/flutter/en/TUIKit/readme.html
|
||||||
|
|
@ -29,7 +29,7 @@ dependencies:
|
||||||
image_picker: ^0.8.5+3
|
image_picker: ^0.8.5+3
|
||||||
file_picker: ^5.3.0
|
file_picker: ^5.3.0
|
||||||
tencent_super_tooltip: ^0.0.1
|
tencent_super_tooltip: ^0.0.1
|
||||||
video_player: ^2.4.2
|
video_player: ^2.7.0
|
||||||
chewie_for_us: ^1.5.0
|
chewie_for_us: ^1.5.0
|
||||||
flutter_slidable_for_tencent_im: ^1.4.0
|
flutter_slidable_for_tencent_im: ^1.4.0
|
||||||
flutter_plugin_record_plus: ^0.0.16
|
flutter_plugin_record_plus: ^0.0.16
|
||||||
|
|
@ -62,12 +62,12 @@ dependencies:
|
||||||
uuid: ^3.0.6
|
uuid: ^3.0.6
|
||||||
tencent_open_file: ^4.0.10
|
tencent_open_file: ^4.0.10
|
||||||
tencent_keyboard_visibility: ^1.0.1
|
tencent_keyboard_visibility: ^1.0.1
|
||||||
tim_ui_kit_sticker_plugin: ^2.0.1
|
tim_ui_kit_sticker_plugin: ^2.2.1
|
||||||
tencent_im_base: ^1.0.57
|
tencent_im_base: ^2.0.1
|
||||||
fc_native_video_thumbnail: any
|
fc_native_video_thumbnail: any
|
||||||
audioplayers: ^3.0.1
|
audioplayers: ^3.0.1
|
||||||
path: ^1.8.1
|
path: ^1.8.1
|
||||||
tencent_cloud_uikit_core: ^1.0.2
|
tencent_cloud_uikit_core: ^1.0.7
|
||||||
pasteboard: ^0.2.0
|
pasteboard: ^0.2.0
|
||||||
desktop_drop: ^0.4.1
|
desktop_drop: ^0.4.1
|
||||||
device_info_plus: any
|
device_info_plus: any
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue