Feat: Upgrade UIKit to 2.2.1
This commit is contained in:
parent
d0b60c68a8
commit
8310e521f8
14
CHANGELOG.md
14
CHANGELOG.md
|
|
@ -1,3 +1,17 @@
|
||||||
|
## 2.2.1
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* Introduced a new `groupMemberList` configuration in `TUIKitChat`; when specified, TUIKit will not load it automatically, optimizing network traffic usage.
|
||||||
|
* Added support for image copying on desktop platforms.
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Fixed an issue preventing the removal of image loading status.
|
||||||
|
* Resolved a problem that prevented images from being saved to the device gallery.
|
||||||
|
* Addressed a potential issue causing the `mentionOtherMemberInGroup` function in `TIMUIKitChatController` to fail.
|
||||||
|
* Corrected an issue that could lead to improper image rendering.
|
||||||
|
|
||||||
## 2.2.0
|
## 2.2.0
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,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 <file_selector_linux/file_selector_plugin.h>
|
||||||
|
#include <image_clipboard/image_clipboard_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>
|
||||||
|
|
||||||
|
|
@ -22,6 +23,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) image_clipboard_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "ImageClipboardPlugin");
|
||||||
|
image_clipboard_plugin_register_with_registrar(image_clipboard_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);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
audioplayers_linux
|
audioplayers_linux
|
||||||
desktop_drop
|
desktop_drop
|
||||||
file_selector_linux
|
file_selector_linux
|
||||||
|
image_clipboard
|
||||||
pasteboard
|
pasteboard
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ 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 file_selector_macos
|
||||||
|
import image_clipboard
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import pasteboard
|
import pasteboard
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
|
|
@ -24,6 +25,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
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"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
|
ImageClipboardPlugin.register(with: registry.registrar(forPlugin: "ImageClipboardPlugin"))
|
||||||
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"))
|
||||||
|
|
|
||||||
|
|
@ -608,6 +608,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
image_clipboard:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_clipboard
|
||||||
|
sha256: "1939365dc3b65acd3b1199176a330180075f4e803a6512f5622d050b62e7eff4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0+2"
|
||||||
image_gallery_saver:
|
image_gallery_saver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1219,7 +1227,7 @@ packages:
|
||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "2.2.0"
|
version: "2.2.1-preview.0"
|
||||||
tencent_cloud_uikit_core:
|
tencent_cloud_uikit_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#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 <file_selector_windows/file_selector_windows.h>
|
||||||
|
#include <image_clipboard/image_clipboard_plugin_c_api.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>
|
||||||
|
|
@ -23,6 +24,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
registry->GetRegistrarForPlugin("FcNativeVideoThumbnailPluginCApi"));
|
registry->GetRegistrarForPlugin("FcNativeVideoThumbnailPluginCApi"));
|
||||||
FileSelectorWindowsRegisterWithRegistrar(
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
|
ImageClipboardPluginCApiRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("ImageClipboardPluginCApi"));
|
||||||
PasteboardPluginRegisterWithRegistrar(
|
PasteboardPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
||||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
desktop_drop
|
desktop_drop
|
||||||
fc_native_video_thumbnail
|
fc_native_video_thumbnail
|
||||||
file_selector_windows
|
file_selector_windows
|
||||||
|
image_clipboard
|
||||||
pasteboard
|
pasteboard
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,8 @@ 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.
|
/// Before rendering a message to message list.
|
||||||
bool Function(V2TimMessage msgID) messageShouldMount;
|
bool Function(V2TimMessage msg) messageShouldMount;
|
||||||
|
|
||||||
ChatLifeCycle({
|
ChatLifeCycle({
|
||||||
this.shouldClearHistoricalMessageList =
|
this.shouldClearHistoricalMessageList =
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
||||||
_groupType = null;
|
_groupType = null;
|
||||||
isGroupExist = true;
|
isGroupExist = true;
|
||||||
_groupInfo = null;
|
_groupInfo = null;
|
||||||
groupMemberList?.clear();
|
groupMemberList = null;
|
||||||
selfMemberInfo = null;
|
selfMemberInfo = null;
|
||||||
|
|
||||||
if (conversationType == ConvType.group) {
|
if (conversationType == ConvType.group) {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/constants/history_message_constant.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/constants/history_message_constant.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/logger.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/logger.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
||||||
|
|
||||||
enum ConvType { none, c2c, group }
|
enum ConvType { none, c2c, group }
|
||||||
|
|
||||||
|
|
@ -49,7 +50,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";
|
||||||
|
|
@ -63,7 +64,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;
|
||||||
|
|
@ -196,17 +197,15 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
Map<String, V2TimMessageReceipt> get messageReadReceiptMap =>
|
Map<String, V2TimMessageReceipt> get messageReadReceiptMap =>
|
||||||
_messageReadReceiptMap;
|
_messageReadReceiptMap;
|
||||||
|
|
||||||
String get currentSelectedConv =>
|
String get currentSelectedConv => _currentConversationList.isNotEmpty
|
||||||
_currentConversationList.isNotEmpty
|
? _currentConversationList[_currentConversationList.length - 1]
|
||||||
? _currentConversationList[_currentConversationList.length - 1]
|
|
||||||
.conversationID
|
.conversationID
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
ConvType? get currentSelectedConvType =>
|
ConvType? get currentSelectedConvType => _currentConversationList.isNotEmpty
|
||||||
_currentConversationList.isNotEmpty
|
? _currentConversationList[_currentConversationList.length - 1]
|
||||||
? _currentConversationList[_currentConversationList.length - 1]
|
|
||||||
.conversationType
|
.conversationType
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
setCurrentConversation(CurrentConversation value) {
|
setCurrentConversation(CurrentConversation value) {
|
||||||
_currentConversationList.add(value);
|
_currentConversationList.add(value);
|
||||||
|
|
@ -242,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();
|
||||||
}
|
}
|
||||||
|
|
@ -333,9 +332,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
prefs.remove(localMsgIDListKey);
|
prefs.remove(localMsgIDListKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateMessageFromController({required String msgID,
|
Future<void> updateMessageFromController(
|
||||||
required String conversationID,
|
{required String msgID,
|
||||||
required ConvType conversationType}) async {
|
required String conversationID,
|
||||||
|
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,
|
||||||
|
|
@ -364,7 +364,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(
|
||||||
|
|
@ -382,12 +382,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;
|
||||||
outputLogger.i("cacheImage ${msgItem.msgID}");
|
outputLogger.i("cacheImage ${msgItem.msgID}");
|
||||||
}));
|
}));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
outputLogger.i("cacheImage error ${msgItem.msgID}");
|
outputLogger.i("cacheImage error ${msgItem.msgID}");
|
||||||
}
|
}
|
||||||
|
|
@ -488,13 +488,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) {
|
||||||
|
|
@ -512,14 +512,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!,
|
||||||
|
|
@ -534,9 +534,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();
|
||||||
}
|
}
|
||||||
|
|
@ -632,17 +632,14 @@ 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
|
targetItem.id = DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
.now()
|
|
||||||
.millisecondsSinceEpoch
|
|
||||||
.toString();
|
|
||||||
activeMessageList[findeIndex] = targetItem;
|
activeMessageList[findeIndex] = targetItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -652,10 +649,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessageModified(V2TimMessage modifiedMessage, [String? convID]) async {
|
onMessageModified(V2TimMessage modifiedMessage, [String? convID]) async {
|
||||||
modifiedMessage.id = DateTime
|
modifiedMessage.id = DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
.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];
|
||||||
|
|
@ -716,8 +710,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
final currentProgress = getMessageProgress(messageProgress.msgID);
|
final currentProgress = getMessageProgress(messageProgress.msgID);
|
||||||
|
|
||||||
if (messageProgress.isFinish && currentProgress < 100) {
|
if (messageProgress.isFinish && currentProgress < 100) {
|
||||||
V2TimMessage? message = await _findAndRetrieveMessage(
|
V2TimMessage? message =
|
||||||
messageProgress.msgID);
|
await _findAndRetrieveMessage(messageProgress.msgID);
|
||||||
_handleFinishedDownload(messageProgress, message);
|
_handleFinishedDownload(messageProgress, message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -726,23 +720,25 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<V2TimMessage?> _findAndRetrieveMessage(String messageId) async {
|
Future<V2TimMessage?> _findAndRetrieveMessage(String messageId) async {
|
||||||
final messages = await _messageService.findMessages(
|
final messages =
|
||||||
messageIDList: [messageId]);
|
await _messageService.findMessages(messageIDList: [messageId]);
|
||||||
return messages?.first;
|
return messages?.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleFinishedDownload(V2TimMessageDownloadProgress messageProgress,
|
void _handleFinishedDownload(
|
||||||
V2TimMessage? message) {
|
V2TimMessageDownloadProgress messageProgress, V2TimMessage? message) {
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
bool isImageType = message.elemType ==
|
bool isImageType =
|
||||||
MessageElemType.V2TIM_ELEM_TYPE_IMAGE;
|
message.elemType == MessageElemType.V2TIM_ELEM_TYPE_IMAGE;
|
||||||
bool isVideoType = message.elemType ==
|
bool isVideoType =
|
||||||
MessageElemType.V2TIM_ELEM_TYPE_VIDEO;
|
message.elemType == MessageElemType.V2TIM_ELEM_TYPE_VIDEO;
|
||||||
|
final originalImageType = PlatformUtils().isIOS ? 1 : 0;
|
||||||
if (!isImageType && !isVideoType) {
|
if (!isImageType && !isVideoType) {
|
||||||
_updateMessageLocationAndDownloadFile(messageProgress);
|
_updateMessageLocationAndDownloadFile(messageProgress);
|
||||||
} else if ((isImageType && messageProgress.type == 0) || isVideoType) {
|
} else if ((isImageType && messageProgress.type == originalImageType) ||
|
||||||
Future.delayed(const Duration(seconds: 1), () =>
|
isVideoType) {
|
||||||
_updateMessageAndDownloadFile(message, messageProgress));
|
Future.delayed(const Duration(seconds: 1),
|
||||||
|
() => _updateMessageAndDownloadFile(message, messageProgress));
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -751,8 +747,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateMessageAndDownloadFile(V2TimMessage message,
|
void _updateMessageAndDownloadFile(
|
||||||
V2TimMessageDownloadProgress messageProgress) {
|
V2TimMessage message, V2TimMessageDownloadProgress messageProgress) {
|
||||||
updateAsyncMessage(
|
updateAsyncMessage(
|
||||||
message,
|
message,
|
||||||
TencentUtils.checkString(message.userID) ??
|
TencentUtils.checkString(message.userID) ??
|
||||||
|
|
@ -769,18 +765,19 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
downloadFile();
|
downloadFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateProgressIfNeeded(V2TimMessageDownloadProgress messageProgress,
|
void _updateProgressIfNeeded(
|
||||||
int currentProgress) {
|
V2TimMessageDownloadProgress messageProgress, int currentProgress) {
|
||||||
try{
|
try {
|
||||||
if (messageProgress.totalSize != -1 && !messageProgress.isFinish) {
|
if (messageProgress.totalSize != -1 && !messageProgress.isFinish) {
|
||||||
int progress = min(99,
|
int progress = min(
|
||||||
|
99,
|
||||||
(messageProgress.currentSize / messageProgress.totalSize * 100)
|
(messageProgress.currentSize / messageProgress.totalSize * 100)
|
||||||
.floor());
|
.floor());
|
||||||
if (progress > 1 && progress > currentProgress) {
|
if (progress > 1 && progress > currentProgress) {
|
||||||
setMessageProgress(messageProgress.msgID, progress);
|
setMessageProgress(messageProgress.msgID, progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
outputLogger.i("calculate error: ${messageProgress.toJson()}");
|
outputLogger.i("calculate error: ${messageProgress.toJson()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -868,13 +865,11 @@ 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 +
|
||||||
"\n@${TencentUtils.checkString(messageBeenReplied.nickName) ??
|
"\n@${TencentUtils.checkString(messageBeenReplied.nickName) ?? TencentUtils.checkString(messageBeenReplied.sender) ?? TencentUtils.checkString(messageBeenReplied.userID)}",
|
||||||
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) ??
|
||||||
|
|
@ -886,7 +881,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
if (messageInfo != null) {
|
if (messageInfo != null) {
|
||||||
final messageInfoWithSender = messageInfo.sender == null
|
final messageInfoWithSender = messageInfo.sender == null
|
||||||
? tools.setUserInfoForMessage(
|
? tools.setUserInfoForMessage(
|
||||||
messageInfo, messageInfo.id ?? textMessageInfo.id ?? "")
|
messageInfo, messageInfo.id ?? textMessageInfo.id ?? "")
|
||||||
: messageInfo;
|
: messageInfo;
|
||||||
|
|
||||||
final hasNickName = messageBeenReplied.nickName != null &&
|
final hasNickName = messageBeenReplied.nickName != null &&
|
||||||
|
|
@ -927,8 +922,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> setLocalCustomData(String msgID, String localCustomData,
|
Future<bool> setLocalCustomData(
|
||||||
String conversationID) async {
|
String msgID, String localCustomData, 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] ?? [];
|
||||||
|
|
@ -947,8 +942,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> setLocalCustomInt(String msgID, int localCustomInt,
|
Future<bool> setLocalCustomInt(
|
||||||
String conversationID) async {
|
String msgID, int localCustomInt, 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] ?? [];
|
||||||
|
|
@ -985,7 +980,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,
|
||||||
|
|
@ -993,8 +988,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))),
|
||||||
|
|
@ -1014,7 +1009,7 @@ 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){
|
if (_lifeCycle?.messageDidSend != null) {
|
||||||
_lifeCycle!.messageDidSend(sendMsgRes);
|
_lifeCycle!.messageDidSend(sendMsgRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1030,7 +1025,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMessage(V2TimValueCallback<V2TimMessage> sendMsgRes,
|
updateMessage(
|
||||||
|
V2TimValueCallback<V2TimMessage> sendMsgRes,
|
||||||
String convID,
|
String convID,
|
||||||
String id,
|
String id,
|
||||||
ConvType convType,
|
ConvType convType,
|
||||||
|
|
@ -1045,10 +1041,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;
|
||||||
|
|
@ -1059,13 +1055,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)))) {
|
||||||
|
|
@ -1076,12 +1072,11 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateAsyncMessage(V2TimMessage message,
|
void updateAsyncMessage(
|
||||||
String convID,) {
|
V2TimMessage message,
|
||||||
message.id = DateTime
|
String convID,
|
||||||
.now()
|
) {
|
||||||
.millisecondsSinceEpoch
|
message.id = DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
.toString();
|
|
||||||
|
|
||||||
final activeMessageList = _messageListMap[convID];
|
final activeMessageList = _messageListMap[convID];
|
||||||
if (activeMessageList == null || activeMessageList.isEmpty) {
|
if (activeMessageList == null || activeMessageList.isEmpty) {
|
||||||
|
|
@ -1108,11 +1103,11 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
{
|
{
|
||||||
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: '',
|
||||||
|
|
@ -1126,15 +1121,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final returnValue = listWithTimestamp.reversed.toList();
|
final returnValue = listWithTimestamp.reversed.toList();
|
||||||
outputLogger.i(returnValue.map((e) => e.toJson())
|
outputLogger.i(returnValue.map((e) => e.toJson()).toList().toString());
|
||||||
.toList()
|
|
||||||
.toString());
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
@ -1144,8 +1137,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMessageListPosition(String conversationID,
|
void setMessageListPosition(
|
||||||
HistoryMessagePosition position) {
|
String conversationID, HistoryMessagePosition position) {
|
||||||
_historyMessagePositionMap[conversationID] = position;
|
_historyMessagePositionMap[conversationID] = position;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,8 +102,6 @@ class TUIKitOutput extends LogOutput {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
print(msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'dart:io';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:image_clipboard/image_clipboard.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.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/services_locatar.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||||
|
|
@ -83,7 +84,7 @@ class TIMUIKitMessageTooltipState
|
||||||
final TUISelfInfoViewModel selfInfoViewModel =
|
final TUISelfInfoViewModel selfInfoViewModel =
|
||||||
serviceLocator<TUISelfInfoViewModel>();
|
serviceLocator<TUISelfInfoViewModel>();
|
||||||
bool isShowMoreSticker = false;
|
bool isShowMoreSticker = false;
|
||||||
bool isShowOpenFile = false;
|
bool fileBeenDownloaded = false;
|
||||||
String filePath = "";
|
String filePath = "";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -98,11 +99,11 @@ class TIMUIKitMessageTooltipState
|
||||||
(widget.message.fileElem == null &&
|
(widget.message.fileElem == null &&
|
||||||
widget.message.imageElem == null &&
|
widget.message.imageElem == null &&
|
||||||
widget.message.videoElem == null)) {
|
widget.message.videoElem == null)) {
|
||||||
isShowOpenFile = false;
|
fileBeenDownloaded = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
isShowOpenFile = true;
|
fileBeenDownloaded = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (PlatformUtils().isDesktop) {
|
if (PlatformUtils().isDesktop) {
|
||||||
|
|
@ -115,7 +116,7 @@ class TIMUIKitMessageTooltipState
|
||||||
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;
|
||||||
isShowOpenFile = true;
|
fileBeenDownloaded = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (widget.message.imageElem != null) {
|
} else if (widget.message.imageElem != null) {
|
||||||
|
|
@ -124,19 +125,19 @@ class TIMUIKitMessageTooltipState
|
||||||
null &&
|
null &&
|
||||||
File(widget.message.imageElem!.imageList![0]!.localUrl!)
|
File(widget.message.imageElem!.imageList![0]!.localUrl!)
|
||||||
.existsSync()) {
|
.existsSync()) {
|
||||||
isShowOpenFile = true;
|
fileBeenDownloaded = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (widget.message.videoElem != null) {
|
} else if (widget.message.videoElem != null) {
|
||||||
if (TencentUtils.checkString(widget.message.videoElem!.localVideoUrl) !=
|
if (TencentUtils.checkString(widget.message.videoElem!.localVideoUrl) !=
|
||||||
null &&
|
null &&
|
||||||
File(widget.message.videoElem!.localVideoUrl!).existsSync()) {
|
File(widget.message.videoElem!.localVideoUrl!).existsSync()) {
|
||||||
isShowOpenFile = true;
|
fileBeenDownloaded = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isShowOpenFile = false;
|
fileBeenDownloaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isRevocable(int timestamp, int upperTimeLimit) =>
|
bool isRevocable(int timestamp, int upperTimeLimit) =>
|
||||||
|
|
@ -183,7 +184,8 @@ class TIMUIKitMessageTooltipState
|
||||||
|
|
||||||
bool isAdminCanRecall() {
|
bool isAdminCanRecall() {
|
||||||
if (widget.model.chatConfig.isGroupAdminRecallEnabled) {
|
if (widget.model.chatConfig.isGroupAdminRecallEnabled) {
|
||||||
final selfMemberInfo = widget.groupMemberInfo ?? widget.model.selfMemberInfo;
|
final selfMemberInfo =
|
||||||
|
widget.groupMemberInfo ?? widget.model.selfMemberInfo;
|
||||||
final selfRole = selfMemberInfo?.role;
|
final selfRole = selfMemberInfo?.role;
|
||||||
return selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN ||
|
return selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN ||
|
||||||
selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER;
|
selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER;
|
||||||
|
|
@ -205,24 +207,31 @@ class TIMUIKitMessageTooltipState
|
||||||
final shouldShowForwardAction = !(widget.message.customElem?.data != null &&
|
final shouldShowForwardAction = !(widget.message.customElem?.data != null &&
|
||||||
MessageUtils.isCallingData(widget.message.customElem!.data!));
|
MessageUtils.isCallingData(widget.message.customElem!.data!));
|
||||||
final tooltipsConfig = widget.toolTipsConfig;
|
final tooltipsConfig = widget.toolTipsConfig;
|
||||||
|
final messageCanCopy = widget.message.elemType ==
|
||||||
|
MessageElemType.V2TIM_ELEM_TYPE_TEXT ||
|
||||||
|
(isDesktopScreen &&
|
||||||
|
widget.message.elemType == MessageElemType.V2TIM_ELEM_TYPE_IMAGE &&
|
||||||
|
fileBeenDownloaded);
|
||||||
|
|
||||||
final List<MessageToolTipItem> defaultTipsList = [
|
final List<MessageToolTipItem> defaultTipsList = [
|
||||||
if (isShowOpenFile)
|
if (fileBeenDownloaded)
|
||||||
MessageToolTipItem(
|
MessageToolTipItem(
|
||||||
label: TIM_t("打开"),
|
label: TIM_t("打开"),
|
||||||
id: "open",
|
id: "open",
|
||||||
iconImageAsset: "images/open_in_new.png",
|
iconImageAsset: "images/open_in_new.png",
|
||||||
onClick: () => _onTap("open", model)),
|
onClick: () => _onTap("open", model)),
|
||||||
if (isShowOpenFile && PlatformUtils().isDesktop)
|
if (fileBeenDownloaded && PlatformUtils().isDesktop)
|
||||||
MessageToolTipItem(
|
MessageToolTipItem(
|
||||||
label: PlatformUtils().isMacOS ? TIM_t("在访达中打开") : TIM_t("查看文件夹"),
|
label: PlatformUtils().isMacOS ? TIM_t("在访达中打开") : TIM_t("查看文件夹"),
|
||||||
id: "finder",
|
id: "finder",
|
||||||
iconImageAsset: "images/folder_open.png",
|
iconImageAsset: "images/folder_open.png",
|
||||||
onClick: () => _onTap("finder", model)),
|
onClick: () => _onTap("finder", model)),
|
||||||
MessageToolTipItem(
|
if (messageCanCopy)
|
||||||
label: TIM_t("复制"),
|
MessageToolTipItem(
|
||||||
id: "copyMessage",
|
label: TIM_t("复制"),
|
||||||
iconImageAsset: "images/copy_message.png",
|
id: "copyMessage",
|
||||||
onClick: () => _onTap("copyMessage", model)),
|
iconImageAsset: "images/copy_message.png",
|
||||||
|
onClick: () => _onTap("copyMessage", model)),
|
||||||
if (shouldShowForwardAction && !isVoteMessage(widget.message))
|
if (shouldShowForwardAction && !isVoteMessage(widget.message))
|
||||||
MessageToolTipItem(
|
MessageToolTipItem(
|
||||||
label: TIM_t("转发"),
|
label: TIM_t("转发"),
|
||||||
|
|
@ -263,8 +272,7 @@ class TIMUIKitMessageTooltipState
|
||||||
defaultFormattedTipsList = defaultTipsList.where((element) {
|
defaultFormattedTipsList = defaultTipsList.where((element) {
|
||||||
final type = element.id;
|
final type = element.id;
|
||||||
if (type == "copyMessage") {
|
if (type == "copyMessage") {
|
||||||
return tooltipsConfig.showCopyMessage &&
|
return tooltipsConfig.showCopyMessage;
|
||||||
widget.message.elemType == MessageElemType.V2TIM_ELEM_TYPE_TEXT;
|
|
||||||
}
|
}
|
||||||
if (type == "forwardMessage") {
|
if (type == "forwardMessage") {
|
||||||
return tooltipsConfig.showForwardMessage &&
|
return tooltipsConfig.showForwardMessage &&
|
||||||
|
|
@ -402,6 +410,12 @@ class TIMUIKitMessageTooltipState
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> copyImageToClipboard(String imagePath) async {
|
||||||
|
ImageClipboard().copyImage(imagePath);
|
||||||
|
// final DesktopClipboard desktopClipboard = DesktopClipboard();
|
||||||
|
// desktopClipboard.copyImage(imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
_onTap(String operation, TUIChatSeparateViewModel model) async {
|
_onTap(String operation, TUIChatSeparateViewModel model) async {
|
||||||
final messageItem = widget.message;
|
final messageItem = widget.message;
|
||||||
final msgID = messageItem.msgID as String;
|
final msgID = messageItem.msgID as String;
|
||||||
|
|
@ -485,6 +499,13 @@ class TIMUIKitMessageTooltipState
|
||||||
infoCode: 6660408));
|
infoCode: 6660408));
|
||||||
// ignore: empty_catches
|
// ignore: empty_catches
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
} else if (widget.message.elemType ==
|
||||||
|
MessageElemType.V2TIM_ELEM_TYPE_IMAGE) {
|
||||||
|
final savePath = (TencentUtils.checkString(
|
||||||
|
widget.message.imageElem!.imageList?[0]?.localUrl) ??
|
||||||
|
TencentUtils.checkString(widget.message.imageElem?.path) ??
|
||||||
|
"");
|
||||||
|
copyImageToClipboard(savePath);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "replyMessage":
|
case "replyMessage":
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
Future<void> _saveImageToLocal(
|
Future<void> _saveImageToLocal(
|
||||||
context,
|
context,
|
||||||
String imageUrl, {
|
String imageUrl, {
|
||||||
bool isAsset = true,
|
bool isLocalResource = true,
|
||||||
TUITheme? theme,
|
TUITheme? theme,
|
||||||
}) async {
|
}) async {
|
||||||
if (PlatformUtils().isWeb) {
|
if (PlatformUtils().isWeb) {
|
||||||
|
|
@ -163,8 +163,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 本地资源的情况下
|
if (!isLocalResource) {
|
||||||
if (!isAsset) {
|
|
||||||
if (widget.message.msgID == null || widget.message.msgID!.isEmpty) {
|
if (widget.message.msgID == null || widget.message.msgID!.isEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -216,9 +215,6 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// model.setMessageProgress(widget.message.msgID!, 0);
|
|
||||||
// var result =
|
|
||||||
// await ImageGallerySaver.saveImage(Uint8List.fromList(response));
|
|
||||||
|
|
||||||
var result = await ImageGallerySaver.saveFile(imageUrl);
|
var result = await ImageGallerySaver.saveFile(imageUrl);
|
||||||
|
|
||||||
|
|
@ -251,44 +247,44 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _saveImg(TUITheme theme) async {
|
Future<void> _saveImg(TUITheme theme) async {
|
||||||
String? path = widget.message.imageElem!.path;
|
try {
|
||||||
if (path != null && PlatformUtils().isWeb
|
String? imageUrl;
|
||||||
? true
|
bool isAssetBool = false;
|
||||||
: File(path!).existsSync()) {
|
final imageElem = widget.message.imageElem;
|
||||||
return await _saveImageToLocal(context, path,
|
|
||||||
isAsset: true, theme: theme);
|
if (imageElem != null) {
|
||||||
} else {
|
final originUrl = getOriginImgURL();
|
||||||
String imgUrl = getOriginImgURL();
|
final localUrl = imageElem.imageList?.firstOrNull?.localUrl;
|
||||||
if (widget.message.imageElem!.imageList![0]!.localUrl != '' &&
|
final filePath = imageElem.path;
|
||||||
widget.message.imageElem!.imageList![0]!.localUrl != null) {
|
final isWeb = PlatformUtils().isWeb;
|
||||||
File f = File(widget.message.imageElem!.imageList![0]!.localUrl!);
|
|
||||||
if (f.existsSync()) {
|
if (!isWeb && filePath != null && File(filePath).existsSync()) {
|
||||||
return await _saveImageToLocal(
|
imageUrl = filePath;
|
||||||
context,
|
isAssetBool = true;
|
||||||
widget.message.imageElem!.imageList![0]!.localUrl!,
|
} else if (localUrl != null &&
|
||||||
isAsset: true,
|
(!isWeb && File(localUrl).existsSync())) {
|
||||||
theme: theme,
|
imageUrl = localUrl;
|
||||||
);
|
isAssetBool = true;
|
||||||
|
} else {
|
||||||
|
imageUrl = originUrl;
|
||||||
|
isAssetBool = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (widget.message.imageElem!.path != '' &&
|
|
||||||
widget.message.imageElem!.path != null) {
|
if (imageUrl != null) {
|
||||||
File f = File(widget.message.imageElem!.path!);
|
return await _saveImageToLocal(
|
||||||
if (f.existsSync()) {
|
context,
|
||||||
return await _saveImageToLocal(
|
imageUrl,
|
||||||
context,
|
isLocalResource: isAssetBool,
|
||||||
widget.message.imageElem!.path!,
|
theme: theme,
|
||||||
isAsset: true,
|
);
|
||||||
theme: theme,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return await _saveImageToLocal(
|
} catch (e) {
|
||||||
context,
|
onTIMCallback(TIMCallback(
|
||||||
imgUrl,
|
infoCode: 6660414,
|
||||||
isAsset: false,
|
infoRecommendText: TIM_t("正在下载中"),
|
||||||
theme: theme,
|
type: TIMCallbackType.INFO));
|
||||||
);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -398,7 +394,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
void onClickImage({
|
void onClickImage({
|
||||||
required bool isNetworkImage,
|
required bool isNetworkImage,
|
||||||
dynamic heroTag,
|
dynamic heroTag,
|
||||||
TUITheme? theme,
|
required TUITheme theme,
|
||||||
String? imgUrl,
|
String? imgUrl,
|
||||||
String? imgPath,
|
String? imgPath,
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -429,7 +425,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
messageID: widget.message.msgID,
|
messageID: widget.message.msgID,
|
||||||
downloadFn: () async {
|
downloadFn: () async {
|
||||||
return await _saveImg(theme!);
|
return await _saveImg(theme);
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -448,7 +444,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
messageID: widget.message.msgID,
|
messageID: widget.message.msgID,
|
||||||
downloadFn: () async {
|
downloadFn: () async {
|
||||||
return await _saveImg(theme!);
|
return await _saveImg(theme);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -458,7 +454,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
|
|
||||||
Widget _renderAllImage(
|
Widget _renderAllImage(
|
||||||
{dynamic heroTag,
|
{dynamic heroTag,
|
||||||
TUITheme? theme,
|
required TUITheme theme,
|
||||||
bool isNetworkImage = false,
|
bool isNetworkImage = false,
|
||||||
String? webPath,
|
String? webPath,
|
||||||
V2TimImage? originalImg,
|
V2TimImage? originalImg,
|
||||||
|
|
@ -485,7 +481,6 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
final imgPath = (TencentUtils.checkString(smallLocalPath) != null
|
final imgPath = (TencentUtils.checkString(smallLocalPath) != null
|
||||||
|
|
||||||
? smallLocalPath
|
? smallLocalPath
|
||||||
: originLocalPath)!;
|
: originLocalPath)!;
|
||||||
return Hero(
|
return Hero(
|
||||||
|
|
@ -504,24 +499,34 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => onClickImage(
|
onTap: () => onClickImage(
|
||||||
|
theme: theme,
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
isNetworkImage: isNetworkImage,
|
isNetworkImage: isNetworkImage,
|
||||||
imgUrl: webPath ?? smallImg?.url ?? originalImg?.url ?? "",
|
imgUrl: webPath ?? smallImg?.url ?? originalImg?.url ?? "",
|
||||||
imgPath: (TencentUtils.checkString(originLocalPath) != null
|
imgPath: (TencentUtils.checkString(originLocalPath) != null
|
||||||
? originLocalPath
|
? originLocalPath
|
||||||
: smallLocalPath) ?? ""
|
: smallLocalPath) ??
|
||||||
),
|
""),
|
||||||
child: getImageWidget(),
|
child: getImageWidget(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
void initImages() async {
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
if (!PlatformUtils().isWeb &&
|
if (!PlatformUtils().isWeb &&
|
||||||
TencentUtils.checkString(widget.message.msgID) != null) {
|
TencentUtils.checkString(widget.message.msgID) != null) {
|
||||||
if (TencentUtils.checkString(
|
if (widget.message.imageElem?.imageList == null ||
|
||||||
widget.message.imageElem!.imageList![0]!.localUrl) ==
|
widget.message.imageElem!.imageList!.isEmpty) {
|
||||||
|
final response = await _messageService.getMessageOnlineUrl(
|
||||||
|
msgID: widget.message.msgID!);
|
||||||
|
final elem = response.data;
|
||||||
|
if (elem != null && elem.imageElem != null) {
|
||||||
|
widget.message.imageElem = elem.imageElem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (widget.message.imageElem?.imageList == null ||
|
||||||
|
widget.message.imageElem!.imageList!.isEmpty ||
|
||||||
|
TencentUtils.checkString(
|
||||||
|
widget.message.imageElem?.imageList?[0]?.localUrl) ==
|
||||||
null ||
|
null ||
|
||||||
!File(widget.message.imageElem!.imageList![0]!.localUrl!)
|
!File(widget.message.imageElem!.imageList![0]!.localUrl!)
|
||||||
.existsSync()) {
|
.existsSync()) {
|
||||||
|
|
@ -531,9 +536,11 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
imageType: 0,
|
imageType: 0,
|
||||||
isSnapshot: false);
|
isSnapshot: false);
|
||||||
}
|
}
|
||||||
if (TencentUtils.checkString(
|
if (widget.message.imageElem?.imageList == null ||
|
||||||
widget.message.imageElem!.imageList![1]!.localUrl) ==
|
widget.message.imageElem!.imageList!.length < 2 &&
|
||||||
null ||
|
TencentUtils.checkString(
|
||||||
|
widget.message.imageElem?.imageList?[1]?.localUrl) ==
|
||||||
|
null ||
|
||||||
!File(widget.message.imageElem!.imageList![1]!.localUrl!)
|
!File(widget.message.imageElem!.imageList![1]!.localUrl!)
|
||||||
.existsSync()) {
|
.existsSync()) {
|
||||||
_messageService.downloadMessage(
|
_messageService.downloadMessage(
|
||||||
|
|
@ -542,8 +549,10 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
imageType: 1,
|
imageType: 1,
|
||||||
isSnapshot: false);
|
isSnapshot: false);
|
||||||
}
|
}
|
||||||
if (TencentUtils.checkString(
|
if (widget.message.imageElem?.imageList != null ||
|
||||||
widget.message.imageElem!.imageList![2]!.localUrl) ==
|
widget.message.imageElem!.imageList!.length < 3 ||
|
||||||
|
TencentUtils.checkString(
|
||||||
|
widget.message.imageElem?.imageList?[2]?.localUrl) ==
|
||||||
null ||
|
null ||
|
||||||
!File(widget.message.imageElem!.imageList![2]!.localUrl!)
|
!File(widget.message.imageElem!.imageList![2]!.localUrl!)
|
||||||
.existsSync()) {
|
.existsSync()) {
|
||||||
|
|
@ -556,6 +565,12 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
initImages();
|
||||||
|
}
|
||||||
|
|
||||||
bool isNeedShowLocalPath() {
|
bool isNeedShowLocalPath() {
|
||||||
final current = (DateTime.now().millisecondsSinceEpoch / 1000).ceil();
|
final current = (DateTime.now().millisecondsSinceEpoch / 1000).ceil();
|
||||||
final timeStamp = widget.message.timestamp ?? current;
|
final timeStamp = widget.message.timestamp ?? current;
|
||||||
|
|
@ -563,7 +578,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
||||||
(isSent || current - timeStamp < 300);
|
(isSent || current - timeStamp < 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? _renderImage(dynamic heroTag, TUITheme? theme,
|
Widget? _renderImage(dynamic heroTag, TUITheme theme,
|
||||||
{V2TimImage? originalImg, V2TimImage? smallImg}) {
|
{V2TimImage? originalImg, V2TimImage? smallImg}) {
|
||||||
double? positionRadio;
|
double? positionRadio;
|
||||||
if (smallImg?.width != null &&
|
if (smallImg?.width != null &&
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -296,6 +296,9 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
|
||||||
if (oldWidget.textFieldBuilder != null && widget.textFieldBuilder == null) {
|
if (oldWidget.textFieldBuilder != null && widget.textFieldBuilder == null) {
|
||||||
textFieldController = TIMUIKitInputTextFieldController();
|
textFieldController = TIMUIKitInputTextFieldController();
|
||||||
}
|
}
|
||||||
|
if (oldWidget.groupMemberList != widget.groupMemberList) {
|
||||||
|
model.groupMemberList = widget.groupMemberList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDraft() async {
|
updateDraft() async {
|
||||||
|
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.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/base_widgets/tim_ui_kit_base.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
|
||||||
|
|
||||||
class CenterLoading extends TIMUIKitStatelessWidget {
|
|
||||||
CenterLoading({Key? key, this.messageID}) : super(key: key);
|
|
||||||
final String? messageID;
|
|
||||||
@override
|
|
||||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
|
||||||
final TUITheme theme = value.theme;
|
|
||||||
|
|
||||||
return MultiProvider(
|
|
||||||
providers: [
|
|
||||||
ChangeNotifierProvider.value(
|
|
||||||
value: serviceLocator<TUIChatGlobalModel>()),
|
|
||||||
],
|
|
||||||
builder: (context, w) {
|
|
||||||
final progress = Provider.of<TUIChatGlobalModel>(context)
|
|
||||||
.getMessageProgress(messageID);
|
|
||||||
return (progress == 0 || progress == 100)
|
|
||||||
? Container()
|
|
||||||
: Center(
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
value: progress / 100,
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
valueColor: AlwaysStoppedAnimation(theme.primaryColor)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:loading_animation_widget/loading_animation_widget.dart';
|
import 'package:loading_animation_widget/loading_animation_widget.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
|
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/center_loading.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/gestured_image.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/gestured_image.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';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/image_hero.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/image_hero.dart';
|
||||||
|
|
@ -152,7 +151,8 @@ class _ImageScreenState extends TIMUIKitState<ImageScreen>
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
color: Colors.white)));
|
color: Colors.white))
|
||||||
|
);
|
||||||
case LoadState.completed:
|
case LoadState.completed:
|
||||||
final screenHeight =
|
final screenHeight =
|
||||||
MediaQuery.of(context).size.height;
|
MediaQuery.of(context).size.height;
|
||||||
|
|
@ -266,7 +266,6 @@ class _ImageScreenState extends TIMUIKitState<ImageScreen>
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CenterLoading(messageID: widget.messageID),
|
|
||||||
if (isLoading)
|
if (isLoading)
|
||||||
Container(
|
Container(
|
||||||
child: LoadingAnimationWidget.staggeredDotsWave(
|
child: LoadingAnimationWidget.staggeredDotsWave(
|
||||||
|
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
|
|
||||||
/// Type for a function that creates image widgets.
|
|
||||||
typedef ImageBuilder = Widget Function(
|
|
||||||
Uri uri, String? imageDirectory, double? width, double? height);
|
|
||||||
|
|
||||||
Widget _handleDataSchemeUri(
|
|
||||||
Uri uri, final double? width, final double? height) {
|
|
||||||
final String mimeType = uri.data!.mimeType;
|
|
||||||
if (mimeType.startsWith('image/')) {
|
|
||||||
return Image.memory(
|
|
||||||
uri.data!.contentAsBytes(),
|
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
);
|
|
||||||
} else if (mimeType.startsWith('text/')) {
|
|
||||||
return Text(uri.data!.contentAsString());
|
|
||||||
}
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
class MDImageRenderer extends StatelessWidget{
|
|
||||||
final String src;
|
|
||||||
final String? title;
|
|
||||||
final String? alt;
|
|
||||||
MDImageRenderer({super.key, required this.src, this.title, this.alt});
|
|
||||||
|
|
||||||
/// A default image builder handling http/https, resource, and file URLs.
|
|
||||||
// ignore: prefer_function_declarations_over_variables
|
|
||||||
final ImageBuilder kDefaultImageBuilder = (
|
|
||||||
Uri uri,
|
|
||||||
String? imageDirectory,
|
|
||||||
double? width,
|
|
||||||
double? height,
|
|
||||||
) {
|
|
||||||
if (uri.scheme == 'http' || uri.scheme == 'https') {
|
|
||||||
return Image.network(uri.toString(), width: width, height: height);
|
|
||||||
} else if (uri.scheme == 'data') {
|
|
||||||
return _handleDataSchemeUri(uri, width, height);
|
|
||||||
} else if (uri.scheme == 'resource') {
|
|
||||||
return Image.asset(uri.path, width: width, height: height);
|
|
||||||
} else {
|
|
||||||
final Uri fileUri = imageDirectory != null
|
|
||||||
? Uri.parse(imageDirectory + uri.toString())
|
|
||||||
: uri;
|
|
||||||
if (fileUri.scheme == 'http' || fileUri.scheme == 'https') {
|
|
||||||
return Image.network(fileUri.toString(), width: width, height: height);
|
|
||||||
} else {
|
|
||||||
return Image.file(File.fromUri(fileUri), width: width, height: height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Widget _buildImage(String src, String? title, String? alt) {
|
|
||||||
final List<String> parts = src.split('#');
|
|
||||||
if (parts.isEmpty) {
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String path = parts.first;
|
|
||||||
double? width;
|
|
||||||
double? height;
|
|
||||||
if (parts.length == 2) {
|
|
||||||
final List<String> dimensions = parts.last.split('x');
|
|
||||||
if (dimensions.length == 2) {
|
|
||||||
width = double.parse(dimensions[0]);
|
|
||||||
height = double.parse(dimensions[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Uri uri = Uri.parse(path);
|
|
||||||
Widget child;
|
|
||||||
if (false) {
|
|
||||||
// child = imageBuilder!(uri, title, alt);
|
|
||||||
} else {
|
|
||||||
child = kDefaultImageBuilder(uri, "", width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GestureDetector(onTap:(){
|
|
||||||
|
|
||||||
}, child: child);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
throw _buildImage(src, title, alt);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -5,9 +5,7 @@ import 'package:extended_text/extended_text.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/emoji_text.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/link_preview/compiler/md_text.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/link_preview/compiler/md_text.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/link_preview/renderer/md_image.dart';
|
|
||||||
import 'package:tencent_im_base/base_widgets/tim_stateless_widget.dart';
|
import 'package:tencent_im_base/base_widgets/tim_stateless_widget.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/DefaultSpecialTextSpanBuilder.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/link_preview/common/utils.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/link_preview/common/utils.dart';
|
||||||
|
|
|
||||||
|
|
@ -683,6 +683,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
image_clipboard:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: image_clipboard
|
||||||
|
sha256: "1939365dc3b65acd3b1199176a330180075f4e803a6512f5622d050b62e7eff4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0+2"
|
||||||
image_gallery_saver:
|
image_gallery_saver:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
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.2.0
|
version: 2.2.1
|
||||||
homepage: https://www.tencentcloud.com/products/im?from=pub
|
homepage: https://trtc.io/products/chat?utm_source=gfs&utm_medium=link&utm_campaign=%E6%B8%A0%E9%81%93&_channel_track_key=k6WgfCKn
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -76,6 +76,7 @@ dependencies:
|
||||||
diff_match_patch: ^0.4.1
|
diff_match_patch: ^0.4.1
|
||||||
markdown: ^7.1.0
|
markdown: ^7.1.0
|
||||||
logger: ^2.0.1
|
logger: ^2.0.1
|
||||||
|
image_clipboard: ^1.0.0+2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_lints: ^1.0.0
|
flutter_lints: ^1.0.0
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue