feat: Upgrade to 2.1.1 pre-release

This commit is contained in:
anonymous 2023-06-08 15:29:41 +08:00
parent be65bea65e
commit 2f001240cd
22 changed files with 1280 additions and 886 deletions

View File

@ -1139,7 +1139,7 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "2.1.0+1" version: "2.1.0+2"
tencent_cloud_uikit_core: tencent_cloud_uikit_core:
dependency: transitive dependency: transitive
description: description:

BIN
images/svg/send_face.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -1,5 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="7.5" stroke="#232832"/> <g opacity="0.795169">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5 5C5.55228 5 6 5.44772 6 6C6 6.55228 5.55228 7 5 7C4.44772 7 4 6.55228 4 6C4 5.44772 4.44772 5 5 5Z" fill="#232832"/> <circle cx="8" cy="8" r="7.5" stroke="#232832"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 5C11.5523 5 12 5.44772 12 6C12 6.55228 11.5523 7 11 7C10.4477 7 10 6.55228 10 6C10 5.44772 10.4477 5 11 5Z" fill="#232832"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M5 5C5.55228 5 6 5.44772 6 6C6 6.55228 5.55228 7 5 7C4.44772 7 4 6.55228 4 6C4 5.44772 4.44772 5 5 5Z" fill="#232832"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 5C11.5523 5 12 5.44772 12 6C12 6.55228 11.5523 7 11 7C10.4477 7 10 6.55228 10 6C10 5.44772 10.4477 5 11 5Z" fill="#232832"/>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 559 B

View File

@ -20,6 +20,7 @@ import 'package:tencent_cloud_chat_uikit/data_services/message/message_services.
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart'; import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
import 'package:tencent_cloud_chat_uikit/ui/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/platform.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_cloud_custom_data.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
enum LoadDirection { previous, latest } enum LoadDirection { previous, latest }
@ -53,7 +54,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
bool showC2cMessageEditStatus = true; bool showC2cMessageEditStatus = true;
TIMUIKitChatConfig chatConfig = const TIMUIKitChatConfig(); TIMUIKitChatConfig chatConfig = const TIMUIKitChatConfig();
ValueChanged<String>? setInputField; ValueChanged<String>? setInputField;
String Function(V2TimMessage message)? abstractMessageBuilder; String? Function(V2TimMessage message)? abstractMessageBuilder;
Function(String userID, TapDownDetails tapDetails)? onTapAvatar; Function(String userID, TapDownDetails tapDetails)? onTapAvatar;
V2TimGroupMemberFullInfo? _currentChatUserInfo; V2TimGroupMemberFullInfo? _currentChatUserInfo;
V2TimGroupInfo? _groupInfo; V2TimGroupInfo? _groupInfo;
@ -228,7 +229,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
globalModel.setChatConfig(chatConfig); globalModel.setChatConfig(chatConfig);
globalModel.clearRecivedNewMessageCount(); globalModel.clearRecivedNewMessageCount();
_isInit = true; _isInit = true;
Future.delayed(const Duration(milliseconds: 300), (){ Future.delayed(const Duration(milliseconds: 300), () {
markMessageAsRead(); markMessageAsRead();
}); });
} }
@ -809,7 +810,25 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
return null; return null;
} }
String _getAbstractMessage(V2TimMessage message) { String _getMessageAbstract(V2TimMessage message){
final messageAbstract = RepliedMessageAbstract(
summary: TIM_t(_getMessageSummary(message)),
elemType: message.elemType,
msgID: message.msgID,
timestamp: message.timestamp,
seq: message.seq
);
return jsonEncode(messageAbstract.toJson());
}
String _getMessageSummary(V2TimMessage message) {
final String? customAbstractMessage = abstractMessageBuilder != null
? abstractMessageBuilder!(message)
: null;
if (customAbstractMessage != null) {
return customAbstractMessage;
}
final elemType = message.elemType; final elemType = message.elemType;
switch (elemType) { switch (elemType) {
case MessageElemType.V2TIM_ELEM_TYPE_FACE: case MessageElemType.V2TIM_ELEM_TYPE_FACE:
@ -831,7 +850,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
case MessageElemType.V2TIM_ELEM_TYPE_SOUND: case MessageElemType.V2TIM_ELEM_TYPE_SOUND:
return "[语音消息]"; return "[语音消息]";
case MessageElemType.V2TIM_ELEM_TYPE_TEXT: case MessageElemType.V2TIM_ELEM_TYPE_TEXT:
return "[文本消息]"; return message.textElem?.text ?? "[文本消息]";
case MessageElemType.V2TIM_ELEM_TYPE_VIDEO: case MessageElemType.V2TIM_ELEM_TYPE_VIDEO:
return "[视频消息]"; return "[视频消息]";
default: default:
@ -869,7 +888,7 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
final cloudCustomData = { final cloudCustomData = {
"messageReply": { "messageReply": {
"messageID": _repliedMessage!.msgID, "messageID": _repliedMessage!.msgID,
"messageAbstract": _getAbstractMessage(_repliedMessage!), "messageAbstract": _getMessageAbstract(_repliedMessage!),
"messageSender": hasNickName "messageSender": hasNickName
? _repliedMessage!.nickName ? _repliedMessage!.nickName
: _repliedMessage?.sender, : _repliedMessage?.sender,
@ -893,9 +912,10 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
]; ];
globalModel.setMessageList(conversationID, currentHistoryMsgList); globalModel.setMessageList(conversationID, currentHistoryMsgList);
final sendMsgRes = await _messageService.sendReplyMessage( _repliedMessage = null;
final sendMsgRes = await _messageService.sendMessage(
cloudCustomData: json.encode(cloudCustomData),
id: textMessageInfo.id as String, id: textMessageInfo.id as String,
replyMessage: _repliedMessage!,
offlinePushInfo: tools.buildMessagePushInfo( offlinePushInfo: tools.buildMessagePushInfo(
messageInfoWithSender, convID, convType), messageInfoWithSender, convID, convType),
needReadReceipt: chatConfig.isShowGroupReadingStatus && needReadReceipt: chatConfig.isShowGroupReadingStatus &&
@ -908,7 +928,6 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
.contains(oldGroupType))), .contains(oldGroupType))),
groupID: groupID, groupID: groupID,
receiver: receiver); receiver: receiver);
_repliedMessage = null;
notifyListeners(); notifyListeners();
globalModel.updateMessage(sendMsgRes, convID, globalModel.updateMessage(sendMsgRes, convID,
messageInfoWithSender.id ?? "", convType, groupType, setInputField); messageInfoWithSender.id ?? "", convType, groupType, setInputField);

View File

@ -2,6 +2,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart';
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
import 'package:tencent_im_base/tencent_im_base.dart'; import 'package:tencent_im_base/tencent_im_base.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/conversation_life_cycle.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/conversation_life_cycle.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
@ -42,6 +43,7 @@ class TUIConversationViewModel extends ChangeNotifier {
late V2TimConversationListener _conversationListener; late V2TimConversationListener _conversationListener;
List<V2TimConversation?> _conversationList = []; List<V2TimConversation?> _conversationList = [];
static V2TimConversation? _selectedConversation; static V2TimConversation? _selectedConversation;
Map<String, String> webDraftMap = {};
bool _haveMoreData = true; bool _haveMoreData = true;
int _totalUnReadCount = 0; int _totalUnReadCount = 0;
@ -65,9 +67,8 @@ class TUIConversationViewModel extends ChangeNotifier {
.toList(); .toList();
_conversationList.removeWhere((element) => element?.isPinned == true); _conversationList.removeWhere((element) => element?.isPinned == true);
_conversationList = [...pinnedConversation, ..._conversationList]; _conversationList = [...pinnedConversation, ..._conversationList];
// ignore: empty_catches // ignore: empty_catches
} catch (e) { } catch (e) {}
}
} else { } else {
_conversationList.sort((a, b) => b!.orderkey!.compareTo(a!.orderkey!)); _conversationList.sort((a, b) => b!.orderkey!.compareTo(a!.orderkey!));
} }
@ -259,10 +260,46 @@ class TUIConversationViewModel extends ChangeNotifier {
listener: _conversationListener); listener: _conversationListener);
} }
Future<V2TimCallback> setConversationDraft( Future<V2TimCallback> setConversationDraft({
{required String conversationID, String? draftText}) async { required String conversationID,
return _conversationService.setConversationDraft( String? draftText,
conversationID: conversationID, draftText: draftText); bool isTopic = false,
String? groupID,
bool isAllowWeb = true,
}) async {
assert(!isTopic || (groupID != null && groupID.isNotEmpty),
"When 'isTopic' is true, 'groupID' must not be null or empty.");
if (PlatformUtils().isWeb && isAllowWeb) {
webDraftMap[conversationID] = draftText ?? "";
return V2TimCallback(code: 0, desc: "");
} else {
if (isTopic) {
final topicInfoList = await TencentImSDKPlugin.v2TIMManager
.getGroupManager()
.getTopicInfoList(groupID: groupID!, topicIDList: [conversationID]);
final topicInfo = topicInfoList.data?.first.topicInfo;
topicInfo?.draftText = draftText;
final res = await TencentImSDKPlugin.v2TIMManager
.getGroupManager()
.setTopicInfo(groupID: groupID, topicInfo: topicInfo!);
return res;
} else {
return _conversationService.setConversationDraft(
conversationID: conversationID, draftText: draftText);
}
}
}
clearWebDraft({
required String conversationID,
}) {
webDraftMap[conversationID] = "";
}
String? getWebDraft({
required String conversationID,
}) {
return TencentUtils.checkString(webDraftMap[conversationID]);
} }
clearData() { clearData() {

View File

@ -1,4 +1,5 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
import 'package:tencent_im_base/tencent_im_base.dart'; import 'package:tencent_im_base/tencent_im_base.dart';
import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_config.dart'; import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_config.dart';
@ -92,4 +93,6 @@ abstract class CoreServices {
setDarkTheme(); setDarkTheme();
setLightTheme(); setLightTheme();
setDeviceType(DeviceType deviceType);
} }

View File

@ -2,6 +2,7 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
import 'package:tencent_im_base/tencent_im_base.dart'; import 'package:tencent_im_base/tencent_im_base.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
@ -74,22 +75,28 @@ class CoreServicesImpl implements CoreServices {
@override @override
Future<bool?> init( Future<bool?> init(
{ {
/// Callback from TUIKit invoke, includes IM SDK API error, notify information, Flutter error. /// Callback from TUIKit invoke, includes IM SDK API error, notify information, Flutter error.
ValueChanged<TIMCallback>? onTUIKitCallbackListener, ValueChanged<TIMCallback>? onTUIKitCallbackListener,
required int sdkAppID, required int sdkAppID,
required LogLevelEnum loglevel, required LogLevelEnum loglevel,
required V2TimSDKListener listener, required V2TimSDKListener listener,
LanguageEnum? language, LanguageEnum? language,
String? extraLanguage, String? extraLanguage,
TIMUIKitConfig? config, TIMUIKitConfig? config,
/// Specify the current device platform, mobile or desktop, based on your needs.
/// TUIKit will automatically determine the platform if no specification is provided. DeviceType? platform,
DeviceType? platform,
VoidCallback? onWebLoginSuccess}) async { VoidCallback? onWebLoginSuccess}) async {
if (platform != null) {
TUIKitScreenUtils.deviceType = platform;
}
addIdentifier(); addIdentifier();
if(extraLanguage != null){ if (extraLanguage != null) {
Future.delayed(const Duration(milliseconds: 1), () { Future.delayed(const Duration(milliseconds: 1), () {
I18nUtils(null, extraLanguage); I18nUtils(null, extraLanguage);
}); });
}else if (language != null) { } else if (language != null) {
Future.delayed(const Duration(milliseconds: 1), () { Future.delayed(const Duration(milliseconds: 1), () {
I18nUtils(null, languageEnumToString[language]); I18nUtils(null, languageEnumToString[language]);
}); });
@ -139,11 +146,11 @@ class CoreServicesImpl implements CoreServices {
required String userId, required String userId,
}) async { }) async {
_userID = userId; _userID = userId;
if(extraLanguage != null){ if (extraLanguage != null) {
Future.delayed(const Duration(milliseconds: 1), () { Future.delayed(const Duration(milliseconds: 1), () {
I18nUtils(null, extraLanguage); I18nUtils(null, extraLanguage);
}); });
}else if (language != null) { } else if (language != null) {
Future.delayed(const Duration(milliseconds: 1), () { Future.delayed(const Duration(milliseconds: 1), () {
I18nUtils(null, languageEnumToString[language]); I18nUtils(null, languageEnumToString[language]);
}); });
@ -246,9 +253,8 @@ class CoreServicesImpl implements CoreServices {
} }
tuiFriendShipViewModel.userStatusList = currentUserStatusList; tuiFriendShipViewModel.userStatusList = currentUserStatusList;
// ignore: empty_catches // ignore: empty_catches
} catch (e) { } catch (e) {}
}
} }
@override @override
@ -398,4 +404,9 @@ class CoreServicesImpl implements CoreServices {
.doBackground(unreadCount: totalCount ?? 0); .doBackground(unreadCount: totalCount ?? 0);
} }
} }
@override
setDeviceType(DeviceType deviceType) {
TUIKitScreenUtils.deviceType = deviceType;
}
} }

