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
|
||||
|
||||
### New Features
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <audioplayers_linux/audioplayers_linux_plugin.h>
|
||||
#include <desktop_drop/desktop_drop_plugin.h>
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <image_clipboard/image_clipboard_plugin.h>
|
||||
#include <pasteboard/pasteboard_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 =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
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 =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
|
||||
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
audioplayers_linux
|
||||
desktop_drop
|
||||
file_selector_linux
|
||||
image_clipboard
|
||||
pasteboard
|
||||
url_launcher_linux
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import desktop_drop
|
|||
import device_info_plus
|
||||
import fc_native_video_thumbnail
|
||||
import file_selector_macos
|
||||
import image_clipboard
|
||||
import package_info_plus
|
||||
import pasteboard
|
||||
import path_provider_foundation
|
||||
|
|
@ -24,6 +25,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FcNativeVideoThumbnailPlugin.register(with: registry.registrar(forPlugin: "FcNativeVideoThumbnailPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
ImageClipboardPlugin.register(with: registry.registrar(forPlugin: "ImageClipboardPlugin"))
|
||||
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
|
||||
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
|
|
|
|||
|
|
@ -608,6 +608,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1219,7 +1227,7 @@ packages:
|
|||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "2.2.0"
|
||||
version: "2.2.1-preview.0"
|
||||
tencent_cloud_uikit_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <desktop_drop/desktop_drop_plugin.h>
|
||||
#include <fc_native_video_thumbnail/fc_native_video_thumbnail_plugin_c_api.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <image_clipboard/image_clipboard_plugin_c_api.h>
|
||||
#include <pasteboard/pasteboard_plugin.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
|
@ -23,6 +24,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||
registry->GetRegistrarForPlugin("FcNativeVideoThumbnailPluginCApi"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
ImageClipboardPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ImageClipboardPluginCApi"));
|
||||
PasteboardPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PasteboardPlugin"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
desktop_drop
|
||||
fc_native_video_thumbnail
|
||||
file_selector_windows
|
||||
image_clipboard
|
||||
pasteboard
|
||||
permission_handler_windows
|
||||
url_launcher_windows
|
||||
|
|
|
|||
|
|
@ -31,9 +31,8 @@ class ChatLifeCycle {
|
|||
/// You can make a second confirmation here by a modal, etc.
|
||||
FutureBool Function(String conversationID) shouldClearHistoricalMessageList;
|
||||
|
||||
|
||||
/// Before rendering a message to message list.
|
||||
bool Function(V2TimMessage msgID) messageShouldMount;
|
||||
bool Function(V2TimMessage msg) messageShouldMount;
|
||||
|
||||
ChatLifeCycle({
|
||||
this.shouldClearHistoricalMessageList =
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
|
|||
_groupType = null;
|
||||
isGroupExist = true;
|
||||
_groupInfo = null;
|
||||
groupMemberList?.clear();
|
||||
groupMemberList = null;
|
||||
selfMemberInfo = null;
|
||||
|
||||
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/utils/message.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 }
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
ChatLifeCycle? _lifeCycle;
|
||||
bool _isDownloading = false;
|
||||
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;
|
||||
String localKeyPrefix = "TUIKit_conversation_stored_";
|
||||
String localMsgIDListKey = "TUIKit_conversation_list";
|
||||
|
|
@ -63,7 +64,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
List<V2TimGroupApplication>? _groupApplicationList;
|
||||
String Function(V2TimMessage message)? _abstractMessageBuilder;
|
||||
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, Timer> _c2cMessageActiveTimer = Map.from({});
|
||||
bool _showC2cMessageEditStatus = true;
|
||||
|
|
@ -196,17 +197,15 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
Map<String, V2TimMessageReceipt> get messageReadReceiptMap =>
|
||||
_messageReadReceiptMap;
|
||||
|
||||
String get currentSelectedConv =>
|
||||
_currentConversationList.isNotEmpty
|
||||
? _currentConversationList[_currentConversationList.length - 1]
|
||||
String get currentSelectedConv => _currentConversationList.isNotEmpty
|
||||
? _currentConversationList[_currentConversationList.length - 1]
|
||||
.conversationID
|
||||
: "";
|
||||
: "";
|
||||
|
||||
ConvType? get currentSelectedConvType =>
|
||||
_currentConversationList.isNotEmpty
|
||||
? _currentConversationList[_currentConversationList.length - 1]
|
||||
ConvType? get currentSelectedConvType => _currentConversationList.isNotEmpty
|
||||
? _currentConversationList[_currentConversationList.length - 1]
|
||||
.conversationType
|
||||
: null;
|
||||
: null;
|
||||
|
||||
setCurrentConversation(CurrentConversation value) {
|
||||
_currentConversationList.add(value);
|
||||
|
|
@ -242,13 +241,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
}
|
||||
_c2cMessageStatusShowTimer[userID] =
|
||||
Timer.periodic(const Duration(seconds: 5), (timer) {
|
||||
_c2cMessageEditStatusMap[userID] = 0;
|
||||
Timer? t = _c2cMessageStatusShowTimer[userID];
|
||||
if (t != null && t.isActive) {
|
||||
// 取消当前的定时器
|
||||
t.cancel();
|
||||
}
|
||||
});
|
||||
_c2cMessageEditStatusMap[userID] = 0;
|
||||
Timer? t = _c2cMessageStatusShowTimer[userID];
|
||||
if (t != null && t.isActive) {
|
||||
// 取消当前的定时器
|
||||
t.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
|
@ -333,9 +332,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
prefs.remove(localMsgIDListKey);
|
||||
}
|
||||
|
||||
Future<void> updateMessageFromController({required String msgID,
|
||||
required String conversationID,
|
||||
required ConvType conversationType}) async {
|
||||
Future<void> updateMessageFromController(
|
||||
{required String msgID,
|
||||
required String conversationID,
|
||||
required ConvType conversationType}) async {
|
||||
final TUIChatModelTools tools = serviceLocator<TUIChatModelTools>();
|
||||
V2TimMessage? newMessage = await tools.getExistingMessageByID(
|
||||
msgID: msgID,
|
||||
|
|
@ -364,7 +364,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
|
||||
_preLoadImage(List<V2TimMessage> msgList) {
|
||||
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) {
|
||||
V2TimImage? getImageFromList(V2TimImageTypesEnum imgType) {
|
||||
V2TimImage? img = MessageUtils.getImageFromImgList(
|
||||
|
|
@ -382,12 +382,12 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
|
||||
image.resolve(configuration).addListener(
|
||||
ImageStreamListener((ImageInfo image, bool synchronousCall) {
|
||||
final tempImg = image.image;
|
||||
_preloadImageMap[msgItem.seq! +
|
||||
msgItem.timestamp.toString() +
|
||||
(msgItem.msgID ?? "")] = tempImg;
|
||||
outputLogger.i("cacheImage ${msgItem.msgID}");
|
||||
}));
|
||||
final tempImg = image.image;
|
||||
_preloadImageMap[msgItem.seq! +
|
||||
msgItem.timestamp.toString() +
|
||||
(msgItem.msgID ?? "")] = tempImg;
|
||||
outputLogger.i("cacheImage ${msgItem.msgID}");
|
||||
}));
|
||||
} catch (e) {
|
||||
outputLogger.i("cacheImage error ${msgItem.msgID}");
|
||||
}
|
||||
|
|
@ -488,13 +488,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
}
|
||||
_c2cMessageActiveTimer[msg.sender ?? ""] =
|
||||
Timer.periodic(const Duration(seconds: 30), (timer) {
|
||||
_c2cMessageFromUserActiveMap[msg.sender ?? ""] = false;
|
||||
Timer? t = _c2cMessageActiveTimer[msg.sender ?? ""];
|
||||
if (t != null && t.isActive) {
|
||||
// 取消当前的定时器
|
||||
t.cancel();
|
||||
}
|
||||
});
|
||||
_c2cMessageFromUserActiveMap[msg.sender ?? ""] = false;
|
||||
Timer? t = _c2cMessageActiveTimer[msg.sender ?? ""];
|
||||
if (t != null && t.isActive) {
|
||||
// 取消当前的定时器
|
||||
t.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
@ -512,14 +512,14 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
}
|
||||
V2TimMsgCreateInfoResult? res = await _messageService.createCustomMessage(
|
||||
data: json.encode({
|
||||
"businessID": "user_typing_status",
|
||||
"typingStatus": isEditing == true ? 1 : 0,
|
||||
"userAction": 14,
|
||||
"version": 0,
|
||||
"actionParam": isEditing == true
|
||||
? "EIMAMSG_InputStatus_Ing"
|
||||
: "EIMAMSG_InputStatus_End"
|
||||
}));
|
||||
"businessID": "user_typing_status",
|
||||
"typingStatus": isEditing == true ? 1 : 0,
|
||||
"userAction": 14,
|
||||
"version": 0,
|
||||
"actionParam": isEditing == true
|
||||
? "EIMAMSG_InputStatus_Ing"
|
||||
: "EIMAMSG_InputStatus_End"
|
||||
}));
|
||||
if (res != null) {
|
||||
_sendMessage(
|
||||
id: res.id!,
|
||||
|
|
@ -534,9 +534,9 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
void refreshGroupApplicationList() async {
|
||||
final res = await _groupServices.getGroupApplicationList();
|
||||
_groupApplicationList = res.data?.groupApplicationList?.map((item) {
|
||||
final V2TimGroupApplication applicationItem = item!;
|
||||
return applicationItem;
|
||||
}).toList() ??
|
||||
final V2TimGroupApplication applicationItem = item!;
|
||||
return applicationItem;
|
||||
}).toList() ??
|
||||
[];
|
||||
notifyListeners();
|
||||
}
|
||||
|
|
@ -632,17 +632,14 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
final activeMessageList = _messageListMap[convID ?? currentSelectedConv];
|
||||
if (activeMessageList != null) {
|
||||
final findeIndex =
|
||||
activeMessageList.indexWhere((element) => element.msgID == msgID);
|
||||
activeMessageList.indexWhere((element) => element.msgID == msgID);
|
||||
if (findeIndex != -1) {
|
||||
final findeIndex =
|
||||
activeMessageList.indexWhere((element) => element.msgID == msgID);
|
||||
activeMessageList.indexWhere((element) => element.msgID == msgID);
|
||||
if (findeIndex != -1) {
|
||||
final targetItem = activeMessageList[findeIndex];
|
||||
targetItem.status = MessageStatus.V2TIM_MSG_STATUS_LOCAL_REVOKED;
|
||||
targetItem.id = DateTime
|
||||
.now()
|
||||
.millisecondsSinceEpoch
|
||||
.toString();
|
||||
targetItem.id = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
activeMessageList[findeIndex] = targetItem;
|
||||
}
|
||||
}
|
||||
|
|
@ -652,10 +649,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
}
|
||||
|
||||
onMessageModified(V2TimMessage modifiedMessage, [String? convID]) async {
|
||||
modifiedMessage.id = DateTime
|
||||
.now()
|
||||
.millisecondsSinceEpoch
|
||||
.toString();
|
||||
modifiedMessage.id = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
final String? exactId = TencentUtils.checkString(modifiedMessage.userID) ??
|
||||
TencentUtils.checkString(modifiedMessage.groupID);
|
||||
final activeMessageList = _messageListMap[convID ?? exactId];
|
||||
|
|
@ -716,8 +710,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
final currentProgress = getMessageProgress(messageProgress.msgID);
|
||||
|
||||
if (messageProgress.isFinish && currentProgress < 100) {
|
||||
V2TimMessage? message = await _findAndRetrieveMessage(
|
||||
messageProgress.msgID);
|
||||
V2TimMessage? message =
|
||||
await _findAndRetrieveMessage(messageProgress.msgID);
|
||||
_handleFinishedDownload(messageProgress, message);
|
||||
return;
|
||||
}
|
||||
|
|
@ -726,23 +720,25 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
}
|
||||
|
||||
Future<V2TimMessage?> _findAndRetrieveMessage(String messageId) async {
|
||||
final messages = await _messageService.findMessages(
|
||||
messageIDList: [messageId]);
|
||||
final messages =
|
||||
await _messageService.findMessages(messageIDList: [messageId]);
|
||||
return messages?.first;
|
||||
}
|
||||
|
||||
void _handleFinishedDownload(V2TimMessageDownloadProgress messageProgress,
|
||||
V2TimMessage? message) {
|
||||
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;
|
||||
bool isImageType =
|
||||
message.elemType == MessageElemType.V2TIM_ELEM_TYPE_IMAGE;
|
||||
bool isVideoType =
|
||||
message.elemType == MessageElemType.V2TIM_ELEM_TYPE_VIDEO;
|
||||
final originalImageType = PlatformUtils().isIOS ? 1 : 0;
|
||||
if (!isImageType && !isVideoType) {
|
||||
_updateMessageLocationAndDownloadFile(messageProgress);
|
||||
} else if ((isImageType && messageProgress.type == 0) || isVideoType) {
|
||||
Future.delayed(const Duration(seconds: 1), () =>
|
||||
_updateMessageAndDownloadFile(message, messageProgress));
|
||||
} else if ((isImageType && messageProgress.type == originalImageType) ||
|
||||
isVideoType) {
|
||||
Future.delayed(const Duration(seconds: 1),
|
||||
() => _updateMessageAndDownloadFile(message, messageProgress));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
|
@ -751,8 +747,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
}
|
||||
}
|
||||
|
||||
void _updateMessageAndDownloadFile(V2TimMessage message,
|
||||
V2TimMessageDownloadProgress messageProgress) {
|
||||
void _updateMessageAndDownloadFile(
|
||||
V2TimMessage message, V2TimMessageDownloadProgress messageProgress) {
|
||||
updateAsyncMessage(
|
||||
message,
|
||||
TencentUtils.checkString(message.userID) ??
|
||||
|
|
@ -769,18 +765,19 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
downloadFile();
|
||||
}
|
||||
|
||||
void _updateProgressIfNeeded(V2TimMessageDownloadProgress messageProgress,
|
||||
int currentProgress) {
|
||||
try{
|
||||
void _updateProgressIfNeeded(
|
||||
V2TimMessageDownloadProgress messageProgress, int currentProgress) {
|
||||
try {
|
||||
if (messageProgress.totalSize != -1 && !messageProgress.isFinish) {
|
||||
int progress = min(99,
|
||||
int progress = min(
|
||||
99,
|
||||
(messageProgress.currentSize / messageProgress.totalSize * 100)
|
||||
.floor());
|
||||
if (progress > 1 && progress > currentProgress) {
|
||||
setMessageProgress(messageProgress.msgID, progress);
|
||||
}
|
||||
}
|
||||
}catch(e){
|
||||
} catch (e) {
|
||||
outputLogger.i("calculate error: ${messageProgress.toJson()}");
|
||||
}
|
||||
}
|
||||
|
|
@ -868,13 +865,11 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
final TUIChatModelTools tools = serviceLocator<TUIChatModelTools>();
|
||||
List<V2TimMessage> currentHistoryMsgList = _messageListMap[convID] ?? [];
|
||||
V2TimMsgCreateInfoResult? textMessageInfo =
|
||||
await _messageService.createTextMessage(text: text);
|
||||
await _messageService.createTextMessage(text: text);
|
||||
|
||||
textMessageInfo = await _messageService.createTextAtMessage(
|
||||
text: text +
|
||||
"\n@${TencentUtils.checkString(messageBeenReplied.nickName) ??
|
||||
TencentUtils.checkString(messageBeenReplied.sender) ??
|
||||
TencentUtils.checkString(messageBeenReplied.userID)}",
|
||||
"\n@${TencentUtils.checkString(messageBeenReplied.nickName) ?? TencentUtils.checkString(messageBeenReplied.sender) ?? TencentUtils.checkString(messageBeenReplied.userID)}",
|
||||
atUserList: [
|
||||
TencentUtils.checkString(messageBeenReplied.sender) ??
|
||||
TencentUtils.checkString(messageBeenReplied.userID) ??
|
||||
|
|
@ -886,7 +881,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
if (messageInfo != null) {
|
||||
final messageInfoWithSender = messageInfo.sender == null
|
||||
? tools.setUserInfoForMessage(
|
||||
messageInfo, messageInfo.id ?? textMessageInfo.id ?? "")
|
||||
messageInfo, messageInfo.id ?? textMessageInfo.id ?? "")
|
||||
: messageInfo;
|
||||
|
||||
final hasNickName = messageBeenReplied.nickName != null &&
|
||||
|
|
@ -927,8 +922,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
return null;
|
||||
}
|
||||
|
||||
Future<bool> setLocalCustomData(String msgID, String localCustomData,
|
||||
String conversationID) async {
|
||||
Future<bool> setLocalCustomData(
|
||||
String msgID, String localCustomData, String conversationID) async {
|
||||
final res = await _messageService.setLocalCustomData(
|
||||
msgID: msgID, localCustomData: localCustomData);
|
||||
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
||||
|
|
@ -947,8 +942,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
return false;
|
||||
}
|
||||
|
||||
Future<bool> setLocalCustomInt(String msgID, int localCustomInt,
|
||||
String conversationID) async {
|
||||
Future<bool> setLocalCustomInt(
|
||||
String msgID, int localCustomInt, String conversationID) async {
|
||||
final res = await _messageService.setLocalCustomInt(
|
||||
msgID: msgID, localCustomInt: localCustomInt);
|
||||
List<V2TimMessage> messageList = _messageListMap[conversationID] ?? [];
|
||||
|
|
@ -985,7 +980,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
String receiver = convType == ConvType.c2c ? convID : '';
|
||||
String groupID = convType == ConvType.group ? convID : '';
|
||||
final oldGroupType =
|
||||
groupType != null ? GroupReceptAllowType.values[groupType.index] : null;
|
||||
groupType != null ? GroupReceptAllowType.values[groupType.index] : null;
|
||||
final sendMsgRes = await _messageService.sendMessage(
|
||||
id: id,
|
||||
receiver: receiver,
|
||||
|
|
@ -993,8 +988,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
chatConfig.isShowGroupReadingStatus &&
|
||||
convType == ConvType.group &&
|
||||
((chatConfig.groupReadReceiptPermissionList != null &&
|
||||
chatConfig.groupReadReceiptPermissionList!
|
||||
.contains(groupType)) ||
|
||||
chatConfig.groupReadReceiptPermissionList!
|
||||
.contains(groupType)) ||
|
||||
(chatConfig.groupReadReceiptPermisionList != null &&
|
||||
chatConfig.groupReadReceiptPermisionList!
|
||||
.contains(oldGroupType))),
|
||||
|
|
@ -1014,7 +1009,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
if (isEditStatusMessage == false) {
|
||||
updateMessage(sendMsgRes, convID, id, convType, groupType, setInputField);
|
||||
}
|
||||
if(_lifeCycle?.messageDidSend != null){
|
||||
if (_lifeCycle?.messageDidSend != null) {
|
||||
_lifeCycle!.messageDidSend(sendMsgRes);
|
||||
}
|
||||
|
||||
|
|
@ -1030,7 +1025,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
notifyListeners();
|
||||
}
|
||||
|
||||
updateMessage(V2TimValueCallback<V2TimMessage> sendMsgRes,
|
||||
updateMessage(
|
||||
V2TimValueCallback<V2TimMessage> sendMsgRes,
|
||||
String convID,
|
||||
String id,
|
||||
ConvType convType,
|
||||
|
|
@ -1045,10 +1041,10 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
}
|
||||
|
||||
final findIdIndex =
|
||||
currentHistoryMsgList.indexWhere((element) => element.id == id);
|
||||
currentHistoryMsgList.indexWhere((element) => element.id == id);
|
||||
final targetIndex = findIdIndex == -1
|
||||
? currentHistoryMsgList
|
||||
.indexWhere((element) => element.msgID == sendMsgResData.msgID)
|
||||
.indexWhere((element) => element.msgID == sendMsgResData.msgID)
|
||||
: findIdIndex;
|
||||
if (targetIndex != -1) {
|
||||
currentHistoryMsgList[targetIndex] = sendMsgResData;
|
||||
|
|
@ -1059,13 +1055,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
loadingMessage[convID]!.removeWhere((element) => element.id == id);
|
||||
}
|
||||
final oldGroupType =
|
||||
groupType != null ? GroupReceptAllowType.values[groupType.index] : null;
|
||||
groupType != null ? GroupReceptAllowType.values[groupType.index] : null;
|
||||
if (chatConfig.isShowGroupReadingStatus &&
|
||||
convType == ConvType.group &&
|
||||
sendMsgRes.data?.msgID != null &&
|
||||
((chatConfig.groupReadReceiptPermissionList != null &&
|
||||
chatConfig.groupReadReceiptPermissionList!
|
||||
.contains(groupType)) ||
|
||||
chatConfig.groupReadReceiptPermissionList!
|
||||
.contains(groupType)) ||
|
||||
(chatConfig.groupReadReceiptPermisionList != null &&
|
||||
chatConfig.groupReadReceiptPermisionList!
|
||||
.contains(oldGroupType)))) {
|
||||
|
|
@ -1076,12 +1072,11 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
notifyListeners();
|
||||
}
|
||||
|
||||
void updateAsyncMessage(V2TimMessage message,
|
||||
String convID,) {
|
||||
message.id = DateTime
|
||||
.now()
|
||||
.millisecondsSinceEpoch
|
||||
.toString();
|
||||
void updateAsyncMessage(
|
||||
V2TimMessage message,
|
||||
String convID,
|
||||
) {
|
||||
message.id = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
|
||||
final activeMessageList = _messageListMap[convID];
|
||||
if (activeMessageList == null || activeMessageList.isEmpty) {
|
||||
|
|
@ -1108,11 +1103,11 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
{
|
||||
if (listWithTimestamp.isEmpty ||
|
||||
(listWithTimestamp[listWithTimestamp.length - 1].timestamp !=
|
||||
null &&
|
||||
null &&
|
||||
item.timestamp != null &&
|
||||
(item.timestamp! -
|
||||
listWithTimestamp[listWithTimestamp.length - 1]
|
||||
.timestamp! >
|
||||
listWithTimestamp[listWithTimestamp.length - 1]
|
||||
.timestamp! >
|
||||
interval))) {
|
||||
listWithTimestamp.add(V2TimMessage(
|
||||
userID: '',
|
||||
|
|
@ -1126,15 +1121,13 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
}
|
||||
}
|
||||
final returnValue = listWithTimestamp.reversed.toList();
|
||||
outputLogger.i(returnValue.map((e) => e.toJson())
|
||||
.toList()
|
||||
.toString());
|
||||
outputLogger.i(returnValue.map((e) => e.toJson()).toList().toString());
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
HistoryMessagePosition getMessageListPosition(String? conversationID) {
|
||||
final HistoryMessagePosition? position =
|
||||
_historyMessagePositionMap[conversationID];
|
||||
_historyMessagePositionMap[conversationID];
|
||||
if (position == null) {
|
||||
_historyMessagePositionMap[conversationID ?? currentSelectedConv] =
|
||||
HistoryMessagePosition.bottom;
|
||||
|
|
@ -1144,8 +1137,8 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
|||
}
|
||||
}
|
||||
|
||||
void setMessageListPosition(String conversationID,
|
||||
HistoryMessagePosition position) {
|
||||
void setMessageListPosition(
|
||||
String conversationID, HistoryMessagePosition position) {
|
||||
_historyMessagePositionMap[conversationID] = position;
|
||||
notifyListeners();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,8 +102,6 @@ class TUIKitOutput extends LogOutput {
|
|||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
print(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'dart:io';
|
|||
import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:image_clipboard/image_clipboard.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/data_services/services_locatar.dart';
|
||||
|
|
@ -83,7 +84,7 @@ class TIMUIKitMessageTooltipState
|
|||
final TUISelfInfoViewModel selfInfoViewModel =
|
||||
serviceLocator<TUISelfInfoViewModel>();
|
||||
bool isShowMoreSticker = false;
|
||||
bool isShowOpenFile = false;
|
||||
bool fileBeenDownloaded = false;
|
||||
String filePath = "";
|
||||
|
||||
@override
|
||||
|
|
@ -98,11 +99,11 @@ class TIMUIKitMessageTooltipState
|
|||
(widget.message.fileElem == null &&
|
||||
widget.message.imageElem == null &&
|
||||
widget.message.videoElem == null)) {
|
||||
isShowOpenFile = false;
|
||||
fileBeenDownloaded = false;
|
||||
return;
|
||||
}
|
||||
if (PlatformUtils().isWeb) {
|
||||
isShowOpenFile = true;
|
||||
fileBeenDownloaded = true;
|
||||
return;
|
||||
}
|
||||
if (PlatformUtils().isDesktop) {
|
||||
|
|
@ -115,7 +116,7 @@ class TIMUIKitMessageTooltipState
|
|||
File f = File(savePath);
|
||||
if (f.existsSync() && widget.message.msgID != null) {
|
||||
filePath = savePath;
|
||||
isShowOpenFile = true;
|
||||
fileBeenDownloaded = true;
|
||||
return;
|
||||
}
|
||||
} else if (widget.message.imageElem != null) {
|
||||
|
|
@ -124,19 +125,19 @@ class TIMUIKitMessageTooltipState
|
|||
null &&
|
||||
File(widget.message.imageElem!.imageList![0]!.localUrl!)
|
||||
.existsSync()) {
|
||||
isShowOpenFile = true;
|
||||
fileBeenDownloaded = true;
|
||||
return;
|
||||
}
|
||||
} else if (widget.message.videoElem != null) {
|
||||
if (TencentUtils.checkString(widget.message.videoElem!.localVideoUrl) !=
|
||||
null &&
|
||||
File(widget.message.videoElem!.localVideoUrl!).existsSync()) {
|
||||
isShowOpenFile = true;
|
||||
fileBeenDownloaded = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
isShowOpenFile = false;
|
||||
fileBeenDownloaded = false;
|
||||
}
|
||||
|
||||
bool isRevocable(int timestamp, int upperTimeLimit) =>
|
||||
|
|
@ -183,7 +184,8 @@ class TIMUIKitMessageTooltipState
|
|||
|
||||
bool isAdminCanRecall() {
|
||||
if (widget.model.chatConfig.isGroupAdminRecallEnabled) {
|
||||
final selfMemberInfo = widget.groupMemberInfo ?? widget.model.selfMemberInfo;
|
||||
final selfMemberInfo =
|
||||
widget.groupMemberInfo ?? widget.model.selfMemberInfo;
|
||||
final selfRole = selfMemberInfo?.role;
|
||||
return selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN ||
|
||||
selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER;
|
||||
|
|
@ -205,24 +207,31 @@ class TIMUIKitMessageTooltipState
|
|||
final shouldShowForwardAction = !(widget.message.customElem?.data != null &&
|
||||
MessageUtils.isCallingData(widget.message.customElem!.data!));
|
||||
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 = [
|
||||
if (isShowOpenFile)
|
||||
if (fileBeenDownloaded)
|
||||
MessageToolTipItem(
|
||||
label: TIM_t("打开"),
|
||||
id: "open",
|
||||
iconImageAsset: "images/open_in_new.png",
|
||||
onClick: () => _onTap("open", model)),
|
||||
if (isShowOpenFile && PlatformUtils().isDesktop)
|
||||
if (fileBeenDownloaded && PlatformUtils().isDesktop)
|
||||
MessageToolTipItem(
|
||||
label: PlatformUtils().isMacOS ? TIM_t("在访达中打开") : TIM_t("查看文件夹"),
|
||||
id: "finder",
|
||||
iconImageAsset: "images/folder_open.png",
|
||||
onClick: () => _onTap("finder", model)),
|
||||
MessageToolTipItem(
|
||||
label: TIM_t("复制"),
|
||||
id: "copyMessage",
|
||||
iconImageAsset: "images/copy_message.png",
|
||||
onClick: () => _onTap("copyMessage", model)),
|
||||
if (messageCanCopy)
|
||||
MessageToolTipItem(
|
||||
label: TIM_t("复制"),
|
||||
id: "copyMessage",
|
||||
iconImageAsset: "images/copy_message.png",
|
||||
onClick: () => _onTap("copyMessage", model)),
|
||||
if (shouldShowForwardAction && !isVoteMessage(widget.message))
|
||||
MessageToolTipItem(
|
||||
label: TIM_t("转发"),
|
||||
|
|
@ -263,8 +272,7 @@ class TIMUIKitMessageTooltipState
|
|||
defaultFormattedTipsList = defaultTipsList.where((element) {
|
||||
final type = element.id;
|
||||
if (type == "copyMessage") {
|
||||
return tooltipsConfig.showCopyMessage &&
|
||||
widget.message.elemType == MessageElemType.V2TIM_ELEM_TYPE_TEXT;
|
||||
return tooltipsConfig.showCopyMessage;
|
||||
}
|
||||
if (type == "forwardMessage") {
|
||||
return tooltipsConfig.showForwardMessage &&
|
||||
|
|
@ -402,6 +410,12 @@ class TIMUIKitMessageTooltipState
|
|||
} catch (e) {}
|
||||
}
|
||||
|
||||
Future<void> copyImageToClipboard(String imagePath) async {
|
||||
ImageClipboard().copyImage(imagePath);
|
||||
// final DesktopClipboard desktopClipboard = DesktopClipboard();
|
||||
// desktopClipboard.copyImage(imagePath);
|
||||
}
|
||||
|
||||
_onTap(String operation, TUIChatSeparateViewModel model) async {
|
||||
final messageItem = widget.message;
|
||||
final msgID = messageItem.msgID as String;
|
||||
|
|
@ -485,6 +499,13 @@ class TIMUIKitMessageTooltipState
|
|||
infoCode: 6660408));
|
||||
// ignore: empty_catches
|
||||
} 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;
|
||||
case "replyMessage":
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
Future<void> _saveImageToLocal(
|
||||
context,
|
||||
String imageUrl, {
|
||||
bool isAsset = true,
|
||||
bool isLocalResource = true,
|
||||
TUITheme? theme,
|
||||
}) async {
|
||||
if (PlatformUtils().isWeb) {
|
||||
|
|
@ -163,8 +163,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
}
|
||||
}
|
||||
|
||||
// 本地资源的情况下
|
||||
if (!isAsset) {
|
||||
if (!isLocalResource) {
|
||||
if (widget.message.msgID == null || widget.message.msgID!.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -216,9 +215,6 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
}
|
||||
return;
|
||||
}
|
||||
// model.setMessageProgress(widget.message.msgID!, 0);
|
||||
// var result =
|
||||
// await ImageGallerySaver.saveImage(Uint8List.fromList(response));
|
||||
|
||||
var result = await ImageGallerySaver.saveFile(imageUrl);
|
||||
|
||||
|
|
@ -251,44 +247,44 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
}
|
||||
|
||||
Future<void> _saveImg(TUITheme theme) async {
|
||||
String? path = widget.message.imageElem!.path;
|
||||
if (path != null && PlatformUtils().isWeb
|
||||
? true
|
||||
: File(path!).existsSync()) {
|
||||
return await _saveImageToLocal(context, path,
|
||||
isAsset: true, theme: theme);
|
||||
} else {
|
||||
String imgUrl = getOriginImgURL();
|
||||
if (widget.message.imageElem!.imageList![0]!.localUrl != '' &&
|
||||
widget.message.imageElem!.imageList![0]!.localUrl != null) {
|
||||
File f = File(widget.message.imageElem!.imageList![0]!.localUrl!);
|
||||
if (f.existsSync()) {
|
||||
return await _saveImageToLocal(
|
||||
context,
|
||||
widget.message.imageElem!.imageList![0]!.localUrl!,
|
||||
isAsset: true,
|
||||
theme: theme,
|
||||
);
|
||||
try {
|
||||
String? imageUrl;
|
||||
bool isAssetBool = false;
|
||||
final imageElem = widget.message.imageElem;
|
||||
|
||||
if (imageElem != null) {
|
||||
final originUrl = getOriginImgURL();
|
||||
final localUrl = imageElem.imageList?.firstOrNull?.localUrl;
|
||||
final filePath = imageElem.path;
|
||||
final isWeb = PlatformUtils().isWeb;
|
||||
|
||||
if (!isWeb && filePath != null && File(filePath).existsSync()) {
|
||||
imageUrl = filePath;
|
||||
isAssetBool = true;
|
||||
} else if (localUrl != null &&
|
||||
(!isWeb && File(localUrl).existsSync())) {
|
||||
imageUrl = localUrl;
|
||||
isAssetBool = true;
|
||||
} else {
|
||||
imageUrl = originUrl;
|
||||
isAssetBool = false;
|
||||
}
|
||||
}
|
||||
if (widget.message.imageElem!.path != '' &&
|
||||
widget.message.imageElem!.path != null) {
|
||||
File f = File(widget.message.imageElem!.path!);
|
||||
if (f.existsSync()) {
|
||||
return await _saveImageToLocal(
|
||||
context,
|
||||
widget.message.imageElem!.path!,
|
||||
isAsset: true,
|
||||
theme: theme,
|
||||
);
|
||||
}
|
||||
|
||||
if (imageUrl != null) {
|
||||
return await _saveImageToLocal(
|
||||
context,
|
||||
imageUrl,
|
||||
isLocalResource: isAssetBool,
|
||||
theme: theme,
|
||||
);
|
||||
}
|
||||
return await _saveImageToLocal(
|
||||
context,
|
||||
imgUrl,
|
||||
isAsset: false,
|
||||
theme: theme,
|
||||
);
|
||||
} catch (e) {
|
||||
onTIMCallback(TIMCallback(
|
||||
infoCode: 6660414,
|
||||
infoRecommendText: TIM_t("正在下载中"),
|
||||
type: TIMCallbackType.INFO));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -398,7 +394,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
void onClickImage({
|
||||
required bool isNetworkImage,
|
||||
dynamic heroTag,
|
||||
TUITheme? theme,
|
||||
required TUITheme theme,
|
||||
String? imgUrl,
|
||||
String? imgPath,
|
||||
}) {
|
||||
|
|
@ -429,7 +425,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
heroTag: heroTag,
|
||||
messageID: widget.message.msgID,
|
||||
downloadFn: () async {
|
||||
return await _saveImg(theme!);
|
||||
return await _saveImg(theme);
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
|
@ -448,7 +444,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
heroTag: heroTag,
|
||||
messageID: widget.message.msgID,
|
||||
downloadFn: () async {
|
||||
return await _saveImg(theme!);
|
||||
return await _saveImg(theme);
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
|
@ -458,7 +454,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
|
||||
Widget _renderAllImage(
|
||||
{dynamic heroTag,
|
||||
TUITheme? theme,
|
||||
required TUITheme theme,
|
||||
bool isNetworkImage = false,
|
||||
String? webPath,
|
||||
V2TimImage? originalImg,
|
||||
|
|
@ -485,7 +481,6 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
));
|
||||
} else {
|
||||
final imgPath = (TencentUtils.checkString(smallLocalPath) != null
|
||||
|
||||
? smallLocalPath
|
||||
: originLocalPath)!;
|
||||
return Hero(
|
||||
|
|
@ -504,24 +499,34 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
|
||||
return GestureDetector(
|
||||
onTap: () => onClickImage(
|
||||
theme: theme,
|
||||
heroTag: heroTag,
|
||||
isNetworkImage: isNetworkImage,
|
||||
imgUrl: webPath ?? smallImg?.url ?? originalImg?.url ?? "",
|
||||
imgPath: (TencentUtils.checkString(originLocalPath) != null
|
||||
? originLocalPath
|
||||
: smallLocalPath) ?? ""
|
||||
),
|
||||
? originLocalPath
|
||||
: smallLocalPath) ??
|
||||
""),
|
||||
child: getImageWidget(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
void initImages() async {
|
||||
if (!PlatformUtils().isWeb &&
|
||||
TencentUtils.checkString(widget.message.msgID) != null) {
|
||||
if (TencentUtils.checkString(
|
||||
widget.message.imageElem!.imageList![0]!.localUrl) ==
|
||||
if (widget.message.imageElem?.imageList == null ||
|
||||
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 ||
|
||||
!File(widget.message.imageElem!.imageList![0]!.localUrl!)
|
||||
.existsSync()) {
|
||||
|
|
@ -531,9 +536,11 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
imageType: 0,
|
||||
isSnapshot: false);
|
||||
}
|
||||
if (TencentUtils.checkString(
|
||||
widget.message.imageElem!.imageList![1]!.localUrl) ==
|
||||
null ||
|
||||
if (widget.message.imageElem?.imageList == null ||
|
||||
widget.message.imageElem!.imageList!.length < 2 &&
|
||||
TencentUtils.checkString(
|
||||
widget.message.imageElem?.imageList?[1]?.localUrl) ==
|
||||
null ||
|
||||
!File(widget.message.imageElem!.imageList![1]!.localUrl!)
|
||||
.existsSync()) {
|
||||
_messageService.downloadMessage(
|
||||
|
|
@ -542,8 +549,10 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
imageType: 1,
|
||||
isSnapshot: false);
|
||||
}
|
||||
if (TencentUtils.checkString(
|
||||
widget.message.imageElem!.imageList![2]!.localUrl) ==
|
||||
if (widget.message.imageElem?.imageList != null ||
|
||||
widget.message.imageElem!.imageList!.length < 3 ||
|
||||
TencentUtils.checkString(
|
||||
widget.message.imageElem?.imageList?[2]?.localUrl) ==
|
||||
null ||
|
||||
!File(widget.message.imageElem!.imageList![2]!.localUrl!)
|
||||
.existsSync()) {
|
||||
|
|
@ -556,6 +565,12 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
initImages();
|
||||
}
|
||||
|
||||
bool isNeedShowLocalPath() {
|
||||
final current = (DateTime.now().millisecondsSinceEpoch / 1000).ceil();
|
||||
final timeStamp = widget.message.timestamp ?? current;
|
||||
|
|
@ -563,7 +578,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
|
|||
(isSent || current - timeStamp < 300);
|
||||
}
|
||||
|
||||
Widget? _renderImage(dynamic heroTag, TUITheme? theme,
|
||||
Widget? _renderImage(dynamic heroTag, TUITheme theme,
|
||||
{V2TimImage? originalImg, V2TimImage? smallImg}) {
|
||||
double? positionRadio;
|
||||
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) {
|
||||
textFieldController = TIMUIKitInputTextFieldController();
|
||||
}
|
||||
if (oldWidget.groupMemberList != widget.groupMemberList) {
|
||||
model.groupMemberList = widget.groupMemberList;
|
||||
}
|
||||
}
|
||||
|
||||
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: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/ui/widgets/center_loading.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/ui/widgets/image_hero.dart';
|
||||
|
|
@ -152,7 +151,8 @@ class _ImageScreenState extends TIMUIKitState<ImageScreen>
|
|||
color: Colors.black,
|
||||
child: const Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: Colors.white)));
|
||||
color: Colors.white))
|
||||
);
|
||||
case LoadState.completed:
|
||||
final screenHeight =
|
||||
MediaQuery.of(context).size.height;
|
||||
|
|
@ -266,7 +266,6 @@ class _ImageScreenState extends TIMUIKitState<ImageScreen>
|
|||
},
|
||||
),
|
||||
),
|
||||
CenterLoading(messageID: widget.messageID),
|
||||
if (isLoading)
|
||||
Container(
|
||||
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/material.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/renderer/md_image.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/widgets/link_preview/common/utils.dart';
|
||||
|
|
|
|||
|
|
@ -683,6 +683,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
name: tencent_cloud_chat_uikit
|
||||
description: A powerful chat UI component library and business logic for Tencent Cloud Chat, creating seamless in-app chat modules for delightful user experiences.
|
||||
version: 2.2.0
|
||||
homepage: https://www.tencentcloud.com/products/im?from=pub
|
||||
version: 2.2.1
|
||||
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
|
||||
documentation: https://comm.qq.com/im/doc/flutter/en/TUIKit/readme.html
|
||||
|
||||
|
|
@ -76,6 +76,7 @@ dependencies:
|
|||
diff_match_patch: ^0.4.1
|
||||
markdown: ^7.1.0
|
||||
logger: ^2.0.1
|
||||
image_clipboard: ^1.0.0+2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^1.0.0
|
||||
|
|
|
|||
Loading…
Reference in New Issue