View File

@ -138,8 +138,8 @@ class TIMUIKitChatController {
assert((groupID == null) != (userID == null)); assert((groupID == null) != (userID == null));
assert(groupID != null || convType != ConvType.group); assert(groupID != null || convType != ConvType.group);
assert(userID != null || convType != ConvType.c2c); assert(userID != null || convType != ConvType.c2c);
if (isNavigateToMessageListBottom) { if (isNavigateToMessageListBottom && scrollController != null) {
scrollController?.animateTo( scrollController!.animateTo(
scrollController!.position.minScrollExtent, scrollController!.position.minScrollExtent,
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
curve: Curves.ease, curve: Curves.ease,
@ -159,7 +159,7 @@ class TIMUIKitChatController {
offlinePushInfo: offlinePushInfo); offlinePushInfo: offlinePushInfo);
} else if (model != null) { } else if (model != null) {
/// Sends a message to the current conversation specified on `TIMUIKitChat`. `TIMUIKitChat` /// Sends a message to the current conversation specified on `TIMUIKitChat`. `TIMUIKitChat`
if (isNavigateToMessageListBottom) { if (isNavigateToMessageListBottom && scrollController != null) {
scrollController?.animateTo( scrollController?.animateTo(
scrollController!.position.minScrollExtent, scrollController!.position.minScrollExtent,
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),

View File

@ -28,8 +28,9 @@ class TUIKitScreenUtils {
final diagonalInInches = final diagonalInInches =
sqrt(pow(screenWidth, 2) + pow(screenHeight, 2)) / 96.0; sqrt(pow(screenWidth, 2) + pow(screenHeight, 2)) / 96.0;
print("diagonalInInches $diagonalInInches");
deviceType = diagonalInInches < 8.0 ? DeviceType.Mobile : DeviceType.Desktop; deviceType = diagonalInInches < 11.0 ? DeviceType.Mobile : DeviceType.Desktop;
return deviceType ?? DeviceType.Mobile; return deviceType ?? DeviceType.Mobile;
}else{ }else{
if(context != null){ if(context != null){

View File

@ -351,7 +351,9 @@ class TIMUIKitMessageTooltipState
children: [ children: [
Image.asset( Image.asset(
item.iconImageAsset, item.iconImageAsset,
package: 'tencent_cloud_chat_uikit', package: defaultTipsIds.contains(item.id)
? 'tencent_cloud_chat_uikit'
: null,
width: 20, width: 20,
height: 20, height: 20,
), ),

View File

@ -3,6 +3,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_model_tools.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/common_utils.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/common_utils.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
import 'package:tencent_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';
@ -57,7 +58,7 @@ class TIMUIKitReplyElem extends StatefulWidget {
} }
class _TIMUIKitReplyElemState extends TIMUIKitState<TIMUIKitReplyElem> { class _TIMUIKitReplyElemState extends TIMUIKitState<TIMUIKitReplyElem> {
MessageRepliedData? repliedMessage; MessageRepliedData? repliedMessage = null;
V2TimMessage? rawMessage; V2TimMessage? rawMessage;
bool isShowJumpState = false; bool isShowJumpState = false;
bool isShining = false; bool isShining = false;
@ -81,10 +82,32 @@ class _TIMUIKitReplyElemState extends TIMUIKitState<TIMUIKitReplyElem> {
} }
_getMessageByMessageID() async { _getMessageByMessageID() async {
final cloudCustomData = _getRepliedMessage(); final MessageRepliedData? cloudCustomData = _getRepliedMessage();
if (cloudCustomData != null) { if (cloudCustomData != null) {
if (mounted) {
setState(() {
repliedMessage = cloudCustomData;
});
}
final messageID = cloudCustomData.messageID; final messageID = cloudCustomData.messageID;
final message = await widget.chatModel.findMessage(messageID); V2TimMessage? message = await widget.chatModel.findMessage(messageID);
if (message == null) {
try {
final RepliedMessageAbstract repliedMessageAbstract =
RepliedMessageAbstract.fromJson(
jsonDecode(cloudCustomData.messageAbstract));
if (repliedMessageAbstract.isNotEmpty) {
message = V2TimMessage(
elemType: 0,
seq: repliedMessageAbstract.seq,
timestamp: repliedMessageAbstract.timestamp,
msgID: repliedMessageAbstract.msgID);
}
} catch (e) {
print(e.toString());
}
}
if (message != null) { if (message != null) {
if (mounted) { if (mounted) {
setState(() { setState(() {
@ -93,36 +116,53 @@ class _TIMUIKitReplyElemState extends TIMUIKitState<TIMUIKitReplyElem> {
} }
} }
} }
if (mounted) {
setState(() {
repliedMessage = cloudCustomData;
});
}
} }
Widget _defaultRawMessageText(String text, TUITheme? theme) { Widget _defaultRawMessageText(String text, TUITheme? theme) {
return Text(text, return Text(text,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: theme?.weakTextColor, color: theme?.weakTextColor,
fontWeight: FontWeight.w400)); fontWeight: FontWeight.w400));
} }
_renderMessageSummary(TUITheme? theme) {
try {
final RepliedMessageAbstract repliedMessageAbstract =
RepliedMessageAbstract.fromJson(
jsonDecode(repliedMessage?.messageAbstract ?? ""));
if (TencentUtils.checkString(repliedMessageAbstract.summary) != null) {
return _defaultRawMessageText(repliedMessageAbstract.summary!, theme);
}
return _defaultRawMessageText(
repliedMessage?.messageAbstract ?? TIM_t("[未知消息]"), theme);
} catch (e) {
return _defaultRawMessageText(
repliedMessage?.messageAbstract ?? TIM_t("[未知消息]"), theme);
}
}
_rawMessageBuilder(V2TimMessage? message, TUITheme? theme) { _rawMessageBuilder(V2TimMessage? message, TUITheme? theme) {
if (repliedMessage == null) { if (repliedMessage == null) {
return const SizedBox(width: 0, height: 12); return const SizedBox(width: 0, height: 12);
} }
if (message == null) { if (message == null) {
if (repliedMessage?.messageAbstract != null) { if (repliedMessage?.messageAbstract != null) {
return _defaultRawMessageText(repliedMessage!.messageAbstract, theme); _renderMessageSummary(theme);
} }
return const SizedBox(width: 0, height: 12); return const SizedBox(width: 0, height: 12);
} }
final messageType = message.elemType; final messageType = message.elemType;
final isSelf = message.isSelf ?? true; final isSelf = message.isSelf ?? true;
if (widget.chatModel.abstractMessageBuilder != null) { final customAbstractMessage =
widget.chatModel.abstractMessageBuilder != null
? widget.chatModel.abstractMessageBuilder!(message)
: null;
if (customAbstractMessage != null) {
return _defaultRawMessageText( return _defaultRawMessageText(
widget.chatModel.abstractMessageBuilder!(message), customAbstractMessage,
theme, theme,
); );
} }
@ -173,7 +213,7 @@ class _TIMUIKitReplyElemState extends TIMUIKitState<TIMUIKitReplyElem> {
messageID: message.msgID ?? "", messageID: message.msgID ?? "",
isSelf: isSelf); isSelf: isSelf);
default: default:
return _defaultRawMessageText(TIM_t("[未知消息]"), theme); return _renderMessageSummary(theme);
} }
} }

View File

@ -93,6 +93,8 @@ class TIMUIKitInputTextField extends StatefulWidget {
final String? groupType; final String? groupType;
final String? groupID;
const TIMUIKitInputTextField( const TIMUIKitInputTextField(
{Key? key, {Key? key,
required this.conversationID, required this.conversationID,
@ -113,7 +115,8 @@ class TIMUIKitInputTextField extends StatefulWidget {
required this.model, required this.model,
required this.currentConversation, required this.currentConversation,
this.groupType, this.groupType,
this.atMemberPanelScroll}) this.atMemberPanelScroll,
this.groupID})
: super(key: key); : super(key: key);
@override @override
@ -166,21 +169,22 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
return text.replaceAll(RegExp(r'\ufeff'), ""); return text.replaceAll(RegExp(r'\ufeff'), "");
} }
handleSetDraftText([String? id, ConvType? convType]) async { Future handleSetDraftText([String? id, ConvType? convType]) async {
String text = textEditingController.text;
String convID = id ?? widget.conversationID; String convID = id ?? widget.conversationID;
String conversationID = convID.contains("@TOPIC#") final isTopic = convID.contains("@TOPIC#");
String conversationID = isTopic
? convID ? convID
: ((convType ?? widget.conversationType) == ConvType.c2c : ((convType ?? widget.conversationType) == ConvType.c2c
? "c2c_$convID" ? "c2c_$convID"
: "group_$convID"); : "group_$convID");
String text = textEditingController.text; String draftText = _filterU200b(text);
String? draftText = _filterU200b(text); return await conversationModel.setConversationDraft(
groupID: widget.groupID,
if (draftText.isEmpty) { isTopic: isTopic,
draftText = ""; isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb,
} conversationID: conversationID,
await conversationModel.setConversationDraft( draftText: draftText);
conversationID: conversationID, draftText: draftText);
} }
backSpaceText() { backSpaceText() {
@ -189,11 +193,9 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
if (originalText == zeroWidthSpace) { if (originalText == zeroWidthSpace) {
_handleSoftKeyBoardDelete(); _handleSoftKeyBoardDelete();
// _addDeleteTag();
} else { } else {
text = originalText.characters.skipLast(1); text = originalText.characters.skipLast(1);
textEditingController.text = text; textEditingController.text = text;
// handleSetDraftText();
} }
} }
@ -202,6 +204,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
lastText = ""; lastText = "";
final text = textEditingController.text.trim(); final text = textEditingController.text.trim();
final convType = widget.conversationType; final convType = widget.conversationType;
conversationModel.clearWebDraft(conversationID: widget.conversationID);
if (text.isNotEmpty && text != zeroWidthSpace) { if (text.isNotEmpty && text != zeroWidthSpace) {
if (widget.model.repliedMessage != null) { if (widget.model.repliedMessage != null) {
MessageUtils.handleMessageError( MessageUtils.handleMessageError(
@ -259,6 +262,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} }
onSubmitted() async { onSubmitted() async {
conversationModel.clearWebDraft(conversationID: widget.conversationID);
lastText = ""; lastText = "";
final text = textEditingController.text.trim(); final text = textEditingController.text.trim();
final convType = widget.conversationType; final convType = widget.conversationType;
@ -417,6 +421,22 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
mentionedMembersMap = map; mentionedMembersMap = map;
} }
updateMentionedMap() {
Map<String, V2TimGroupMemberFullInfo> map = {};
Iterable<Match> matches = atTextReg.allMatches(textEditingController.text);
List<String?> parseAtList = [];
for (final item in matches) {
final str = item.group(0);
parseAtList.add(str);
}
for (String? key in parseAtList) {
if (key != null && mentionedMembersMap[key] != null) {
map[key] = mentionedMembersMap[key]!;
}
}
mentionedMembersMap = map;
}
_handleAtText(String text, TUIChatSeparateViewModel model) async { _handleAtText(String text, TUIChatSeparateViewModel model) async {
final text = textEditingController.text; final text = textEditingController.text;
String? groupID = widget.conversationType == ConvType.group String? groupID = widget.conversationType == ConvType.group
@ -449,22 +469,11 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
textEditingController.selection = textEditingController.selection =
TextSelection.collapsed(offset: atIndex); TextSelection.collapsed(offset: atIndex);
lastText = newText; lastText = newText;
Map<String, V2TimGroupMemberFullInfo> map = {}; updateMentionedMap();
Iterable<Match> matches = atTextReg.allMatches(text);
List<String?> parseAtList = [];
for (final item in matches) {
final str = item.group(0);
parseAtList.add(str);
}
for (String? key in parseAtList) {
if (key != null && mentionedMembersMap[key] != null) {
map[key] = mentionedMembersMap[key]!;
}
}
mentionedMembersMap = map;
return; return;
} }
} }
updateMentionedMap();
} }
final int selfRole = widget.model.selfMemberInfo?.role ?? 0; final int selfRole = widget.model.selfMemberInfo?.role ?? 0;
@ -709,8 +718,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
void didUpdateWidget(TIMUIKitInputTextField oldWidget) { void didUpdateWidget(TIMUIKitInputTextField oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (widget.conversationID != oldWidget.conversationID) { if (widget.conversationID != oldWidget.conversationID) {
handleSetDraftText(oldWidget.conversationID, oldWidget.conversationType);
mentionedMembersMap.clear(); mentionedMembersMap.clear();
handleSetDraftText(oldWidget.conversationID, oldWidget.conversationType);
if (oldWidget.initText != widget.initText) { if (oldWidget.initText != widget.initText) {
textEditingController.text = widget.initText ?? ""; textEditingController.text = widget.initText ?? "";
} else { } else {

View File

@ -309,12 +309,23 @@ class _TIMUIKitTextFieldLayoutNarrowState
}); });
}; };
} }
String getAbstractMessage(V2TimMessage message) {
final String? customAbstractMessage = widget
.model.abstractMessageBuilder != null ? widget.model
.abstractMessageBuilder!(widget.model.repliedMessage!) : null;
return customAbstractMessage ?? MessageUtils
.getAbstractMessageAsync(
widget.model.repliedMessage!, widget.model.groupMemberList ?? []);
}
_buildRepliedMessage(V2TimMessage? repliedMessage) { _buildRepliedMessage(V2TimMessage? repliedMessage) {
final haveRepliedMessage = repliedMessage != null; final haveRepliedMessage = repliedMessage != null;
if (haveRepliedMessage) { if (haveRepliedMessage) {
final text = final text =
"${MessageUtils.getDisplayName(widget.model.repliedMessage!)}:${widget.model.abstractMessageBuilder != null ? widget.model.abstractMessageBuilder!(widget.model.repliedMessage!) : MessageUtils.getAbstractMessageAsync(widget.model.repliedMessage!, widget.model.groupMemberList ?? [])}"; "${MessageUtils.getDisplayName(
widget.model.repliedMessage!)}:${getAbstractMessage(
repliedMessage
)}";
return Container( return Container(
color: widget.backgroundColor ?? hexToColor("f5f5f6"), color: widget.backgroundColor ?? hexToColor("f5f5f6"),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,

View File

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:ui' as ui;
import 'package:fc_native_video_thumbnail/fc_native_video_thumbnail.dart'; import 'package:fc_native_video_thumbnail/fc_native_video_thumbnail.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
@ -32,6 +33,7 @@ import 'package:universal_html/html.dart' as html;
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart'; import 'package:wechat_assets_picker/wechat_assets_picker.dart';
import 'package:flutter_svg/flutter_svg.dart';
// ignore: unnecessary_import // ignore: unnecessary_import
import 'dart:typed_data'; import 'dart:typed_data';
@ -262,36 +264,62 @@ class _TIMUIKitTextFieldLayoutWideState
}; };
} }
String getAbstractMessage(V2TimMessage message) {
final String? customAbstractMessage =
widget.model.abstractMessageBuilder != null
? widget.model.abstractMessageBuilder!(widget.model.repliedMessage!)
: null;
return customAbstractMessage ??
MessageUtils.getAbstractMessageAsync(
widget.model.repliedMessage!, widget.model.groupMemberList ?? []);
}
_buildRepliedMessage(V2TimMessage? repliedMessage) { _buildRepliedMessage(V2TimMessage? repliedMessage) {
final haveRepliedMessage = repliedMessage != null; final haveRepliedMessage = repliedMessage != null;
if (haveRepliedMessage) { if (haveRepliedMessage) {
final text =
"${MessageUtils.getDisplayName(widget.model.repliedMessage!)}:${widget.model.abstractMessageBuilder != null ? widget.model.abstractMessageBuilder!(widget.model.repliedMessage!) : MessageUtils.getAbstractMessageAsync(widget.model.repliedMessage!, widget.model.groupMemberList ?? [])}";
return Container( return Container(
color: widget.backgroundColor ?? hexToColor("f5f5f6"), color: widget.backgroundColor ?? hexToColor("f5f5f6"),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text(
TIM_t("回复 "),
style: TextStyle(
color: hexToColor("8f959e"), fontSize: 14),
),
Text(
MessageUtils.getDisplayName(
widget.model.repliedMessage!),
softWrap: true,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: hexToColor("8f959e"),
fontSize: 14,
fontWeight: FontWeight.bold),
),
Expanded( Expanded(
child: Text( child: Text(
text, ": ${getAbstractMessage(repliedMessage)}",
softWrap: true, maxLines: 1,
maxLines: 3,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle(color: hexToColor("8f959e"), fontSize: 14), style: TextStyle(
fontSize: 14,
color: hexToColor("8f959e"),
),
), ),
), ),
const SizedBox( const SizedBox(
width: 16, width: 8,
), ),
InkWell( InkWell(
onTap: () { onTap: () {
widget.model.repliedMessage = null; widget.model.repliedMessage = null;
}, },
child: Icon(Icons.clear, color: hexToColor("8f959e"), size: 18), child: Icon(Icons.cancel, color: hexToColor("8f959e"), size: 18),
) )
], ],
), ),
@ -314,8 +342,9 @@ class _TIMUIKitTextFieldLayoutWideState
entry = null; entry = null;
} }
}, },
initOffset: offset ?? initOffset: offset != null
Offset(MediaQuery.of(context).size.height * 0.5 + 20, ? Offset(offset.dx, max(offset.dy, 16))
: Offset(MediaQuery.of(context).size.height * 0.5 + 20,
MediaQuery.of(context).size.height * 0.5 - 100), MediaQuery.of(context).size.height * 0.5 - 100),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -793,7 +822,7 @@ class _TIMUIKitTextFieldLayoutWideState
onClick: (offset) { onClick: (offset) {
_sendEmoji(offset, widget.theme); _sendEmoji(offset, widget.theme);
}, },
svgPath: "images/svg/send_face.svg"), imgPath: "images/svg/send_face.png"),
if (config.showScreenshotButton && PlatformUtils().isDesktop) if (config.showScreenshotButton && PlatformUtils().isDesktop)
DesktopControlBarItem( DesktopControlBarItem(
item: "screenShot", item: "screenShot",
@ -950,6 +979,7 @@ class _TIMUIKitTextFieldLayoutWideState
color: widget.backgroundColor ?? theme.desktopChatMessageInputBgColor, color: widget.backgroundColor ?? theme.desktopChatMessageInputBgColor,
child: Column( child: Column(
children: [ children: [
_buildRepliedMessage(widget.repliedMessage),
SizedBox( SizedBox(
height: 1, height: 1,
child: Container( child: Container(
@ -963,7 +993,6 @@ class _TIMUIKitTextFieldLayoutWideState
children: generateControlBar(widget.model, theme), children: generateControlBar(widget.model, theme),
), ),
), ),
_buildRepliedMessage(widget.repliedMessage),
Container( Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 6), padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 6),
constraints: const BoxConstraints(minHeight: 50), constraints: const BoxConstraints(minHeight: 50),

View File

@ -11,12 +11,14 @@ import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/chat_life_cyc
import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_conversation_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';
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
import 'package:tencent_cloud_chat_uikit/ui/constants/history_message_constant.dart'; import 'package:tencent_cloud_chat_uikit/ui/constants/history_message_constant.dart';
import 'package:tencent_cloud_chat_uikit/ui/controller/tim_uikit_chat_controller.dart'; import 'package:tencent_cloud_chat_uikit/ui/controller/tim_uikit_chat_controller.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/frame.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/frame.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/optimize_utils.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/optimize_utils.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/at_member_panel.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/at_member_panel.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_multi_select_panel.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_multi_select_panel.dart';
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_send_file.dart'; import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/tim_uikit_send_file.dart';
@ -50,7 +52,7 @@ class TIMUIKitChat extends StatefulWidget {
/// use for customize avatar /// use for customize avatar
final Widget Function(BuildContext context, V2TimMessage message)? final Widget Function(BuildContext context, V2TimMessage message)?
userAvatarBuilder; userAvatarBuilder;
/// Use for show conversation name. /// Use for show conversation name.
/// This field is not necessary to be provided, when `conversation` is provided, unless you want to cover this field manually. /// This field is not necessary to be provided, when `conversation` is provided, unless you want to cover this field manually.
@ -61,7 +63,7 @@ class TIMUIKitChat extends StatefulWidget {
/// Avatar and name in message reaction secondary tap callback. /// Avatar and name in message reaction secondary tap callback.
final void Function(String userID, TapDownDetails tapDetails)? final void Function(String userID, TapDownDetails tapDetails)?
onSecondaryTapAvatar; onSecondaryTapAvatar;
@Deprecated( @Deprecated(
"Nickname will not shows in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead") "Nickname will not shows in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead")
@ -108,18 +110,23 @@ class TIMUIKitChat extends StatefulWidget {
final TongueItemBuilder? tongueItemBuilder; final TongueItemBuilder? tongueItemBuilder;
/// The `groupAtInfoList` from `V2TimConversation`. /// The `groupAtInfoList` from `V2TimConversation`.
/// This field is not necessary to be provided, when `conversation` is provided, unless you want to cover this field manually. /// This field is not necessary to be provided, when `conversation` is provided,
/// unless you want to cover this field manually.
final List<V2TimGroupAtInfo?>? groupAtInfoList; final List<V2TimGroupAtInfo?>? groupAtInfoList;
/// The configuration for the whole `TIMUIKitChat` widget. /// The configuration for the whole `TIMUIKitChat` widget.
final TIMUIKitChatConfig? config; final TIMUIKitChatConfig? config;
/// The callback for jumping to the page for `TIMUIKitGroupApplicationList` or other pages to deal with enter group application for group administrator manually, in the case of [public group]. /// The callback for jumping to the page for `TIMUIKitGroupApplicationList`
/// or other pages to deal with enter group application for group administrator manually,
/// in the case of [public group].
/// The parameter here is `String groupID` /// The parameter here is `String groupID`
final ValueChanged<String>? onDealWithGroupApplication; final ValueChanged<String>? onDealWithGroupApplication;
/// The builder for abstract messages, normally used in replied message and forward message. /// The generator for the abstract summary preview of a message,
final String Function(V2TimMessage message)? abstractMessageBuilder; /// typically used in replied and forwarded messages.
/// Returns `null` to use the default message summary.
final String? Function(V2TimMessage message)? abstractMessageBuilder;
/// The configuration for tool tips panel, long press messages will show this panel. /// The configuration for tool tips panel, long press messages will show this panel.
final ToolTipsConfig? toolTipsConfig; final ToolTipsConfig? toolTipsConfig;
@ -140,45 +147,45 @@ class TIMUIKitChat extends StatefulWidget {
/// Custom text field /// Custom text field
final Widget Function(BuildContext context)? textFieldBuilder; final Widget Function(BuildContext context)? textFieldBuilder;
TIMUIKitChat( TIMUIKitChat({Key? key,
{Key? key, this.groupID,
this.groupID, required this.conversation,
required this.conversation, this.conversationID,
this.conversationID, this.conversationType,
this.conversationType, this.conversationShowName,
this.conversationShowName, this.abstractMessageBuilder,
this.abstractMessageBuilder, this.onTapAvatar,
this.onTapAvatar, @Deprecated(
@Deprecated( "Nickname will not show in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead") this.showNickName = false,
"Nickname will not show in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead") this.showTotalUnReadCount = false,
this.showNickName = false, this.messageItemBuilder,
this.showTotalUnReadCount = false, @Deprecated(
this.messageItemBuilder, "Please use [extraTipsActionItemBuilder] instead") this.exteraTipsActionItemBuilder,
@Deprecated("Please use [extraTipsActionItemBuilder] instead") this.extraTipsActionItemBuilder,
this.exteraTipsActionItemBuilder, this.draftText,
this.extraTipsActionItemBuilder, this.textFieldHintText,
this.draftText, this.initFindingMsg,
this.textFieldHintText, this.userAvatarBuilder,
this.initFindingMsg, this.appBarConfig,
this.userAvatarBuilder, this.controller,
this.appBarConfig, this.morePanelConfig,
this.controller, this.customStickerPanel,
this.morePanelConfig, this.config = const TIMUIKitChatConfig(),
this.customStickerPanel, this.tongueItemBuilder,
this.config = const TIMUIKitChatConfig(), this.groupAtInfoList,
this.tongueItemBuilder, this.mainHistoryListConfig,
this.groupAtInfoList, this.onDealWithGroupApplication,
this.mainHistoryListConfig, this.toolTipsConfig,
this.onDealWithGroupApplication, this.lifeCycle,
this.toolTipsConfig, this.topFixWidget = const SizedBox(),
this.lifeCycle, this.textFieldBuilder,
this.topFixWidget = const SizedBox(), this.customEmojiStickerList = const [],
this.textFieldBuilder, this.customAppBar,
this.customEmojiStickerList = const [], this.onSecondaryTapAvatar})
this.customAppBar,
this.onSecondaryTapAvatar})
: super(key: key) { : super(key: key) {
startTime = DateTime.now().millisecondsSinceEpoch; startTime = DateTime
.now()
.millisecondsSinceEpoch;
} }
@override @override
@ -188,11 +195,13 @@ class TIMUIKitChat extends StatefulWidget {
class _TUIChatState extends TIMUIKitState<TIMUIKitChat> { class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
TUIChatSeparateViewModel model = TUIChatSeparateViewModel(); TUIChatSeparateViewModel model = TUIChatSeparateViewModel();
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>(); final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
final TUIConversationViewModel conversationViewModel =
serviceLocator<TUIConversationViewModel>();
final TIMUIKitInputTextFieldController textFieldController = final TIMUIKitInputTextFieldController textFieldController =
TIMUIKitInputTextFieldController(); TIMUIKitInputTextFieldController();
bool isInit = false; bool isInit = false;
final TUIChatGlobalModel chatGlobalModel = final TUIChatGlobalModel chatGlobalModel =
serviceLocator<TUIChatGlobalModel>(); serviceLocator<TUIChatGlobalModel>();
bool _dragging = false; bool _dragging = false;
final GlobalKey alignKey = GlobalKey(); final GlobalKey alignKey = GlobalKey();
@ -200,13 +209,19 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
late AutoScrollController autoController = AutoScrollController( late AutoScrollController autoController = AutoScrollController(
viewportBoundaryGetter: () => viewportBoundaryGetter: () =>
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom), Rect.fromLTRB(0, 0, 0, MediaQuery
.of(context)
.padding
.bottom),
axis: Axis.vertical, axis: Axis.vertical,
); );
late AutoScrollController atMemberPanelScroll = AutoScrollController( late AutoScrollController atMemberPanelScroll = AutoScrollController(
viewportBoundaryGetter: () => viewportBoundaryGetter: () =>
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom), Rect.fromLTRB(0, 0, 0, MediaQuery
.of(context)
.padding
.bottom),
axis: Axis.vertical, axis: Axis.vertical,
); );
@ -220,11 +235,16 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
model.onTapAvatar = widget.onTapAvatar; model.onTapAvatar = widget.onTapAvatar;
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
if (kProfileMode) { if (kProfileMode) {
widget.endTime = DateTime.now().millisecondsSinceEpoch; widget.endTime = DateTime
.now()
.millisecondsSinceEpoch;
int timeSpend = widget.endTime - widget.startTime; int timeSpend = widget.endTime - widget.startTime;
print("Page render time:$timeSpend ms"); print("Page render time:$timeSpend ms");
} }
}); });
Future.delayed(const Duration(milliseconds: 500), () {
updateDraft();
});
} }
@override @override
@ -245,8 +265,8 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
model = TUIChatSeparateViewModel(); model = TUIChatSeparateViewModel();
model.abstractMessageBuilder = widget.abstractMessageBuilder; model.abstractMessageBuilder = widget.abstractMessageBuilder;
model.onTapAvatar = widget.onTapAvatar; model.onTapAvatar = widget.onTapAvatar;
textFieldController.requestFocus();
Future.delayed(const Duration(milliseconds: 50), () { Future.delayed(const Duration(milliseconds: 50), () {
updateDraft();
textFieldController.requestFocus(); textFieldController.requestFocus();
try { try {
autoController.jumpTo( autoController.jumpTo(
@ -261,6 +281,22 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
} }
} }
updateDraft() async {
final isTopic = widget.conversation.conversationID.contains("@TOPIC#");
if (isTopic) {
final topicInfoList = await TencentImSDKPlugin.v2TIMManager
.getGroupManager()
.getTopicInfoList(
groupID: widget.groupID!,
topicIDList: [widget.conversation.conversationID]);
final topicInfo = topicInfoList.data?.first.topicInfo;
final draftText = topicInfo?.draftText;
if (TencentUtils.checkString(draftText) != null) {
textFieldController.setTextField(draftText!);
}
}
}
Widget _renderJoinGroupApplication(int amount, TUITheme theme) { Widget _renderJoinGroupApplication(int amount, TUITheme theme) {
String option1 = amount.toString(); String option1 = amount.toString();
return Container( return Container(
@ -318,7 +354,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final TUITheme theme = value.theme; final TUITheme theme = value.theme;
final closePanel = final closePanel =
OptimizeUtils.throttle((_) => textFieldController.hideAllPanel(), 60); OptimizeUtils.throttle((_) => textFieldController.hideAllPanel(), 60);
final isBuild = isInit; final isBuild = isInit;
isInit = true; isInit = true;
@ -337,7 +373,7 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
], ],
builder: (context, model, w) { builder: (context, model, w) {
final TUIChatGlobalModel chatGlobalModel = final TUIChatGlobalModel chatGlobalModel =
Provider.of<TUIChatGlobalModel>(context, listen: true); Provider.of<TUIChatGlobalModel>(context, listen: true);
widget.controller?.model = model; widget.controller?.model = model;
widget.controller?.textFieldController = textFieldController; widget.controller?.textFieldController = textFieldController;
@ -347,13 +383,13 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
widget.onDealWithGroupApplication != null) { widget.onDealWithGroupApplication != null) {
filteredApplicationList = filteredApplicationList =
chatGlobalModel.groupApplicationList.where((item) { chatGlobalModel.groupApplicationList.where((item) {
return (item.groupID == widget.conversationID) && return (item.groupID == widget.conversationID) &&
item.handleStatus == 0; item.handleStatus == 0;
}).toList(); }).toList();
} }
final TUIGroupListenerModel groupListenerModel = final TUIGroupListenerModel groupListenerModel =
Provider.of<TUIGroupListenerModel>(context, listen: true); Provider.of<TUIGroupListenerModel>(context, listen: true);
final NeedUpdate? needUpdate = groupListenerModel.needUpdate; final NeedUpdate? needUpdate = groupListenerModel.needUpdate;
if (needUpdate != null && if (needUpdate != null &&
needUpdate.groupID == widget.conversationID) { needUpdate.groupID == widget.conversationID) {
@ -379,13 +415,13 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
appBar: (widget.customAppBar == null) appBar: (widget.customAppBar == null)
? TIMUIKitAppBar( ? TIMUIKitAppBar(
showTotalUnReadCount: widget.showTotalUnReadCount, showTotalUnReadCount: widget.showTotalUnReadCount,
config: widget.appBarConfig, config: widget.appBarConfig,
conversationShowName: _getTitle(), conversationShowName: _getTitle(),
conversationID: _getConvID(), conversationID: _getConvID(),
showC2cMessageEditStatus: showC2cMessageEditStatus:
widget.config?.showC2cMessageEditStatus ?? true, widget.config?.showC2cMessageEditStatus ?? true,
) )
: null, : null,
body: DropTarget( body: DropTarget(
onDragDone: (detail) { onDragDone: (detail) {
@ -421,90 +457,100 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
if (widget.topFixWidget != null) widget.topFixWidget!, if (widget.topFixWidget != null) widget.topFixWidget!,
Expanded( Expanded(
child: Container( child: Container(
color: theme.chatBgColor, color: theme.chatBgColor,
child: Align( child: Align(
key: alignKey, key: alignKey,
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: Listener( child: Listener(
onPointerMove: closePanel, onPointerMove: closePanel,
child: TIMUIKitHistoryMessageListContainer( child: TIMUIKitHistoryMessageListContainer(
conversation: widget.conversation, conversation: widget.conversation,
textFieldController: textFieldController, textFieldController: textFieldController,
customEmojiStickerList: customEmojiStickerList:
widget.customEmojiStickerList, widget.customEmojiStickerList,
isUseDefaultEmoji: isUseDefaultEmoji:
widget.config!.isUseDefaultEmoji, widget.config!.isUseDefaultEmoji,
key: listContainerKey, key: listContainerKey,
isAllowScroll: true, isAllowScroll: true,
userAvatarBuilder: widget.userAvatarBuilder, userAvatarBuilder: widget
toolTipsConfig: widget.toolTipsConfig, .userAvatarBuilder,
groupAtInfoList: widget.groupAtInfoList, toolTipsConfig: widget.toolTipsConfig,
tongueItemBuilder: widget.tongueItemBuilder, groupAtInfoList: widget.groupAtInfoList,
onLongPressForOthersHeadPortrait: tongueItemBuilder: widget
(String? userId, String? nickName) { .tongueItemBuilder,
textFieldController.longPressToAt( onLongPressForOthersHeadPortrait:
nickName, userId); (String? userId, String? nickName) {
}, textFieldController.longPressToAt(
mainHistoryListConfig: nickName, userId);
},
mainHistoryListConfig:
widget.mainHistoryListConfig, widget.mainHistoryListConfig,
initFindingMsg: widget.initFindingMsg, initFindingMsg: widget.initFindingMsg,
extraTipsActionItemBuilder: extraTipsActionItemBuilder:
widget.extraTipsActionItemBuilder ?? widget.extraTipsActionItemBuilder ??
widget.exteraTipsActionItemBuilder, widget.exteraTipsActionItemBuilder,
conversationType: _getConvType(), conversationType: _getConvType(),
scrollController: autoController, scrollController: autoController,
onSecondaryTapAvatar: onSecondaryTapAvatar:
widget.onSecondaryTapAvatar, widget.onSecondaryTapAvatar,
onTapAvatar: widget.onTapAvatar, onTapAvatar: widget.onTapAvatar,
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
showNickName: widget.showNickName, showNickName: widget.showNickName,
messageItemBuilder: messageItemBuilder:
widget.messageItemBuilder, widget.messageItemBuilder,
conversationID: _getConvID(), conversationID: _getConvID(),
), ),
)), )),
)), )),
Selector<TUIChatSeparateViewModel, bool>( Selector<TUIChatSeparateViewModel, bool>(
builder: (context, value, child) { builder: (context, value, child) {
return value return value
? MultiSelectPanel( ? MultiSelectPanel(
conversationType: _getConvType(), conversationType: _getConvType(),
) )
: (widget.textFieldBuilder != null : (widget.textFieldBuilder != null
? widget.textFieldBuilder!(context) ? widget.textFieldBuilder!(context)
: TIMUIKitInputTextField( : TIMUIKitInputTextField(
atMemberPanelScroll: groupID: widget.groupID,
atMemberPanelScroll, atMemberPanelScroll:
groupType: atMemberPanelScroll,
widget.conversation.groupType, groupType:
currentConversation: widget.conversation.groupType,
widget.conversation, currentConversation:
model: model, widget.conversation,
controller: textFieldController, model: model,
customEmojiStickerList: controller: textFieldController,
widget.customEmojiStickerList, customEmojiStickerList:
isUseDefaultEmoji: widget.customEmojiStickerList,
widget.config!.isUseDefaultEmoji, isUseDefaultEmoji:
customStickerPanel: widget.config!.isUseDefaultEmoji,
widget.customStickerPanel, customStickerPanel:
morePanelConfig: widget.customStickerPanel,
widget.morePanelConfig, morePanelConfig:
scrollController: autoController, widget.morePanelConfig,
conversationID: _getConvID(), scrollController: autoController,
conversationType: _getConvType(), conversationID: _getConvID(),
initText: widget.draftText ?? conversationType: _getConvType(),
widget.conversation.draftText, initText: TencentUtils.checkString(
hintText: widget.textFieldHintText, widget.draftText) ?? (PlatformUtils().isWeb
showMorePanel: widget.config ? TencentUtils.checkString(
?.isAllowShowMorePanel ?? conversationViewModel.getWebDraft(
true, conversationID: widget.conversation
showSendAudio: widget.config .conversationID))
?.isAllowSoundMessage ?? :
true, TencentUtils.checkString(widget
showSendEmoji: widget .conversation.draftText)),
.config?.isAllowEmojiPanel ?? hintText: widget.textFieldHintText,
true, showMorePanel: widget.config
)); ?.isAllowShowMorePanel ??
true,
showSendAudio: widget.config
?.isAllowSoundMessage ??
true,
showSendEmoji: widget
.config?.isAllowEmojiPanel ??
true,
));
}, },
selector: (c, model) { selector: (c, model) {
return model.isMultiSelect; return model.isMultiSelect;
@ -533,13 +579,13 @@ class TIMUIKitChatProviderScope extends StatelessWidget {
final TUIChatGlobalModel globalModel = serviceLocator<TUIChatGlobalModel>(); final TUIChatGlobalModel globalModel = serviceLocator<TUIChatGlobalModel>();
TUIChatSeparateViewModel? model; TUIChatSeparateViewModel? model;
final TUIGroupListenerModel groupListenerModel = final TUIGroupListenerModel groupListenerModel =
serviceLocator<TUIGroupListenerModel>(); serviceLocator<TUIGroupListenerModel>();
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>(); final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
final Widget? child; final Widget? child;
/// You could get the model from here, and transfer it to other widget from TUIKit. /// You could get the model from here, and transfer it to other widget from TUIKit.
final Widget Function(BuildContext, TUIChatSeparateViewModel, Widget?) final Widget Function(BuildContext, TUIChatSeparateViewModel, Widget?)
builder; builder;
final List<SingleChildWidget>? providers; final List<SingleChildWidget>? providers;
/// `TIMUIKitChatController` needs to be provided if you use it outside. /// `TIMUIKitChatController` needs to be provided if you use it outside.
@ -566,21 +612,20 @@ class TIMUIKitChatProviderScope extends StatelessWidget {
final AutoScrollController? scrollController; final AutoScrollController? scrollController;
TIMUIKitChatProviderScope( TIMUIKitChatProviderScope({Key? key,
{Key? key, this.child,
this.child, this.providers,
this.providers, this.textFieldController,
this.textFieldController, required this.builder,
required this.builder, this.model,
this.model, this.groupID,
this.groupID, this.isBuild,
this.isBuild, required this.conversationID,
required this.conversationID, required this.conversationType,
required this.conversationType, this.controller,
this.controller, this.config,
this.config, this.lifeCycle,
this.lifeCycle, this.scrollController})
this.scrollController})
: super(key: key) { : super(key: key) {
if (isBuild ?? false) { if (isBuild ?? false) {
return; return;
@ -596,7 +641,7 @@ class TIMUIKitChatProviderScope extends StatelessWidget {
model?.initForEachConversation( model?.initForEachConversation(
conversationType, conversationType,
conversationID, conversationID,
(String value) { (String value) {
textFieldController?.textEditingController?.text = value; textFieldController?.textEditingController?.text = value;
}, },
groupID: groupID, groupID: groupID,

View File

@ -185,6 +185,12 @@ class TIMUIKitChatConfig {
/// Define the lines in the text message input field on Desktop. /// Define the lines in the text message input field on Desktop.
final int desktopMessageInputFieldLines; final int desktopMessageInputFieldLines;
/// Specifies whether to use the draft feature on the Web, as the Chat SDK does not support this functionality.
/// If enabled, draft data will be stored in TUIKit's memory.
/// Note that the draft text will be lost upon refreshing the website.
/// [Default]: true.
final bool isUseDraftOnWeb;
const TIMUIKitChatConfig( const TIMUIKitChatConfig(
{this.onTapLink, {this.onTapLink,
this.timeDividerConfig, this.timeDividerConfig,
@ -203,7 +209,7 @@ class TIMUIKitChatConfig {
this.isShowSelfNameInGroup = false, this.isShowSelfNameInGroup = false,
this.offlinePushInfo, this.offlinePushInfo,
@Deprecated("Please use [isShowGroupReadingStatus] instead") @Deprecated("Please use [isShowGroupReadingStatus] instead")
this.isShowGroupMessageReadReceipt = true, this.isShowGroupMessageReadReceipt = true,
this.upperRecallTime = 120, this.upperRecallTime = 120,
this.isShowOthersNameInGroup = true, this.isShowOthersNameInGroup = true,
this.urlPreviewType = UrlPreviewType.onlyHyperlink, this.urlPreviewType = UrlPreviewType.onlyHyperlink,
@ -213,13 +219,14 @@ class TIMUIKitChatConfig {
this.notificationIOSSound = "", this.notificationIOSSound = "",
this.isAllowSoundMessage = true, this.isAllowSoundMessage = true,
@Deprecated("Please use [groupReadReceiptPermissionList] instead") @Deprecated("Please use [groupReadReceiptPermissionList] instead")
this.groupReadReceiptPermisionList, this.groupReadReceiptPermisionList,
this.groupReadReceiptPermissionList, this.groupReadReceiptPermissionList,
this.isAllowEmojiPanel = true, this.isAllowEmojiPanel = true,
this.isAllowShowMorePanel = true, this.isAllowShowMorePanel = true,
this.isShowReadingStatus = true, this.isShowReadingStatus = true,
this.desktopControlBarConfig, this.desktopControlBarConfig,
this.isAllowLongPressMessage = true, this.isAllowLongPressMessage = true,
this.isUseDraftOnWeb = true,
this.isAllowClickAvatar = true, this.isAllowClickAvatar = true,
this.isEnableTextSelection, this.isEnableTextSelection,
this.additionalDesktopMessageHoverBarItem, this.additionalDesktopMessageHoverBarItem,

View File

@ -1,3 +1,5 @@
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
class MessageRepliedData { class MessageRepliedData {
late String messageAbstract; late String messageAbstract;
late String messageSender; late String messageSender;
@ -10,6 +12,42 @@ class MessageRepliedData {
} }
} }
class RepliedMessageAbstract {
final int? elemType;
final String? msgID;
final int? timestamp;
final String? seq;
final String? summary;
RepliedMessageAbstract(
{this.elemType, this.msgID, this.timestamp, this.seq, this.summary});
// fromJson constructor
RepliedMessageAbstract.fromJson(Map<String, dynamic> json)
: elemType = json['elemType'],
msgID = json['msgID'],
timestamp = json['timestamp'],
seq = json['seq'],
summary = json['summary'];
// toJson function
Map<String, dynamic> toJson() {
return {
'summary': summary,
'elemType': elemType,
'msgID': msgID,
'timestamp': timestamp,
'seq': seq,
};
}
// isNotEmpty method
bool get isNotEmpty =>
TencentUtils.checkString(msgID) != null &&
TencentUtils.checkString(timestamp.toString()) != null &&
TencentUtils.checkString(seq) != null;
}
class CloudCustomData { class CloudCustomData {
Map<String, dynamic>? messageReply; Map<String, dynamic>? messageReply;
Map<String, dynamic>? messageReaction = {}; Map<String, dynamic>? messageReaction = {};

View File

@ -17,7 +17,8 @@ class LinkPreviewEntry {
return isMarkdown return isMarkdown
? LinkTextMarkdown( ? LinkTextMarkdown(
isEnableTextSelection: isEnableTextSelection, isEnableTextSelection: isEnableTextSelection,
messageText: replaceSingleNewlineWithTwo(messageText), messageText: addSpaceAfterLeftBracket(
addSpaceBeforeHttp(replaceSingleNewlineWithTwo(messageText))),
style: style, style: style,
onLinkTap: onLinkTap) onLinkTap: onLinkTap)
: LinkText( : LinkText(
@ -30,10 +31,27 @@ class LinkPreviewEntry {
}; };
} }
static String addSpaceAfterLeftBracket(String inputText) {
return inputText.splitMapJoin(
RegExp(r'<\w+[^<>]*>'),
onMatch: (match) {
return match.group(0)!.replaceFirst('<', '< ');
},
onNonMatch: (text) => text,
);
}
static String replaceSingleNewlineWithTwo(String inputText) { static String replaceSingleNewlineWithTwo(String inputText) {
return inputText.replaceAllMapped( return inputText.split('\n').join('\n\n');
RegExp(r'(?<!\n)\n(?!\n)'), }
(match) => '\n\n',
static String addSpaceBeforeHttp(String inputText) {
return inputText.splitMapJoin(
RegExp(r'http'),
onMatch: (match) {
return ' http';
},
onNonMatch: (text) => text,
); );
} }

View File

@ -8,6 +8,7 @@ import 'package:flutter_markdown/flutter_markdown.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';
import 'package:markdown/markdown.dart' as md;
class LinkTextMarkdown extends TIMStatelessWidget { class LinkTextMarkdown extends TIMStatelessWidget {
/// Callback for when link is tapped /// Callback for when link is tapped
@ -40,6 +41,7 @@ class LinkTextMarkdown extends TIMStatelessWidget {
.copyWith( .copyWith(
a: TextStyle(color: LinkUtils.hexToColor("015fff")), a: TextStyle(color: LinkUtils.hexToColor("015fff")),
), ),
extensionSet: md.ExtensionSet.gitHubWeb,
onTapLink: ( onTapLink: (
String link, String link,
String? href, String? href,
@ -155,3 +157,20 @@ class LinkText extends TIMStatelessWidget {
)); ));
} }
} }
class TextBuilder extends MarkdownElementBuilder {
@override
Widget? visitText(md.Text text, TextStyle? preferredStyle) {
return Text(text.textContent);
}
}
class RawHtmlSyntax extends md.InlineSyntax {
RawHtmlSyntax() : super(r'<.+?>');
@override
bool onMatch(md.InlineParser parser, Match match) {
parser.addNode(md.Text(match[0]!));
return true;
}
}

View File

@ -7,6 +7,7 @@ import 'package:tencent_cloud_chat_uikit/ui/widgets/drag_widget.dart';
class TUIKitWidePopup { class TUIKitWidePopup {
static OverlayEntry? entry; static OverlayEntry? entry;
static bool isShow = false;
static showSecondaryConfirmDialog({ static showSecondaryConfirmDialog({
required TUIKitWideModalOperationKey operationKey, required TUIKitWideModalOperationKey operationKey,
@ -17,7 +18,7 @@ class TUIKitWidePopup {
VoidCallback? onCancel, VoidCallback? onCancel,
}) { }) {
return TUIKitWidePopup.showPopupWindow( return TUIKitWidePopup.showPopupWindow(
operationKey: operationKey, operationKey: operationKey,
context: context, context: context,
isDarkBackground: false, isDarkBackground: false,
onCancel: onCancel, onCancel: onCancel,
@ -56,37 +57,205 @@ class TUIKitWidePopup {
VoidCallback? onConfirm, VoidCallback? onConfirm,
VoidCallback? onCancel, VoidCallback? onCancel,
}) async { }) async {
if (isShow) {
return;
}
isShow = true;
final TUISelfInfoViewModel selfInfoViewModel = final TUISelfInfoViewModel selfInfoViewModel =
serviceLocator<TUISelfInfoViewModel>(); serviceLocator<TUISelfInfoViewModel>();
if(selfInfoViewModel.globalConfig?.showDesktopModalFunc != null){ if (selfInfoViewModel.globalConfig?.showDesktopModalFunc != null) {
final res = await selfInfoViewModel.globalConfig!.showDesktopModalFunc!( final res = await selfInfoViewModel.globalConfig!.showDesktopModalFunc!(
operationKey, operationKey,
context, context,
child, child,
theme, theme,
width, width,
height, height,
offset, offset,
initText, initText,
borderRadius, borderRadius,
isDarkBackground, isDarkBackground,
title, title,
onSubmit, onSubmit,
submitWidget, submitWidget,
onConfirm, onConfirm,
onCancel onCancel);
);
if(res == true){ if (res == true) {
return; return;
} }
} }
final isUseMaterialAlert = (offset == null);
final Widget contentWidget = Container(
width: width,
height: height,
decoration: BoxDecoration(
borderRadius:
borderRadius ?? const BorderRadius.all(Radius.circular(16)),
color: theme?.wideBackgroundColor ?? const Color(0xFFffffff),
border: isDarkBackground
? Border.all(
width: 2,
color: theme?.weakBackgroundColor ?? const Color(0xFFbebebe),
)
: null,
boxShadow: (isDarkBackground || isUseMaterialAlert)
? null
: const [
BoxShadow(
color: Color(0xFFbebebe),
offset: Offset(3, 3),
blurRadius: 10,
spreadRadius: 1,
),
],
),
child: Column(
children: [
if (title != null)
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: hexToColor("f5f6f7"),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Text(
title,
style: TextStyle(
fontSize: 18,
color: theme?.darkTextColor ?? const Color(0xFF444444)),
),
InkWell(
onTap: () {
if (onSubmit != null) {
onSubmit();
}
isShow = false;
if (offset == null) {
Navigator.pop(context);
} else {
entry?.remove();
entry = null;
}
},
child: onSubmit != null
? (submitWidget ?? const Icon(Icons.check))
: const Icon(Icons.close),
)
],
),
),
if (title != null)
SizedBox(
height: 1,
child: Container(
color: theme?.weakDividerColor ?? const Color(0xFFE5E6E9),
),
),
if (height != null && width != null)
Expanded(child: child(() {
isShow = false;
if (isUseMaterialAlert) {
Navigator.pop(context);
} else {
entry?.remove();
entry = null;
}
})),
if (height == null || width == null)
child(() {
isShow = false;
if (isUseMaterialAlert) {
Navigator.pop(context);
} else {
entry?.remove();
entry = null;
}
}),
if (onCancel != null || onConfirm != null)
Container(
padding: const EdgeInsets.only(bottom: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (onCancel != null)
Container(
margin: const EdgeInsets.only(right: 16),
child: OutlinedButton(
onPressed: () {
isShow = false;
if (isUseMaterialAlert) {
Navigator.pop(context);
} else {
entry?.remove();
entry = null;
}
onCancel();
},
child: Text(
TIM_t("取消"),
style: TextStyle(
color: theme?.weakTextColor ?? Colors.black),
)),
),
if (onConfirm != null)
Container(
margin: const EdgeInsets.only(right: 16),
child: ElevatedButton(
onPressed: () {
isShow = false;
if (isUseMaterialAlert) {
Navigator.pop(context);
} else {
entry?.remove();
entry = null;
}
onConfirm();
},
child: Text(
TIM_t("确定"),
style: TextStyle(color: theme?.primaryColor),
)),
),
],
),
)
],
),
);
if (isUseMaterialAlert) {
return showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return WillPopScope(
child: AlertDialog(
backgroundColor: Colors.transparent,
titlePadding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
contentPadding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
content: contentWidget,
),
onWillPop: () {
return Future.value(false);
});
});
}
if (entry != null) { if (entry != null) {
return; return;
} }
entry = OverlayEntry(builder: (BuildContext context) { entry = OverlayEntry(builder: (BuildContext context) {
return Material( return Material(
color: Colors.transparent, color: Colors.transparent,
@ -100,133 +269,13 @@ class TUIKitWidePopup {
}, },
initOffset: offset ?? initOffset: offset ??
(width != null && height != null (width != null && height != null
? Offset(MediaQuery.of(context).size.width * 0.5 - width / 2, ? Offset(
MediaQuery.of(context).size.height * 0.5 - height / 2) MediaQuery.of(context).size.width * 0.5 - width / 2,
MediaQuery.of(context).size.height * 0.5 - height / 2)
: null), : null),
child: Container( child: contentWidget),
width: width,
height: height,
decoration: BoxDecoration(
borderRadius:
borderRadius ?? const BorderRadius.all(Radius.circular(16)),
color: theme?.wideBackgroundColor ?? const Color(0xFFffffff),
border: isDarkBackground
? Border.all(
width: 2,
color:
theme?.weakBackgroundColor ?? const Color(0xFFbebebe),
)
: null,
boxShadow: isDarkBackground
? null
: const [
BoxShadow(
color: Color(0xFFbebebe),
offset: Offset(3, 3),
blurRadius: 10,
spreadRadius: 1,
),
],
),
child: Column(
children: [
if (title != null)
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: hexToColor("f5f6f7"),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
Text(
title,
style: TextStyle(
fontSize: 18,
color: theme?.darkTextColor ??
const Color(0xFF444444)),
),
InkWell(
onTap: () {
if (onSubmit != null) {
onSubmit();
}
entry?.remove();
entry = null;
},
child: onSubmit != null
? (submitWidget ?? const Icon(Icons.check))
: const Icon(Icons.close),
)
],
),
),
if (title != null)
SizedBox(
height: 1,
child: Container(
color: theme?.weakDividerColor ?? const Color(0xFFE5E6E9),
),
),
if (height != null && width != null)
Expanded(child: child(() {
entry?.remove();
entry = null;
})),
if (height == null || width == null)
child(() {
entry?.remove();
entry = null;
}),
if (onCancel != null || onConfirm != null)
Container(
padding: const EdgeInsets.only(bottom: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (onCancel != null)
Container(
margin: const EdgeInsets.only(right: 16),
child: OutlinedButton(
onPressed: () {
entry?.remove();
entry = null;
onCancel();
},
child: Text(
TIM_t("取消"),
style: TextStyle(
color:
theme?.weakTextColor ?? Colors.black),
)),
),
if (onConfirm != null)
Container(
margin: const EdgeInsets.only(right: 16),
child: ElevatedButton(
onPressed: () {
entry?.remove();
entry = null;
onConfirm();
},
child: Text(
TIM_t("确定"),
style: TextStyle(color: theme?.primaryColor),
)),
),
],
),
)
],
),
)),
); );
}); });
Overlay.of(context).insert(entry!); Overlay.of(context).insert(entry!);
} }
} }

View File

@ -1,6 +1,6 @@
name: tencent_cloud_chat_uikit name: tencent_cloud_chat_uikit
description: A powerful chat UI component library and business logic for Tencent Cloud Chat, creating seamless in-app chat modules for delightful user experiences. description: A powerful chat UI component library and business logic for Tencent Cloud Chat, creating seamless in-app chat modules for delightful user experiences.
version: 2.1.0+2 version: 2.1.1
homepage: https://www.tencentcloud.com/products/im?from=pub homepage: https://www.tencentcloud.com/products/im?from=pub
repository: https://github.com/TencentCloud/tc-chat-uikit-flutter repository: https://github.com/TencentCloud/tc-chat-uikit-flutter
documentation: https://comm.qq.com/im/doc/flutter/en/TUIKit/readme.html documentation: https://comm.qq.com/im/doc/flutter/en/TUIKit/readme.html