tencent_cloud_chat_uikit source code update to version 4.0.0.

This commit is contained in:
vinsonswang 2024-12-17 11:07:49 +08:00
parent 763cf3f750
commit 7a2d31ea71
19 changed files with 788 additions and 520 deletions

View File

@ -1,3 +1,13 @@
# 4.0.0
## Breaking changes
* Upgraded the plugin tim_ui_kit_sticker_plugin to 4.0.0, no longer supports QQ emoji and unicode emoji.
* Delete the useQQStickerPackage and unicodeEmojiList parameters in StickerPanelConfig.
* Delete the isUseDefaultEmoji parameter in TIMUIKitChatConfig.
* Delete the isUseDefaultEmoji parameter in each widget.
## Bug Fixes
* Solve the problem that showReplyMessage and showForwardMessage in ToolTipsConfig do not take effect after being set to false.
# 3.1.0+2 # 3.1.0+2
* Replace the flutter_slidable library with flutter_slidable_plus_plus to solve the compatibility issue of flutter 3.27.0 version. * Replace the flutter_slidable library with flutter_slidable_plus_plus to solve the compatibility issue of flutter 3.27.0 version.

View File

@ -271,9 +271,6 @@ class TIMUIKitHistoryMessageListItem extends StatefulWidget {
// open MessageReaction // open MessageReaction
final bool? isUseMessageReaction; final bool? isUseMessageReaction;
/// Whether to use the default emoji
final bool isUseDefaultEmoji;
final List<CustomEmojiFaceData> customEmojiStickerList; final List<CustomEmojiFaceData> customEmojiStickerList;
final V2TimGroupMemberFullInfo? groupMemberInfo; final V2TimGroupMemberFullInfo? groupMemberInfo;
@ -309,7 +306,6 @@ class TIMUIKitHistoryMessageListItem extends StatefulWidget {
this.topRowBuilder, this.topRowBuilder,
this.isUseMessageReaction, this.isUseMessageReaction,
this.bottomRowBuilder, this.bottomRowBuilder,
this.isUseDefaultEmoji = false,
this.customEmojiStickerList = const [], this.customEmojiStickerList = const [],
this.textFieldController, this.textFieldController,
this.onSecondaryTapForOthersPortrait, this.onSecondaryTapForOthersPortrait,
@ -502,7 +498,6 @@ class _TIMUIKItHistoryMessageListItemState
fontStyle: widget.themeData?.messageTextStyle, fontStyle: widget.themeData?.messageTextStyle,
backgroundColor: widget.themeData?.messageBackgroundColor, backgroundColor: widget.themeData?.messageBackgroundColor,
textPadding: widget.textPadding, textPadding: widget.textPadding,
isUseDefaultEmoji: widget.isUseDefaultEmoji,
customEmojiStickerList: widget.customEmojiStickerList, customEmojiStickerList: widget.customEmojiStickerList,
chatModel: model, chatModel: model,
isShowMessageReaction: widget.isUseMessageReaction, isShowMessageReaction: widget.isUseMessageReaction,
@ -527,7 +522,6 @@ class _TIMUIKItHistoryMessageListItemState
backgroundColor: widget.themeData?.messageBackgroundColor, backgroundColor: widget.themeData?.messageBackgroundColor,
textPadding: widget.textPadding, textPadding: widget.textPadding,
isShowMessageReaction: widget.isUseMessageReaction, isShowMessageReaction: widget.isUseMessageReaction,
isUseDefaultEmoji: widget.isUseDefaultEmoji,
customEmojiStickerList: widget.customEmojiStickerList, customEmojiStickerList: widget.customEmojiStickerList,
); );
case MessageElemType.V2TIM_ELEM_TYPE_FACE: case MessageElemType.V2TIM_ELEM_TYPE_FACE:
@ -888,17 +882,23 @@ class _TIMUIKItHistoryMessageListItemState
} }
} }
if (widget.message.status != MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) { //
widget.toolTipsConfig?.showReplyMessage = true; if ((widget.toolTipsConfig?.showReplyMessage ?? true)) {
} else { if (widget.message.status != MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) {
widget.toolTipsConfig?.showReplyMessage = false; widget.toolTipsConfig?.showReplyMessage = true;
} else {
widget.toolTipsConfig?.showReplyMessage = false;
}
} }
if (widget.message.status != MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL && //
!(widget.message.hasRiskContent ?? false)) { if ((widget.toolTipsConfig?.showForwardMessage ?? true)) {
widget.toolTipsConfig?.showForwardMessage = true; if (widget.message.status != MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL &&
} else { !(widget.message.hasRiskContent ?? false)) {
widget.toolTipsConfig?.showForwardMessage = false; widget.toolTipsConfig?.showForwardMessage = true;
} else {
widget.toolTipsConfig?.showForwardMessage = false;
}
} }
tooltip = SuperTooltip( tooltip = SuperTooltip(
@ -1561,7 +1561,6 @@ class _TIMUIKItHistoryMessageListItemState
), ),
TIMUIKitTextTranslationElem( TIMUIKitTextTranslationElem(
message: message, message: message,
isUseDefaultEmoji: widget.isUseDefaultEmoji,
customEmojiStickerList: customEmojiStickerList:
widget.customEmojiStickerList, widget.customEmojiStickerList,
isFromSelf: message.isSelf ?? true, isFromSelf: message.isSelf ?? true,

View File

@ -68,9 +68,6 @@ class TIMUIKitHistoryMessageListContainer extends StatefulWidget {
/// tool tips panel configuration, long press message will show tool tips panel /// tool tips panel configuration, long press message will show tool tips panel
final ToolTipsConfig? toolTipsConfig; final ToolTipsConfig? toolTipsConfig;
/// Whether to use the default emoji
final bool isUseDefaultEmoji;
final List<CustomEmojiFaceData> customEmojiStickerList; final List<CustomEmojiFaceData> customEmojiStickerList;
final bool isAllowScroll; final bool isAllowScroll;
@ -105,7 +102,6 @@ class TIMUIKitHistoryMessageListContainer extends StatefulWidget {
this.initFindingMsg, this.initFindingMsg,
this.mainHistoryListConfig, this.mainHistoryListConfig,
this.toolTipsConfig, this.toolTipsConfig,
this.isUseDefaultEmoji = false,
this.customEmojiStickerList = const [], this.customEmojiStickerList = const [],
this.textFieldController, this.textFieldController,
required this.conversation, required this.conversation,
@ -131,10 +127,11 @@ class _TIMUIKitHistoryMessageListContainerState
if ((direction == LoadDirection.previous) || if ((direction == LoadDirection.previous) ||
(direction == LoadDirection.latest && model.haveMoreLatestData)) { (direction == LoadDirection.latest && model.haveMoreLatestData)) {
return await model.loadChatRecord( return await model.loadChatRecord(
direction: direction, direction: direction,
count: count ?? (kIsWeb ? 15 : HistoryMessageDartConstant.getCount), count: count ?? (kIsWeb ? 15 : HistoryMessageDartConstant.getCount),
lastMsgID: lastMsgID, lastMsgID: lastMsgID,
lastMsgSeq: lastSeq ?? -1,); lastMsgSeq: lastSeq ?? -1,
);
} else { } else {
return false; return false;
} }
@ -182,7 +179,6 @@ class _TIMUIKitHistoryMessageListContainerState
textFieldController: widget.textFieldController, textFieldController: widget.textFieldController,
userAvatarBuilder: widget.userAvatarBuilder, userAvatarBuilder: widget.userAvatarBuilder,
customEmojiStickerList: widget.customEmojiStickerList, customEmojiStickerList: widget.customEmojiStickerList,
isUseDefaultEmoji: widget.isUseDefaultEmoji,
topRowBuilder: _getTopRowBuilder(model), topRowBuilder: _getTopRowBuilder(model),
onScrollToIndex: _historyMessageListController.scrollToIndex, onScrollToIndex: _historyMessageListController.scrollToIndex,
onScrollToIndexBegin: onScrollToIndexBegin:
@ -206,7 +202,8 @@ class _TIMUIKitHistoryMessageListContainerState
tongueItemBuilder: widget.tongueItemBuilder, tongueItemBuilder: widget.tongueItemBuilder,
initFindingMsg: widget.initFindingMsg, initFindingMsg: widget.initFindingMsg,
messageList: messageList, messageList: messageList,
onLoadMore: (String? a, LoadDirection direction, [int? b, int? lastSeq]) async { onLoadMore: (String? a, LoadDirection direction,
[int? b, int? lastSeq]) async {
return await requestForData(a, direction, model, b, lastSeq); return await requestForData(a, direction, model, b, lastSeq);
}, },
); );

View File

@ -180,7 +180,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
} }
File f = File(savePath); File f = File(savePath);
if (f.existsSync()) { if (f.existsSync()) {
var result = await ImageGallerySaver.saveFile(savePath); var result = await ImageGallerySaverPlus.saveFile(savePath);
if (PlatformUtils().isIOS) { if (PlatformUtils().isIOS) {
if (result['isSuccess']) { if (result['isSuccess']) {
@ -218,7 +218,7 @@ class _TIMUIKitImageElem extends TIMUIKitState<TIMUIKitImageElem> {
return; return;
} }
var result = await ImageGallerySaver.saveFile(imageUrl); var result = await ImageGallerySaverPlus.saveFile(imageUrl);
if (PlatformUtils().isIOS) { if (PlatformUtils().isIOS) {
if (result['isSuccess']) { if (result['isSuccess']) {

View File

@ -37,7 +37,6 @@ class TIMUIKitReplyElem extends StatefulWidget {
final EdgeInsetsGeometry? textPadding; final EdgeInsetsGeometry? textPadding;
final TUIChatSeparateViewModel chatModel; final TUIChatSeparateViewModel chatModel;
final bool? isShowMessageReaction; final bool? isShowMessageReaction;
final bool isUseDefaultEmoji;
final List<CustomEmojiFaceData> customEmojiStickerList; final List<CustomEmojiFaceData> customEmojiStickerList;
const TIMUIKitReplyElem({ const TIMUIKitReplyElem({
@ -51,7 +50,6 @@ class TIMUIKitReplyElem extends StatefulWidget {
this.isShowMessageReaction, this.isShowMessageReaction,
this.backgroundColor, this.backgroundColor,
this.textPadding, this.textPadding,
this.isUseDefaultEmoji = false,
this.customEmojiStickerList = const [], this.customEmojiStickerList = const [],
required this.chatModel, required this.chatModel,
}) : super(key: key); }) : super(key: key);
@ -94,7 +92,7 @@ class _TIMUIKitReplyElemState extends TIMUIKitState<TIMUIKitReplyElem> {
} }
final messageID = cloudCustomData.messageID; final messageID = cloudCustomData.messageID;
if(PlatformUtils().isWeb){ if (PlatformUtils().isWeb) {
return; return;
} }
V2TimMessage? message = await widget.chatModel.findMessage(messageID); V2TimMessage? message = await widget.chatModel.findMessage(messageID);
@ -289,12 +287,12 @@ class _TIMUIKitReplyElemState extends TIMUIKitState<TIMUIKitReplyElem> {
} }
void _jumpToRawMsg() { void _jumpToRawMsg() {
if (rawMessage?.status != MessageStatus.V2TIM_MSG_STATUS_LOCAL_REVOKED && rawMessage?.timestamp != null) { if (rawMessage?.status != MessageStatus.V2TIM_MSG_STATUS_LOCAL_REVOKED &&
rawMessage?.timestamp != null) {
widget.scrollToIndex(rawMessage); widget.scrollToIndex(rawMessage);
} else { } else {
onTIMCallback(TIMCallback( onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO, type: TIMCallbackType.INFO, infoRecommendText: TIM_t("无法定位到原消息")));
infoRecommendText: TIM_t("无法定位到原消息")));
} }
} }
@ -370,10 +368,6 @@ class _TIMUIKitReplyElemState extends TIMUIKitState<TIMUIKitReplyElem> {
widget.message.textElem?.text ?? "", widget.message.textElem?.text ?? "",
widget.chatModel.chatConfig.isSupportMarkdownForTextMessage, widget.chatModel.chatConfig.isSupportMarkdownForTextMessage,
onLinkTap: widget.chatModel.chatConfig.onTapLink, onLinkTap: widget.chatModel.chatConfig.onTapLink,
isUseQQPackage: (widget.chatModel.chatConfig.stickerPanelConfig
?.useTencentCloudChatStickerPackage ??
true) ||
widget.isUseDefaultEmoji,
isUseTencentCloudChatPackage: widget.chatModel.chatConfig isUseTencentCloudChatPackage: widget.chatModel.chatConfig
.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? .stickerPanelConfig?.useTencentCloudChatStickerPackage ??
true, true,
@ -440,13 +434,6 @@ class _TIMUIKitReplyElemState extends TIMUIKitState<TIMUIKitReplyElem> {
fontSize: isDesktopScreen ? 14 : 16, fontSize: isDesktopScreen ? 14 : 16,
height: widget.chatModel.chatConfig.textHeight), height: widget.chatModel.chatConfig.textHeight),
specialTextSpanBuilder: DefaultSpecialTextSpanBuilder( specialTextSpanBuilder: DefaultSpecialTextSpanBuilder(
isUseQQPackage: (widget
.chatModel
.chatConfig
.stickerPanelConfig
?.useTencentCloudChatStickerPackage ??
true) ||
widget.isUseDefaultEmoji,
isUseTencentCloudChatPackage: widget isUseTencentCloudChatPackage: widget
.chatModel .chatModel
.chatConfig .chatConfig

View File

@ -24,7 +24,6 @@ class TIMUIKitTextElem extends StatefulWidget {
final EdgeInsetsGeometry? textPadding; final EdgeInsetsGeometry? textPadding;
final TUIChatSeparateViewModel chatModel; final TUIChatSeparateViewModel chatModel;
final bool? isShowMessageReaction; final bool? isShowMessageReaction;
final bool isUseDefaultEmoji;
final List<CustomEmojiFaceData> customEmojiStickerList; final List<CustomEmojiFaceData> customEmojiStickerList;
const TIMUIKitTextElem( const TIMUIKitTextElem(
@ -39,7 +38,6 @@ class TIMUIKitTextElem extends StatefulWidget {
this.backgroundColor, this.backgroundColor,
this.textPadding, this.textPadding,
required this.chatModel, required this.chatModel,
this.isUseDefaultEmoji = false,
this.customEmojiStickerList = const []}) this.customEmojiStickerList = const []})
: super(key: key); : super(key: key);
@ -167,10 +165,6 @@ class _TIMUIKitTextElemState extends TIMUIKitState<TIMUIKitTextElem> {
widget.message.textElem?.text ?? "", widget.message.textElem?.text ?? "",
widget.chatModel.chatConfig.isSupportMarkdownForTextMessage, widget.chatModel.chatConfig.isSupportMarkdownForTextMessage,
onLinkTap: widget.chatModel.chatConfig.onTapLink, onLinkTap: widget.chatModel.chatConfig.onTapLink,
isUseQQPackage: (widget.chatModel.chatConfig.stickerPanelConfig
?.useTencentCloudChatStickerPackage ??
true) ||
widget.isUseDefaultEmoji,
isUseTencentCloudChatPackage: widget.chatModel.chatConfig isUseTencentCloudChatPackage: widget.chatModel.chatConfig
.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? .stickerPanelConfig?.useTencentCloudChatStickerPackage ??
true, true,
@ -238,13 +232,6 @@ class _TIMUIKitTextElemState extends TIMUIKitState<TIMUIKitTextElem> {
fontSize: isDesktopScreen ? 14 : 16, fontSize: isDesktopScreen ? 14 : 16,
height: widget.chatModel.chatConfig.textHeight), height: widget.chatModel.chatConfig.textHeight),
specialTextSpanBuilder: DefaultSpecialTextSpanBuilder( specialTextSpanBuilder: DefaultSpecialTextSpanBuilder(
isUseQQPackage: (widget
.chatModel
.chatConfig
.stickerPanelConfig
?.useTencentCloudChatStickerPackage ??
true) ||
widget.isUseDefaultEmoji,
isUseTencentCloudChatPackage: widget isUseTencentCloudChatPackage: widget
.chatModel .chatModel
.chatConfig .chatConfig

View File

@ -22,7 +22,6 @@ class TIMUIKitTextTranslationElem extends StatefulWidget {
final EdgeInsetsGeometry? textPadding; final EdgeInsetsGeometry? textPadding;
final TUIChatSeparateViewModel chatModel; final TUIChatSeparateViewModel chatModel;
final bool? isShowMessageReaction; final bool? isShowMessageReaction;
final bool isUseDefaultEmoji;
final List<CustomEmojiFaceData> customEmojiStickerList; final List<CustomEmojiFaceData> customEmojiStickerList;
const TIMUIKitTextTranslationElem( const TIMUIKitTextTranslationElem(
@ -37,7 +36,6 @@ class TIMUIKitTextTranslationElem extends StatefulWidget {
this.backgroundColor, this.backgroundColor,
this.textPadding, this.textPadding,
required this.chatModel, required this.chatModel,
this.isUseDefaultEmoji = false,
this.customEmojiStickerList = const []}) this.customEmojiStickerList = const []})
: super(key: key); : super(key: key);
@ -124,10 +122,6 @@ class _TIMUIKitTextTranslationElemState
final textWithLink = LinkPreviewEntry.getHyperlinksText(translateText ?? "", final textWithLink = LinkPreviewEntry.getHyperlinksText(translateText ?? "",
widget.chatModel.chatConfig.isSupportMarkdownForTextMessage, widget.chatModel.chatConfig.isSupportMarkdownForTextMessage,
onLinkTap: widget.chatModel.chatConfig.onTapLink, onLinkTap: widget.chatModel.chatConfig.onTapLink,
isUseQQPackage: (widget.chatModel.chatConfig.stickerPanelConfig
?.useTencentCloudChatStickerPackage ??
true) ||
widget.isUseDefaultEmoji,
isUseTencentCloudChatPackage: widget.chatModel.chatConfig isUseTencentCloudChatPackage: widget.chatModel.chatConfig
.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? .stickerPanelConfig?.useTencentCloudChatStickerPackage ??
true, true,
@ -166,13 +160,6 @@ class _TIMUIKitTextTranslationElemState
fontSize: isDesktopScreen ? 14 : 16, fontSize: isDesktopScreen ? 14 : 16,
height: widget.chatModel.chatConfig.textHeight), height: widget.chatModel.chatConfig.textHeight),
specialTextSpanBuilder: DefaultSpecialTextSpanBuilder( specialTextSpanBuilder: DefaultSpecialTextSpanBuilder(
isUseQQPackage: (widget
.chatModel
.chatConfig
.stickerPanelConfig
?.useTencentCloudChatStickerPackage ??
true) ||
widget.isUseDefaultEmoji,
isUseTencentCloudChatPackage: widget isUseTencentCloudChatPackage: widget
.chatModel .chatModel
.chatConfig .chatConfig

View File

@ -9,7 +9,6 @@ import 'emoji_text.dart';
class DefaultSpecialTextSpanBuilder extends SpecialTextSpanBuilder { class DefaultSpecialTextSpanBuilder extends SpecialTextSpanBuilder {
DefaultSpecialTextSpanBuilder({ DefaultSpecialTextSpanBuilder({
this.isUseQQPackage = false,
this.isUseTencentCloudChatPackage = false, this.isUseTencentCloudChatPackage = false,
this.customEmojiStickerList = const [], this.customEmojiStickerList = const [],
this.showAtBackground = false, this.showAtBackground = false,
@ -19,8 +18,6 @@ class DefaultSpecialTextSpanBuilder extends SpecialTextSpanBuilder {
/// whether show background for @somebody /// whether show background for @somebody
final bool showAtBackground; final bool showAtBackground;
final bool isUseQQPackage;
final bool isUseTencentCloudChatPackage; final bool isUseTencentCloudChatPackage;
final bool checkHttpLink; final bool checkHttpLink;
@ -41,7 +38,6 @@ class DefaultSpecialTextSpanBuilder extends SpecialTextSpanBuilder {
return EmojiText(textStyle, return EmojiText(textStyle,
isUseTencentCloudChatPackage: isUseTencentCloudChatPackage, isUseTencentCloudChatPackage: isUseTencentCloudChatPackage,
start: index! - (EmojiText.flag.length - 1), start: index! - (EmojiText.flag.length - 1),
isUseQQPackage: isUseQQPackage,
customEmojiStickerList: customEmojiStickerList); customEmojiStickerList: customEmojiStickerList);
} else if (isStart(flag, HttpText.flag) && checkHttpLink) { } else if (isStart(flag, HttpText.flag) && checkHttpLink) {
return HttpText(textStyle, onTap, return HttpText(textStyle, onTap,

View File

@ -8,12 +8,10 @@ class EmojiText extends SpecialText {
EmojiText(TextStyle? textStyle, EmojiText(TextStyle? textStyle,
{this.start, {this.start,
this.isUseTencentCloudChatPackage = false, this.isUseTencentCloudChatPackage = false,
this.isUseQQPackage = false,
this.customEmojiStickerList = const []}) this.customEmojiStickerList = const []})
: super(EmojiText.flag, ']', textStyle); : super(EmojiText.flag, ']', textStyle);
static const String flag = '['; static const String flag = '[';
final int? start; final int? start;
final bool isUseQQPackage;
final bool isUseTencentCloudChatPackage; final bool isUseTencentCloudChatPackage;
final List<CustomEmojiFaceData> customEmojiStickerList; final List<CustomEmojiFaceData> customEmojiStickerList;
@ -22,7 +20,6 @@ class EmojiText extends SpecialText {
final String key = toString(); final String key = toString();
final EmojiUtil emojiUtil = EmojiUtil( final EmojiUtil emojiUtil = EmojiUtil(
isUseTencentCloudChatPackage: isUseTencentCloudChatPackage, isUseTencentCloudChatPackage: isUseTencentCloudChatPackage,
isUseQQPackage: isUseQQPackage,
customEmojiStickerList: customEmojiStickerList); customEmojiStickerList: customEmojiStickerList);
if (emojiUtil.emojiMap.containsKey(key)) { if (emojiUtil.emojiMap.containsKey(key)) {
@ -33,18 +30,7 @@ class EmojiText extends SpecialText {
size = ts.fontSize! * 1.44; size = ts.fontSize! * 1.44;
} }
if (isUseQQPackage == true && if (isUseTencentCloudChatPackage == true &&
(emojiUtil.emojiKeyCategoryMap["4349"]?.contains(key) ?? false)) {
return ImageSpan(
AssetImage(emojiUtil.emojiMap[key]!,
package: "tim_ui_kit_sticker_plugin"),
actualText: key,
imageWidth: size,
imageHeight: size,
start: start!,
// fit: BoxFit.cover,
margin: const EdgeInsets.all(0));
} else if (isUseTencentCloudChatPackage == true &&
(emojiUtil.emojiKeyCategoryMap["tcc1"]?.contains(key) ?? false)) { (emojiUtil.emojiKeyCategoryMap["tcc1"]?.contains(key) ?? false)) {
return ImageSpan( return ImageSpan(
AssetImage(emojiUtil.emojiMap[key]!, AssetImage(emojiUtil.emojiMap[key]!,
@ -73,8 +59,7 @@ class EmojiText extends SpecialText {
class EmojiUtil { class EmojiUtil {
// Private constructor initializing the emoji data // Private constructor initializing the emoji data
EmojiUtil._internal( EmojiUtil._internal(
{required this.isUseQQPackage, {required this.isUseTencentCloudChatPackage,
required this.isUseTencentCloudChatPackage,
required this.customEmojiStickerList}) { required this.customEmojiStickerList}) {
_emojiMap.addAll(loadDefaultEmojis()); _emojiMap.addAll(loadDefaultEmojis());
@ -83,7 +68,6 @@ class EmojiUtil {
_emojiKeyCategoryMap["custom"] = customEmojis.$2; _emojiKeyCategoryMap["custom"] = customEmojis.$2;
} }
final bool isUseQQPackage;
final bool isUseTencentCloudChatPackage; final bool isUseTencentCloudChatPackage;
final List<CustomEmojiFaceData> customEmojiStickerList; final List<CustomEmojiFaceData> customEmojiStickerList;
@ -93,20 +77,12 @@ class EmojiUtil {
for (final emojiGroup in TUIKitStickerConstData.emojiList) { for (final emojiGroup in TUIKitStickerConstData.emojiList) {
final groupName = emojiGroup.name; final groupName = emojiGroup.name;
final keyList = []; final keyList = [];
if ((isUseQQPackage && groupName == "4349") || if (isUseTencentCloudChatPackage && groupName == "tcc1") {
(isUseTencentCloudChatPackage && groupName == "tcc1")) {
for (final emoji in emojiGroup.list) { for (final emoji in emojiGroup.list) {
String emojiName = emoji.split('.png')[0]; String emojiName = emoji.split('.png')[0];
defaultEmojiMap['[$emojiName]'] = defaultEmojiMap['[$emojiName]'] =
'$_emojiFilePath/$groupName/$emojiName.png'; '$_emojiFilePath/$groupName/$emojiName.png';
keyList.add('[$emojiName]'); keyList.add('[$emojiName]');
if (groupName == "4349") {
final zhKey = TUIKitStickerConstData.emojiMapList[emojiName];
defaultEmojiMap['[$zhKey]'] =
'$_emojiFilePath/$groupName/$emojiName.png';
keyList.add('[$zhKey]');
}
} }
_emojiKeyCategoryMap[groupName] = keyList; _emojiKeyCategoryMap[groupName] = keyList;
} }
@ -149,11 +125,9 @@ class EmojiUtil {
// Factory constructor to return the singleton instance of EmojiUtil with custom parameters // Factory constructor to return the singleton instance of EmojiUtil with custom parameters
factory EmojiUtil( factory EmojiUtil(
{bool isUseQQPackage = false, {bool isUseTencentCloudChatPackage = false,
bool isUseTencentCloudChatPackage = false,
List<CustomEmojiFaceData> customEmojiStickerList = const []}) { List<CustomEmojiFaceData> customEmojiStickerList = const []}) {
return _instance ??= EmojiUtil._internal( return _instance ??= EmojiUtil._internal(
isUseQQPackage: isUseQQPackage,
customEmojiStickerList: customEmojiStickerList, customEmojiStickerList: customEmojiStickerList,
isUseTencentCloudChatPackage: isUseTencentCloudChatPackage); isUseTencentCloudChatPackage: isUseTencentCloudChatPackage);
} }

View File

@ -142,7 +142,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
double inputWidth = 900; double inputWidth = 900;
Map<String, V2TimGroupMemberFullInfo> mentionedMembersMap = {}; Map<String, V2TimGroupMemberFullInfo> mentionedMembersMap = {};
late TextEditingController textEditingController; late TextEditingController textEditingController;
final TUIConversationViewModel conversationModel = serviceLocator<TUIConversationViewModel>(); final TUIConversationViewModel conversationModel =
serviceLocator<TUIConversationViewModel>();
final TUISelfInfoViewModel selfModel = serviceLocator<TUISelfInfoViewModel>(); final TUISelfInfoViewModel selfModel = serviceLocator<TUISelfInfoViewModel>();
MuteStatus muteStatus = MuteStatus.none; MuteStatus muteStatus = MuteStatus.none;
bool _isComposingText = false; bool _isComposingText = false;
@ -154,41 +155,29 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
// Keep using original scheme. // Keep using original scheme.
return; return;
} }
final stickerConfig = widget.model.chatConfig.stickerPanelConfig ?? StickerPanelConfig(); final stickerConfig =
widget.model.chatConfig.stickerPanelConfig ?? StickerPanelConfig();
if (stickerConfig.useTencentCloudChatStickerPackage) { if (stickerConfig.useTencentCloudChatStickerPackage) {
final tccEmojiSet = TUIKitStickerConstData.emojiList.firstWhere((element) => element.name == "tcc1"); final tccEmojiSet = TUIKitStickerConstData.emojiList
.firstWhere((element) => element.name == "tcc1");
stickerPackageList.add(CustomStickerPackage( stickerPackageList.add(CustomStickerPackage(
name: tccEmojiSet.name, name: tccEmojiSet.name,
baseUrl: "assets/custom_face_resource/${tccEmojiSet.name}", baseUrl: "assets/custom_face_resource/${tccEmojiSet.name}",
isEmoji: tccEmojiSet.isEmoji, isEmoji: tccEmojiSet.isEmoji,
isDefaultEmoji: true, isDefaultEmoji: true,
stickerList: tccEmojiSet.list.asMap().keys.map((idx) => CustomSticker(index: idx, name: tccEmojiSet.list[idx])).toList(), stickerList: tccEmojiSet.list
.asMap()
.keys
.map((idx) =>
CustomSticker(index: idx, name: tccEmojiSet.list[idx]))
.toList(),
menuItem: CustomSticker( menuItem: CustomSticker(
index: 0, index: 0,
name: tccEmojiSet.icon, name: tccEmojiSet.icon,
))); )));
} }
if (stickerConfig.useQQStickerPackage) {
final qqEmojiSet = TUIKitStickerConstData.emojiList.firstWhere((element) => element.name == "4349");
stickerPackageList.add(CustomStickerPackage(
name: qqEmojiSet.name,
baseUrl: "assets/custom_face_resource/${qqEmojiSet.name}",
isEmoji: qqEmojiSet.isEmoji,
isDefaultEmoji: true,
stickerList: qqEmojiSet.list.asMap().keys.map((idx) => CustomSticker(index: idx, name: qqEmojiSet.list[idx])).toList(),
menuItem: CustomSticker(
index: 0,
name: qqEmojiSet.icon,
)));
}
if (stickerConfig.unicodeEmojiList.isNotEmpty) {
final defEmojiList = TUIKitStickerConstData.defaultUnicodeEmojiList.map((emojiItem) {
return CustomSticker(index: 0, name: emojiItem.toString(), unicode: emojiItem);
}).toList();
stickerPackageList.add(CustomStickerPackage(name: "defaultEmoji", stickerList: defEmojiList, menuItem: defEmojiList[0]));
}
stickerPackageList.addAll(stickerConfig.customStickerPackages);
stickerPackageList.addAll(stickerConfig.customStickerPackages);
return stickerPackageList; return stickerPackageList;
} }
@ -215,7 +204,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
if (cursorPosition > 0) { if (cursorPosition > 0) {
final EmojiUtil emojiUtil = EmojiUtil(); final EmojiUtil emojiUtil = EmojiUtil();
int removeLength = 1; int removeLength = 1;
int openBracketIndex = originalText.lastIndexOf('[', cursorPosition - 1); int openBracketIndex =
originalText.lastIndexOf('[', cursorPosition - 1);
if (openBracketIndex != -1 && originalText[cursorPosition - 1] == ']') { if (openBracketIndex != -1 && originalText[cursorPosition - 1] == ']') {
// Small png emoji // Small png emoji
@ -224,18 +214,23 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
if (emojiUtil.emojiMap.containsKey(key)) { if (emojiUtil.emojiMap.containsKey(key)) {
removeLength = cursorPosition - openBracketIndex; removeLength = cursorPosition - openBracketIndex;
} }
} else if (cursorPosition > 1 && isEmoji(originalText.substring(cursorPosition - 2, cursorPosition))) { } else if (cursorPosition > 1 &&
isEmoji(
originalText.substring(cursorPosition - 2, cursorPosition))) {
removeLength = 2; removeLength = 2;
} }
text = originalText.substring(0, cursorPosition - removeLength) + originalText.substring(cursorPosition); text = originalText.substring(0, cursorPosition - removeLength) +
originalText.substring(cursorPosition);
currentCursor = (currentCursor ?? removeLength) - removeLength; currentCursor = (currentCursor ?? removeLength) - removeLength;
} }
textEditingController.text = text; textEditingController.text = text;
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) { if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: currentCursor ?? textEditingController.text.length)); textEditingController.selection = TextSelection.fromPosition(
TextPosition(
offset: currentCursor ?? textEditingController.text.length));
focusNode.requestFocus(); focusNode.requestFocus();
} }
} }
@ -255,7 +250,9 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
void _addStickerToText(String sticker) { void _addStickerToText(String sticker) {
final currentText = textEditingController.text; final currentText = textEditingController.text;
if (currentCursor != null && currentCursor! > -1 && currentCursor! < currentText.length + 1) { if (currentCursor != null &&
currentCursor! > -1 &&
currentCursor! < currentText.length + 1) {
final firstString = currentText.substring(0, currentCursor); final firstString = currentText.substring(0, currentCursor);
final secondString = currentText.substring(currentCursor!); final secondString = currentText.substring(currentCursor!);
currentCursor = currentCursor! + sticker.length; currentCursor = currentCursor! + sticker.length;
@ -266,7 +263,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} }
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) { if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: currentCursor ?? textEditingController.text.length)); textEditingController.selection = TextSelection.fromPosition(TextPosition(
offset: currentCursor ?? textEditingController.text.length));
focusNode.requestFocus(); focusNode.requestFocus();
} }
} }
@ -275,13 +273,23 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
return text.replaceAll(RegExp(r'\ufeff'), ""); return text.replaceAll(RegExp(r'\ufeff'), "");
} }
Future handleSetDraftText({String? id, ConvType? convType, String? groupID}) async { Future handleSetDraftText(
{String? id, ConvType? convType, String? groupID}) async {
String text = textEditingController.text; String text = textEditingController.text;
String convID = id ?? widget.conversationID; String convID = id ?? widget.conversationID;
final isTopic = convID.contains("@TOPIC#"); final isTopic = convID.contains("@TOPIC#");
String conversationID = isTopic ? convID : ((convType ?? widget.conversationType) == ConvType.c2c ? "${TUIConversationViewModel.conversationC2CPrefix}$convID" : "${TUIConversationViewModel.conversationGroupPrefix}$convID"); String conversationID = isTopic
? convID
: ((convType ?? widget.conversationType) == ConvType.c2c
? "${TUIConversationViewModel.conversationC2CPrefix}$convID"
: "${TUIConversationViewModel.conversationGroupPrefix}$convID");
String draftText = _filterU200b(text); String draftText = _filterU200b(text);
return await conversationModel.setConversationDraft(groupID: groupID ?? widget.groupID, isTopic: isTopic, isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb, conversationID: conversationID, draftText: draftText); return await conversationModel.setConversationDraft(
groupID: groupID ?? widget.groupID,
isTopic: isTopic,
isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb,
conversationID: conversationID,
draftText: draftText);
} }
// onSubmitted一样 // onSubmitted一样
@ -329,9 +337,21 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} }
if (widget.model.repliedMessage != null) { if (widget.model.repliedMessage != null) {
MessageUtils.handleMessageError(widget.model.sendFaceMessage(index: index, data: data, convID: widget.conversationID, convType: convType), context); MessageUtils.handleMessageError(
widget.model.sendFaceMessage(
index: index,
data: data,
convID: widget.conversationID,
convType: convType),
context);
} else { } else {
MessageUtils.handleMessageError(widget.model.sendFaceMessage(index: index, data: data, convID: widget.conversationID, convType: convType), context); MessageUtils.handleMessageError(
widget.model.sendFaceMessage(
index: index,
data: data,
convID: widget.conversationID,
convType: convType),
context);
} }
} }
@ -351,11 +371,24 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
final convType = widget.conversationType; final convType = widget.conversationType;
if (text.isNotEmpty && text != zeroWidthSpace) { if (text.isNotEmpty && text != zeroWidthSpace) {
if (widget.model.repliedMessage != null) { if (widget.model.repliedMessage != null) {
MessageUtils.handleMessageError(widget.model.sendReplyMessage(text: text, convID: widget.conversationID, convType: convType, atUserIDList: getUserIdFromMemberInfoMap()), context); MessageUtils.handleMessageError(
widget.model.sendReplyMessage(
text: text,
convID: widget.conversationID,
convType: convType,
atUserIDList: getUserIdFromMemberInfoMap()),
context);
} else if (mentionedMembersMap.isNotEmpty) { } else if (mentionedMembersMap.isNotEmpty) {
widget.model.sendTextAtMessage(text: text, convType: widget.conversationType, convID: widget.conversationID, atUserList: getUserIdFromMemberInfoMap()); widget.model.sendTextAtMessage(
text: text,
convType: widget.conversationType,
convID: widget.conversationID,
atUserList: getUserIdFromMemberInfoMap());
} else { } else {
MessageUtils.handleMessageError(widget.model.sendTextMessage(text: text, convID: widget.conversationID, convType: convType), context); MessageUtils.handleMessageError(
widget.model.sendTextMessage(
text: text, convID: widget.conversationID, convType: convType),
context);
} }
textEditingController.clear(); textEditingController.clear();
currentCursor = null; currentCursor = null;
@ -368,7 +401,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} }
void goDownBottom() { void goDownBottom() {
if (globalModel.getMessageListPosition(widget.conversationID) == HistoryMessagePosition.notShowLatest) { if (globalModel.getMessageListPosition(widget.conversationID) ==
HistoryMessagePosition.notShowLatest) {
return; return;
} }
Future.delayed(const Duration(milliseconds: 50), () { Future.delayed(const Duration(milliseconds: 50), () {
@ -397,14 +431,18 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} }
String _getShowName(V2TimGroupMemberFullInfo? item) { String _getShowName(V2TimGroupMemberFullInfo? item) {
return TencentUtils.checkStringWithoutSpace(item?.nameCard) ?? TencentUtils.checkStringWithoutSpace(item?.nickName) ?? TencentUtils.checkStringWithoutSpace(item?.userID) ?? ""; return TencentUtils.checkStringWithoutSpace(item?.nameCard) ??
TencentUtils.checkStringWithoutSpace(item?.nickName) ??
TencentUtils.checkStringWithoutSpace(item?.userID) ??
"";
} }
mentionMemberInMessage(String? userID, String? nickName) { mentionMemberInMessage(String? userID, String? nickName) {
if (TencentUtils.checkString(userID) == null) { if (TencentUtils.checkString(userID) == null) {
focusNode.requestFocus(); focusNode.requestFocus();
} else { } else {
final memberInfo = widget.model.groupMemberList?.firstWhereOrNull((element) => element?.userID == userID) ?? final memberInfo = widget.model.groupMemberList
?.firstWhereOrNull((element) => element?.userID == userID) ??
V2TimGroupMemberFullInfo( V2TimGroupMemberFullInfo(
userID: userID ?? "", userID: userID ?? "",
nickName: nickName, nickName: nickName,
@ -415,7 +453,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
//please do not delete space //please do not delete space
focusNode.requestFocus(); focusNode.requestFocus();
textEditingController.text = text; textEditingController.text = text;
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: text.length)); textEditingController.selection =
TextSelection.fromPosition(TextPosition(offset: text.length));
lastText = text; lastText = text;
_isComposingText = false; _isComposingText = false;
narrowTextFieldKey.currentState?.showKeyboard = true; narrowTextFieldKey.currentState?.showKeyboard = true;
@ -443,10 +482,16 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
maxLines: null, maxLines: null,
); );
textPainter.layout(maxWidth: inputWidth); textPainter.layout(maxWidth: inputWidth);
final TextPosition lastLineOffset = textPainter.getPositionForOffset(Offset(textPainter.width, textPainter.height)); final TextPosition lastLineOffset = textPainter
final Offset caretPosition = textPainter.getOffsetForCaret(lastLineOffset, Rect.zero); .getPositionForOffset(Offset(textPainter.width, textPainter.height));
final Offset caretPosition =
textPainter.getOffsetForCaret(lastLineOffset, Rect.zero);
final dx = min(inputWidth - 180, caretPosition.dx + 16); final dx = min(inputWidth - 180, caretPosition.dx + 16);
final dy = max(24, 21 * widget.model.chatConfig.desktopMessageInputFieldLines - caretPosition.dy).toDouble(); final dy = max(
24,
21 * widget.model.chatConfig.desktopMessageInputFieldLines -
caretPosition.dy)
.toDouble();
return Offset(dx, dy); return Offset(dx, dy);
} }
@ -483,13 +528,19 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
mentionedMembersMap = map; mentionedMembersMap = map;
} }
(int, String, bool)? findChangedCharacter(String originalString, String newString) { (int, String, bool)? findChangedCharacter(
String originalString, String newString) {
if (newString.length < originalString.length) { if (newString.length < originalString.length) {
final originalStringLength = originalString.length; final originalStringLength = originalString.length;
final newStringLength = newString.length; final newStringLength = newString.length;
for (int i = 0; i < newString.length; ++i) { for (int i = 0; i < newString.length; ++i) {
if (originalString[originalStringLength - i - 1] != newString[newStringLength - i - 1]) { if (originalString[originalStringLength - i - 1] !=
return (newStringLength - i, originalString[originalStringLength - i - 1], false); newString[newStringLength - i - 1]) {
return (
newStringLength - i,
originalString[originalStringLength - i - 1],
false
);
} }
} }
return (newString.length, originalString[newString.length], false); return (newString.length, originalString[newString.length], false);
@ -508,8 +559,11 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
_handleAtText(String text, TUIChatSeparateViewModel model) async { _handleAtText(String text, TUIChatSeparateViewModel model) async {
final text = textEditingController.text; final text = textEditingController.text;
final String originalText = lastText; final String originalText = lastText;
String? groupID = widget.conversationType == ConvType.group ? widget.conversationID : null; String? groupID = widget.conversationType == ConvType.group
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; ? widget.conversationID
: null;
final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
if (groupID == null) { if (groupID == null) {
lastText = text; lastText = text;
@ -529,9 +583,11 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
String atTag = originalText.substring(atIndex, spaceIndex); String atTag = originalText.substring(atIndex, spaceIndex);
String deletedChar = originalText[diffIndex]; String deletedChar = originalText[diffIndex];
if (shouldRemoveAtTag(atTag, deletedChar)) { if (shouldRemoveAtTag(atTag, deletedChar)) {
final newText = originalText.substring(0, atIndex) + originalText.substring(spaceIndex + 1); final newText = originalText.substring(0, atIndex) +
originalText.substring(spaceIndex + 1);
textEditingController.text = newText; textEditingController.text = newText;
textEditingController.selection = TextSelection.collapsed(offset: atIndex); textEditingController.selection =
TextSelection.collapsed(offset: atIndex);
lastText = newText; lastText = newText;
updateMentionedMap(); updateMentionedMap();
return; return;
@ -541,13 +597,14 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} }
final int selfRole = widget.model.selfMemberInfo?.role ?? 0; final int selfRole = widget.model.selfMemberInfo?.role ?? 0;
final bool canAtAll = widget.model.chatConfig.isMemberCanAtAll ? true : (selfRole == GroupMemberRoleType final bool canAtAll = widget.model.chatConfig.isMemberCanAtAll
.V2TIM_GROUP_MEMBER_ROLE_ADMIN || selfRole ? true
== : (selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN ||
GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER); selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER);
if (isDesktopScreen) { if (isDesktopScreen) {
(int, String, bool)? changedCharacterRecord = findChangedCharacter(originalText, text); (int, String, bool)? changedCharacterRecord =
findChangedCharacter(originalText, text);
int? changedTextPosition = changedCharacterRecord?.$1; int? changedTextPosition = changedCharacterRecord?.$1;
String? changedCharacter = changedCharacterRecord?.$2; String? changedCharacter = changedCharacterRecord?.$2;
bool isAdded = changedCharacterRecord?.$3 ?? false; bool isAdded = changedCharacterRecord?.$3 ?? false;
@ -556,10 +613,13 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
int? atPlace; int? atPlace;
if (changedTextPosition != null) { if (changedTextPosition != null) {
subText = isAdded == true ? text.substring(0, changedTextPosition + 1) : text.substring(0, changedTextPosition); subText = isAdded == true
? text.substring(0, changedTextPosition + 1)
: text.substring(0, changedTextPosition);
atPlace = subText.lastIndexOf('@'); atPlace = subText.lastIndexOf('@');
if (atPlace != -1) { if (atPlace != -1) {
keyword = text.substring(atPlace + 1, changedTextPosition + (isAdded ? 1 : 0)); keyword = text.substring(
atPlace + 1, changedTextPosition + (isAdded ? 1 : 0));
} }
} else { } else {
atPlace = -1; atPlace = -1;
@ -572,21 +632,28 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
model.atPositionY = atPosition.dy; model.atPositionY = atPosition.dy;
isAddingAtSearchWords = true; isAddingAtSearchWords = true;
} }
List<V2TimGroupMemberFullInfo> showAtMemberList = (model.groupMemberList ?? []) List<V2TimGroupMemberFullInfo> showAtMemberList = (model
.groupMemberList ??
[])
.where((element) { .where((element) {
final showName = (TencentUtils.checkStringWithoutSpace(element?.friendRemark) ?? final showName = (TencentUtils.checkStringWithoutSpace(
element?.friendRemark) ??
TencentUtils.checkStringWithoutSpace(element?.nameCard) ?? TencentUtils.checkStringWithoutSpace(element?.nameCard) ??
TencentUtils.checkStringWithoutSpace(element?.nickName) ?? TencentUtils.checkStringWithoutSpace(element?.nickName) ??
TencentUtils.checkStringWithoutSpace(element?.userID) ?? TencentUtils.checkStringWithoutSpace(element?.userID) ??
"") "")
.toLowerCase(); .toLowerCase();
keyword ??= ""; keyword ??= "";
return element != null && showName.contains(keyword!.toLowerCase()) && TencentUtils.checkString(showName) != null && element.userID != widget.model.selfMemberInfo?.userID; return element != null &&
showName.contains(keyword!.toLowerCase()) &&
TencentUtils.checkString(showName) != null &&
element.userID != widget.model.selfMemberInfo?.userID;
}) })
.whereType<V2TimGroupMemberFullInfo>() .whereType<V2TimGroupMemberFullInfo>()
.toList(); .toList();
showAtMemberList.sort((V2TimGroupMemberFullInfo userA, V2TimGroupMemberFullInfo userB) { showAtMemberList.sort(
(V2TimGroupMemberFullInfo userA, V2TimGroupMemberFullInfo userB) {
final isUserAIsGroupAdmin = userA.role == 300; final isUserAIsGroupAdmin = userA.role == 300;
final isUserAIsGroupOwner = userA.role == 400; final isUserAIsGroupOwner = userA.role == 400;
@ -609,7 +676,11 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
keyword ??= ""; keyword ??= "";
if (canAtAll && showAtMemberList.isNotEmpty && keyword!.isEmpty) { if (canAtAll && showAtMemberList.isNotEmpty && keyword!.isEmpty) {
showAtMemberList = [V2TimGroupMemberFullInfo(userID: "__kImSDK_MesssageAtALL__", nickName: TIM_t("所有人")), ...showAtMemberList]; showAtMemberList = [
V2TimGroupMemberFullInfo(
userID: "__kImSDK_MesssageAtALL__", nickName: TIM_t("所有人")),
...showAtMemberList
];
} }
model.activeAtIndex = 0; model.activeAtIndex = 0;
@ -621,11 +692,19 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
model.showAtMemberList = []; model.showAtMemberList = [];
isAddingAtSearchWords = false; isAddingAtSearchWords = false;
} }
} else if (textLength > 0 && text[textLength - 1] == "@" && lastText.length < textLength) { } else if (textLength > 0 &&
List<V2TimGroupMemberFullInfo> selectedAtMemberList = await Navigator.push( text[textLength - 1] == "@" &&
lastText.length < textLength) {
List<V2TimGroupMemberFullInfo> selectedAtMemberList =
await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => AtText(groupMemberList: model.groupMemberList, groupInfo: model.groupInfo, groupID: groupID, canAtAll: canAtAll, groupType: widget.groupType), builder: (context) => AtText(
groupMemberList: model.groupMemberList,
groupInfo: model.groupInfo,
groupID: groupID,
canAtAll: canAtAll,
groupType: widget.groupType),
), ),
); );
@ -635,7 +714,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
if (memberInfo != null) { if (memberInfo != null) {
mentionedMembersMap["@$showName"] = memberInfo; mentionedMembersMap["@$showName"] = memberInfo;
String addAtCharacter = i == 0 ? "" : "@"; String addAtCharacter = i == 0 ? "" : "@";
textEditingController.text = "${textEditingController.text}$addAtCharacter$showName "; textEditingController.text =
"${textEditingController.text}$addAtCharacter$showName ";
lastText = "${textEditingController.text}$addAtCharacter$showName "; lastText = "${textEditingController.text}$addAtCharacter$showName ";
} }
} }
@ -646,17 +726,22 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
void replaceAtTag(String selectedMember) { void replaceAtTag(String selectedMember) {
int cursorPosition = textEditingController.selection.baseOffset; int cursorPosition = textEditingController.selection.baseOffset;
int atIndex = textEditingController.text.lastIndexOf('@', cursorPosition - 1); int atIndex =
textEditingController.text.lastIndexOf('@', cursorPosition - 1);
if (atIndex >= 0) { if (atIndex >= 0) {
String beforeAt = textEditingController.text.substring(0, atIndex); String beforeAt = textEditingController.text.substring(0, atIndex);
String afterAt = textEditingController.text.substring(cursorPosition); String afterAt = textEditingController.text.substring(cursorPosition);
textEditingController.text = beforeAt + '@' + selectedMember + ' ' + afterAt; textEditingController.text =
textEditingController.selection = TextSelection.collapsed(offset: atIndex + selectedMember.length + 2); beforeAt + '@' + selectedMember + ' ' + afterAt;
textEditingController.selection =
TextSelection.collapsed(offset: atIndex + selectedMember.length + 2);
lastText = beforeAt + '@' + selectedMember + ' ' + afterAt; lastText = beforeAt + '@' + selectedMember + ' ' + afterAt;
} }
} }
void handleAtMember({V2TimGroupMemberFullInfo? memberInfo, bool? isAddToCursorPosition = false}) { void handleAtMember(
{V2TimGroupMemberFullInfo? memberInfo,
bool? isAddToCursorPosition = false}) {
if (memberInfo != null) { if (memberInfo != null) {
final String showName = _getShowName(memberInfo); final String showName = _getShowName(memberInfo);
mentionedMembersMap["@$showName"] = memberInfo; mentionedMembersMap["@$showName"] = memberInfo;
@ -670,17 +755,24 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
KeyEventResult handleDesktopKeyEvent(FocusNode node, RawKeyEvent event) { KeyEventResult handleDesktopKeyEvent(FocusNode node, RawKeyEvent event) {
final activeIndex = widget.model.activeAtIndex; final activeIndex = widget.model.activeAtIndex;
final showMemberList = widget.model.showAtMemberList; final showMemberList = widget.model.showAtMemberList;
final isPressEnter = (event.physicalKey == PhysicalKeyboardKey.enter) || (event.physicalKey == PhysicalKeyboardKey.numpadEnter); final isPressEnter = (event.physicalKey == PhysicalKeyboardKey.enter) ||
(event.physicalKey == PhysicalKeyboardKey.numpadEnter);
if (event.runtimeType == RawKeyDownEvent) { if (event.runtimeType == RawKeyDownEvent) {
if (event.physicalKey == PhysicalKeyboardKey.backspace) { if (event.physicalKey == PhysicalKeyboardKey.backspace) {
if (textEditingController.text.isEmpty && lastText.isEmpty) { if (textEditingController.text.isEmpty && lastText.isEmpty) {
widget.model.repliedMessage = null; widget.model.repliedMessage = null;
return KeyEventResult.handled; return KeyEventResult.handled;
} }
} else if ((event.isShiftPressed || event.isAltPressed || event.isControlPressed || event.isMetaPressed) && isPressEnter) { } else if ((event.isShiftPressed ||
event.isAltPressed ||
event.isControlPressed ||
event.isMetaPressed) &&
isPressEnter) {
final offset = textEditingController.selection.baseOffset; final offset = textEditingController.selection.baseOffset;
textEditingController.text = '${lastText.substring(0, offset)}\n${lastText.substring(offset)}'; textEditingController.text =
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: offset + 1)); '${lastText.substring(0, offset)}\n${lastText.substring(offset)}';
textEditingController.selection =
TextSelection.fromPosition(TextPosition(offset: offset + 1));
lastText = textEditingController.text; lastText = textEditingController.text;
return KeyEventResult.handled; return KeyEventResult.handled;
@ -690,26 +782,34 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
onSubmitted(); onSubmitted();
} else { } else {
isAddingAtSearchWords = false; isAddingAtSearchWords = false;
final V2TimGroupMemberFullInfo? memberInfo = showMemberList[activeIndex]; final V2TimGroupMemberFullInfo? memberInfo =
showMemberList[activeIndex];
if (memberInfo != null) { if (memberInfo != null) {
handleAtMember(memberInfo: memberInfo, isAddToCursorPosition: true); handleAtMember(
memberInfo: memberInfo, isAddToCursorPosition: true);
} }
} }
return KeyEventResult.handled; return KeyEventResult.handled;
} }
} }
if (event.isKeyPressed(LogicalKeyboardKey.arrowUp) && isAddingAtSearchWords && showMemberList.isNotEmpty) { if (event.isKeyPressed(LogicalKeyboardKey.arrowUp) &&
isAddingAtSearchWords &&
showMemberList.isNotEmpty) {
final newIndex = max(activeIndex - 1, 0); final newIndex = max(activeIndex - 1, 0);
widget.model.activeAtIndex = newIndex; widget.model.activeAtIndex = newIndex;
widget.atMemberPanelScroll?.scrollToIndex(newIndex, preferPosition: AutoScrollPosition.middle); widget.atMemberPanelScroll?.scrollToIndex(newIndex,
preferPosition: AutoScrollPosition.middle);
return KeyEventResult.handled; return KeyEventResult.handled;
} }
if (event.isKeyPressed(LogicalKeyboardKey.arrowDown) && isAddingAtSearchWords && showMemberList.isNotEmpty) { if (event.isKeyPressed(LogicalKeyboardKey.arrowDown) &&
isAddingAtSearchWords &&
showMemberList.isNotEmpty) {
final newIndex = min(activeIndex + 1, showMemberList.length - 1); final newIndex = min(activeIndex + 1, showMemberList.length - 1);
widget.model.activeAtIndex = newIndex; widget.model.activeAtIndex = newIndex;
widget.atMemberPanelScroll?.scrollToIndex(newIndex, preferPosition: AutoScrollPosition.middle); widget.atMemberPanelScroll?.scrollToIndex(newIndex,
preferPosition: AutoScrollPosition.middle);
return KeyEventResult.handled; return KeyEventResult.handled;
} }
} }
@ -727,7 +827,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} else { } else {
focusNode = FocusNode(); focusNode = FocusNode();
} }
textEditingController = widget.controller?.textEditingController ?? TextEditingController(); textEditingController =
widget.controller?.textEditingController ?? TextEditingController();
if (widget.initText != null) { if (widget.initText != null) {
textEditingController.text = widget.initText!; textEditingController.text = widget.initText!;
} }
@ -735,7 +836,10 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
widget.controller?.addListener(controllerHandler); widget.controller?.addListener(controllerHandler);
} }
final AppLocale appLocale = I18nUtils.findDeviceLocale(null); final AppLocale appLocale = I18nUtils.findDeviceLocale(null);
languageType = (appLocale == AppLocale.zhHans || appLocale == AppLocale.zhHant) ? 'zh' : 'en'; languageType =
(appLocale == AppLocale.zhHans || appLocale == AppLocale.zhHant)
? 'zh'
: 'en';
textEditingController.addListener(() { textEditingController.addListener(() {
_isComposingText = textEditingController.value.composing.start != -1; _isComposingText = textEditingController.value.composing.start != -1;
}); });
@ -745,11 +849,13 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
controllerHandler() { controllerHandler() {
final actionType = widget.controller?.actionType; final actionType = widget.controller?.actionType;
if (actionType == ActionType.longPressToAt) { if (actionType == ActionType.longPressToAt) {
mentionMemberInMessage(widget.controller?.atUserID, widget.controller?.atUserName); mentionMemberInMessage(
widget.controller?.atUserID, widget.controller?.atUserName);
} else if (actionType == ActionType.setTextField) { } else if (actionType == ActionType.setTextField) {
final newText = widget.controller?.inputText ?? ""; final newText = widget.controller?.inputText ?? "";
textEditingController.text = newText; textEditingController.text = newText;
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: textEditingController.text.length)); textEditingController.selection = TextSelection.fromPosition(
TextPosition(offset: textEditingController.text.length));
lastText = textEditingController.text; lastText = textEditingController.text;
focusNode.requestFocus(); focusNode.requestFocus();
return; return;
@ -767,14 +873,18 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (widget.conversationID != oldWidget.conversationID) { if (widget.conversationID != oldWidget.conversationID) {
mentionedMembersMap.clear(); mentionedMembersMap.clear();
handleSetDraftText(id: oldWidget.conversationID, convType: oldWidget.conversationType, groupID: oldWidget.groupID); handleSetDraftText(
id: oldWidget.conversationID,
convType: oldWidget.conversationType,
groupID: oldWidget.groupID);
if (oldWidget.initText != widget.initText) { if (oldWidget.initText != widget.initText) {
textEditingController.text = widget.initText ?? ""; textEditingController.text = widget.initText ?? "";
} else { } else {
textEditingController.clear(); textEditingController.clear();
} }
} }
if (widget.initText != oldWidget.initText && TencentUtils.checkString(widget.initText) != null) { if (widget.initText != oldWidget.initText &&
TencentUtils.checkString(widget.initText) != null) {
textEditingController.text = widget.initText!; textEditingController.text = widget.initText!;
focusNode.requestFocus(); focusNode.requestFocus();
} }
@ -792,8 +902,12 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
Future<bool> getMemberMuteStatus(String userID) async { Future<bool> getMemberMuteStatus(String userID) async {
// Get the mute state of the members recursively // Get the mute state of the members recursively
if (widget.model.groupMemberList?.any((item) => (item?.userID == userID)) ?? false) { if (widget.model.groupMemberList?.any((item) => (item?.userID == userID)) ??
final int muteUntil = widget.model.groupMemberList?.firstWhere((item) => (item?.userID == userID))?.muteUntil ?? 0; false) {
final int muteUntil = widget.model.groupMemberList
?.firstWhere((item) => (item?.userID == userID))
?.muteUntil ??
0;
return muteUntil * 1000 > DateTime.now().millisecondsSinceEpoch; return muteUntil * 1000 > DateTime.now().millisecondsSinceEpoch;
} else { } else {
return false; return false;
@ -806,22 +920,30 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} }
final int selfRole = widget.model.selfMemberInfo?.role ?? 0; final int selfRole = widget.model.selfMemberInfo?.role ?? 0;
final bool willNotBeenMuted = (selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN || selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER); final bool willNotBeenMuted =
(selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN ||
selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER);
if (widget.conversationType == ConvType.group && !willNotBeenMuted) { if (widget.conversationType == ConvType.group && !willNotBeenMuted) {
if ((model.groupInfo?.isAllMuted ?? false) && muteStatus != MuteStatus.all) { if ((model.groupInfo?.isAllMuted ?? false) &&
muteStatus != MuteStatus.all) {
Future.delayed(const Duration(seconds: 0), () { Future.delayed(const Duration(seconds: 0), () {
setState(() { setState(() {
muteStatus = MuteStatus.all; muteStatus = MuteStatus.all;
}); });
}); });
} else if (selfModel.loginInfo?.userID != null && await getMemberMuteStatus(selfModel.loginInfo!.userID!) && muteStatus != MuteStatus.me) { } else if (selfModel.loginInfo?.userID != null &&
await getMemberMuteStatus(selfModel.loginInfo!.userID!) &&
muteStatus != MuteStatus.me) {
Future.delayed(const Duration(seconds: 0), () { Future.delayed(const Duration(seconds: 0), () {
setState(() { setState(() {
muteStatus = MuteStatus.me; muteStatus = MuteStatus.me;
}); });
}); });
} else if (!(model.groupInfo?.isAllMuted ?? false) && !(selfModel.loginInfo?.userID != null && await getMemberMuteStatus(selfModel.loginInfo!.userID!)) && muteStatus != MuteStatus.none) { } else if (!(model.groupInfo?.isAllMuted ?? false) &&
!(selfModel.loginInfo?.userID != null &&
await getMemberMuteStatus(selfModel.loginInfo!.userID!)) &&
muteStatus != MuteStatus.none) {
Future.delayed(const Duration(seconds: 0), () { Future.delayed(const Duration(seconds: 0), () {
setState(() { setState(() {
muteStatus = MuteStatus.none; muteStatus = MuteStatus.none;
@ -850,7 +972,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
@override @override
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final theme = value.theme; final theme = value.theme;
final TUIChatSeparateViewModel model = Provider.of<TUIChatSeparateViewModel>(context); final TUIChatSeparateViewModel model =
Provider.of<TUIChatSeparateViewModel>(context);
_getMuteType(model); _getMuteType(model);
@ -870,7 +993,8 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} }
final forbiddenText = getForbiddenText(); final forbiddenText = getForbiddenText();
return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
inputWidth = constraints.maxWidth; inputWidth = constraints.maxWidth;
return TUIKitScreenUtils.getDeviceWidget( return TUIKitScreenUtils.getDeviceWidget(
context: context, context: context,

View File

@ -132,10 +132,12 @@ class TIMUIKitTextFieldLayoutNarrow extends StatefulWidget {
: super(key: key); : super(key: key);
@override @override
State<TIMUIKitTextFieldLayoutNarrow> createState() => _TIMUIKitTextFieldLayoutNarrowState(); State<TIMUIKitTextFieldLayoutNarrow> createState() =>
_TIMUIKitTextFieldLayoutNarrowState();
} }
class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFieldLayoutNarrow> { class _TIMUIKitTextFieldLayoutNarrowState
extends TIMUIKitState<TIMUIKitTextFieldLayoutNarrow> {
final TUISettingModel settingModel = serviceLocator<TUISettingModel>(); final TUISettingModel settingModel = serviceLocator<TUISettingModel>();
bool showMore = false; bool showMore = false;
@ -209,14 +211,13 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
}, },
addCustomEmojiText: ((String singleEmojiName) { addCustomEmojiText: ((String singleEmojiName) {
String? emojiName = singleEmojiName.split('.png')[0]; String? emojiName = singleEmojiName.split('.png')[0];
if (widget.isUseDefaultEmoji && widget.languageType == 'zh' && TUIKitStickerConstData.emojiMapList[emojiName] != null && TUIKitStickerConstData.emojiMapList[emojiName] != '') { final newText = TIM_t('[$emojiName]');
emojiName = TUIKitStickerConstData.emojiMapList[emojiName];
}
final newText = '[$emojiName]';
widget.addStickerToText(newText); widget.addStickerToText(newText);
setSendButton(); setSendButton();
}), }),
defaultCustomEmojiStickerList: widget.isUseDefaultEmoji ? TUIKitStickerConstData.emojiList : []) defaultCustomEmojiStickerList: widget.isUseDefaultEmoji
? TUIKitStickerConstData.emojiList
: [])
: StickerPanel( : StickerPanel(
isWideScreen: false, isWideScreen: false,
sendTextMsg: () { sendTextMsg: () {
@ -236,10 +237,7 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
}, },
addCustomEmojiText: ((String singleEmojiName) { addCustomEmojiText: ((String singleEmojiName) {
String? emojiName = singleEmojiName.split('.png')[0]; String? emojiName = singleEmojiName.split('.png')[0];
if (widget.isUseDefaultEmoji && widget.languageType == 'zh' && TUIKitStickerConstData.emojiMapList[emojiName] != null && TUIKitStickerConstData.emojiMapList[emojiName] != '') { final newText = TIM_t('[$emojiName]');
emojiName = TUIKitStickerConstData.emojiMapList[emojiName];
}
final newText = '[$emojiName]';
widget.addStickerToText(newText); widget.addStickerToText(newText);
setSendButton(); setSendButton();
}), }),
@ -248,7 +246,10 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
} }
if (showMore) { if (showMore) {
return MorePanel(morePanelConfig: widget.morePanelConfig, conversationID: widget.conversationID, conversationType: widget.conversationType); return MorePanel(
morePanelConfig: widget.morePanelConfig,
conversationID: widget.conversationID,
conversationType: widget.conversationType);
} }
return const SizedBox(height: 0); return const SizedBox(height: 0);
@ -270,7 +271,8 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
return height; return height;
} else if (showMore || showEmojiPanel) { } else if (showMore || showEmojiPanel) {
return 248.0 + (bottomPadding ?? 0.0); return 248.0 + (bottomPadding ?? 0.0);
} else if (widget.textEditingController.text.length >= 46 && showKeyboard == false) { } else if (widget.textEditingController.text.length >= 46 &&
showKeyboard == false) {
return 25 + (bottomPadding ?? 0.0); return 25 + (bottomPadding ?? 0.0);
} else { } else {
return bottomPadding ?? 0; return bottomPadding ?? 0;
@ -323,14 +325,20 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
} }
String getAbstractMessage(V2TimMessage message) { String getAbstractMessage(V2TimMessage message) {
final String? customAbstractMessage = widget.model.abstractMessageBuilder != null ? widget.model.abstractMessageBuilder!(message) : null; final String? customAbstractMessage =
return customAbstractMessage ?? MessageUtils.getAbstractMessageAsync(message, widget.model.groupMemberList ?? []); widget.model.abstractMessageBuilder != null
? widget.model.abstractMessageBuilder!(message)
: null;
return customAbstractMessage ??
MessageUtils.getAbstractMessageAsync(
message, widget.model.groupMemberList ?? []);
} }
_buildRepliedMessage(V2TimMessage? repliedMessage) { _buildRepliedMessage(V2TimMessage? repliedMessage) {
final haveRepliedMessage = repliedMessage != null; final haveRepliedMessage = repliedMessage != null;
if (haveRepliedMessage) { if (haveRepliedMessage) {
final String text = "${MessageUtils.getDisplayName(repliedMessage)}:${getAbstractMessage(repliedMessage)}"; final String text =
"${MessageUtils.getDisplayName(repliedMessage)}:${getAbstractMessage(repliedMessage)}";
return Container( return Container(
color: widget.backgroundColor ?? hexToColor("f5f5f6"), color: widget.backgroundColor ?? hexToColor("f5f5f6"),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
@ -411,7 +419,8 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
child: Column( child: Column(
children: [ children: [
Container( Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), padding:
const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
constraints: const BoxConstraints(minHeight: 50), constraints: const BoxConstraints(minHeight: 50),
child: Row( child: Row(
children: [ children: [
@ -435,24 +444,28 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
} }
}, },
child: SvgPicture.asset( child: SvgPicture.asset(
showSendSoundText ? 'images/keyboard.svg' : 'images/voice.svg', showSendSoundText
? 'images/keyboard.svg'
: 'images/voice.svg',
package: 'tencent_cloud_chat_uikit', package: 'tencent_cloud_chat_uikit',
color: const Color.fromRGBO(68, 68, 68, 1), color: const Color.fromRGBO(68, 68, 68, 1),
height: 28, height: 28,
width: 28, width: 28,
), ),
), ),
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
Expanded( Expanded(
child: showSendSoundText child: showSendSoundText
? SendSoundMessage(onDownBottom: widget.goDownBottom, conversationID: widget.conversationID, conversationType: widget.conversationType) ? SendSoundMessage(
: Stack( onDownBottom: widget.goDownBottom,
children: [ conversationID: widget.conversationID,
Center( conversationType: widget.conversationType)
child: KeyboardVisibility( : Stack(children: [
child: ExtendedTextField( Center(
child: KeyboardVisibility(
child: ExtendedTextField(
maxLines: 4, maxLines: 4,
minLines: 1, minLines: 1,
focusNode: widget.focusNode, focusNode: widget.focusNode,
@ -466,19 +479,24 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
}); });
}, },
keyboardType: TextInputType.multiline, keyboardType: TextInputType.multiline,
textInputAction: PlatformUtils().isAndroid ? TextInputAction.newline : TextInputAction.send, textInputAction:
PlatformUtils().isAndroid
? TextInputAction.newline
: TextInputAction.send,
onEditingComplete: () { onEditingComplete: () {
widget.onSubmitted(); widget.onSubmitted();
if (showKeyboard) { if (showKeyboard) {
widget.focusNode.requestFocus(); widget.focusNode.requestFocus();
} }
setState(() { setState(() {
if (widget.textEditingController.text.isEmpty) { if (widget.textEditingController
.text.isEmpty) {
showMoreButton = true; showMoreButton = true;
} }
}); });
}, },
textAlignVertical: TextAlignVertical.top, textAlignVertical:
TextAlignVertical.top,
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
hintStyle: const TextStyle( hintStyle: const TextStyle(
@ -489,41 +507,52 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
filled: true, filled: true,
isDense: true, isDense: true,
hintText: widget.hintText ?? ''), hintText: widget.hintText ?? ''),
controller: widget.textEditingController, controller:
specialTextSpanBuilder: PlatformUtils().isWeb widget.textEditingController,
specialTextSpanBuilder: PlatformUtils()
.isWeb
? null ? null
: DefaultSpecialTextSpanBuilder( : DefaultSpecialTextSpanBuilder(
isUseQQPackage: (widget.model.chatConfig.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? true) || widget.isUseDefaultEmoji, isUseTencentCloudChatPackage:
isUseTencentCloudChatPackage: widget.model.chatConfig.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? true, widget
customEmojiStickerList: widget.customEmojiStickerList, .model
.chatConfig
.stickerPanelConfig
?.useTencentCloudChatStickerPackage ??
true,
customEmojiStickerList: widget
.customEmojiStickerList,
showAtBackground: true, showAtBackground: true,
checkHttpLink: false, checkHttpLink: false,
)), )),
onChanged: (bool visibility) { onChanged: (bool visibility) {
if (showKeyboard != visibility) { if (showKeyboard != visibility) {
setState(() { setState(() {
showKeyboard = visibility; showKeyboard = visibility;
}); });
}
}),
),
RawKeyboardListener(
autofocus: true,
focusNode: FocusNode(),
onKey: (key) {
if (key is RawKeyDownEvent && key.logicalKey == LogicalKeyboardKey.backspace) {
if (widget.onDeleteText != null) {
widget.onDeleteText!(widget.textEditingController.text);
}
} }
}, child: Container(), }),
),
]
), ),
), RawKeyboardListener(
const SizedBox( autofocus: true,
width: 10, focusNode: FocusNode(),
), onKey: (key) {
if (key is RawKeyDownEvent &&
key.logicalKey ==
LogicalKeyboardKey.backspace) {
if (widget.onDeleteText != null) {
widget.onDeleteText!(
widget.textEditingController.text);
}
}
},
child: Container(),
),
]),
),
const SizedBox(
width: 10,
),
if (widget.showSendEmoji) if (widget.showSendEmoji)
InkWell( InkWell(
onTap: () { onTap: () {
@ -531,18 +560,25 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
widget.goDownBottom(); widget.goDownBottom();
}, },
child: PlatformUtils().isWeb child: PlatformUtils().isWeb
? Icon(showEmojiPanel ? Icons.keyboard_alt_outlined : Icons.mood_outlined, color: hexToColor("5c6168"), size: 32) ? Icon(
showEmojiPanel
? Icons.keyboard_alt_outlined
: Icons.mood_outlined,
color: hexToColor("5c6168"),
size: 32)
: SvgPicture.asset( : SvgPicture.asset(
showEmojiPanel ? 'images/keyboard.svg' : 'images/face.svg', showEmojiPanel
? 'images/keyboard.svg'
: 'images/face.svg',
package: 'tencent_cloud_chat_uikit', package: 'tencent_cloud_chat_uikit',
color: const Color.fromRGBO(68, 68, 68, 1), color: const Color.fromRGBO(68, 68, 68, 1),
height: 28, height: 28,
width: 28, width: 28,
), ),
), ),
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
if (widget.showMorePanel && showMoreButton) if (widget.showMorePanel && showMoreButton)
InkWell( InkWell(
onTap: () { onTap: () {
@ -551,7 +587,8 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
widget.goDownBottom(); widget.goDownBottom();
}, },
child: PlatformUtils().isWeb child: PlatformUtils().isWeb
? Icon(Icons.add_circle_outline_outlined, color: hexToColor("5c6168"), size: 32) ? Icon(Icons.add_circle_outline_outlined,
color: hexToColor("5c6168"), size: 32)
: SvgPicture.asset( : SvgPicture.asset(
'images/add.svg', 'images/add.svg',
package: 'tencent_cloud_chat_uikit', package: 'tencent_cloud_chat_uikit',
@ -560,7 +597,8 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
width: 28, width: 28,
), ),
), ),
if ((isAndroidDevice() || isWebDevice()) && !showMoreButton) if ((isAndroidDevice() || isWebDevice()) &&
!showMoreButton)
SizedBox( SizedBox(
height: 32.0, height: 32.0,
child: ElevatedButton( child: ElevatedButton(
@ -582,7 +620,10 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
), ),
), ),
AnimatedContainer( AnimatedContainer(
duration: Duration(milliseconds: (showKeyboard && PlatformUtils().isAndroid) ? 200 : 340), duration: Duration(
milliseconds: (showKeyboard && PlatformUtils().isAndroid)
? 200
: 340),
curve: Curves.fastOutSlowIn, curve: Curves.fastOutSlowIn,
height: max(_getBottomHeight(), 0.0), height: max(_getBottomHeight(), 0.0),
child: ListView( child: ListView(

View File

@ -56,7 +56,9 @@ class DesktopControlBarItem {
required this.onClick, required this.onClick,
this.showName, this.showName,
this.size}) this.size})
: assert(icon != null || TencentUtils.checkString(imgPath) != null || TencentUtils.checkString(svgPath) != null); : assert(icon != null ||
TencentUtils.checkString(imgPath) != null ||
TencentUtils.checkString(svgPath) != null);
} }
class DesktopControlBarConfig { class DesktopControlBarConfig {
@ -188,10 +190,12 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget {
: super(key: key); : super(key: key);
@override @override
State<TIMUIKitTextFieldLayoutWide> createState() => _TIMUIKitTextFieldLayoutWideState(); State<TIMUIKitTextFieldLayoutWide> createState() =>
_TIMUIKitTextFieldLayoutWideState();
} }
class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldLayoutWide> { class _TIMUIKitTextFieldLayoutWideState
extends TIMUIKitState<TIMUIKitTextFieldLayoutWide> {
final TUISettingModel settingModel = serviceLocator<TUISettingModel>(); final TUISettingModel settingModel = serviceLocator<TUISettingModel>();
OverlayEntry? entry; OverlayEntry? entry;
final ImagePicker _picker = ImagePicker(); final ImagePicker _picker = ImagePicker();
@ -265,11 +269,13 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
} }
String getAbstractMessage(V2TimMessage message) { String getAbstractMessage(V2TimMessage message) {
final String? customAbstractMessage = widget.model.abstractMessageBuilder != null final String? customAbstractMessage =
? widget.model.abstractMessageBuilder!(widget.model.repliedMessage!) widget.model.abstractMessageBuilder != null
: null; ? widget.model.abstractMessageBuilder!(widget.model.repliedMessage!)
: null;
return customAbstractMessage ?? return customAbstractMessage ??
MessageUtils.getAbstractMessageAsync(widget.model.repliedMessage!, widget.model.groupMemberList ?? []); MessageUtils.getAbstractMessageAsync(
widget.model.repliedMessage!, widget.model.groupMemberList ?? []);
} }
_buildRepliedMessage(V2TimMessage? repliedMessage) { _buildRepliedMessage(V2TimMessage? repliedMessage) {
@ -292,7 +298,10 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
softWrap: true, softWrap: true,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle(color: hexToColor("8f959e"), fontSize: 14, fontWeight: FontWeight.bold), style: TextStyle(
color: hexToColor("8f959e"),
fontSize: 14,
fontWeight: FontWeight.bold),
), ),
Expanded( Expanded(
child: Text( child: Text(
@ -337,7 +346,8 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
}, },
initOffset: offset != null initOffset: offset != null
? Offset(offset.dx, max(offset.dy, 16)) ? Offset(offset.dx, max(offset.dy, 16))
: Offset(MediaQuery.of(context).size.height * 0.5 + 20, MediaQuery.of(context).size.height * 0.5 - 100), : Offset(MediaQuery.of(context).size.height * 0.5 + 20,
MediaQuery.of(context).size.height * 0.5 - 100),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(8)), borderRadius: const BorderRadius.all(Radius.circular(8)),
@ -375,18 +385,14 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
}, },
addCustomEmojiText: ((String singleEmojiName) { addCustomEmojiText: ((String singleEmojiName) {
String? emojiName = singleEmojiName.split('.png')[0]; String? emojiName = singleEmojiName.split('.png')[0];
if (widget.isUseDefaultEmoji && final newText = TIM_t('[$emojiName]');
widget.languageType == 'zh' &&
TUIKitStickerConstData.emojiMapList[emojiName] != null &&
TUIKitStickerConstData.emojiMapList[emojiName] != '') {
emojiName = TUIKitStickerConstData.emojiMapList[emojiName];
}
final newText = '[$emojiName]';
widget.addStickerToText(newText); widget.addStickerToText(newText);
entry?.remove(); entry?.remove();
entry = null; entry = null;
}), }),
defaultCustomEmojiStickerList: widget.isUseDefaultEmoji ? TUIKitStickerConstData.emojiList : []) defaultCustomEmojiStickerList: widget.isUseDefaultEmoji
? TUIKitStickerConstData.emojiList
: [])
: Material( : Material(
color: Colors.transparent, color: Colors.transparent,
child: StickerPanel( child: StickerPanel(
@ -409,14 +415,9 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
entry = null; entry = null;
}, },
addCustomEmojiText: ((String singleEmojiName) { addCustomEmojiText: ((String singleEmojiName) {
String? emojiName = singleEmojiName.split('.png')[0]; String? emojiName =
if (widget.isUseDefaultEmoji && singleEmojiName.split('.png')[0];
widget.languageType == 'zh' && final newText = TIM_t('[$emojiName]');
TUIKitStickerConstData.emojiMapList[emojiName] != null &&
TUIKitStickerConstData.emojiMapList[emojiName] != '') {
emojiName = TUIKitStickerConstData.emojiMapList[emojiName];
}
final newText = '[$emojiName]';
widget.addStickerToText(newText); widget.addStickerToText(newText);
entry?.remove(); entry?.remove();
entry = null; entry = null;
@ -467,11 +468,17 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
if (result != null && result.files.isNotEmpty) { if (result != null && result.files.isNotEmpty) {
if (PlatformUtils().isWeb) { if (PlatformUtils().isWeb) {
html.Node? inputElem; html.Node? inputElem;
inputElem = html.document.getElementById("__file_picker_web-file-input")?.querySelector("input"); inputElem = html.document
.getElementById("__file_picker_web-file-input")
?.querySelector("input");
fileName = result.files.single.name; fileName = result.files.single.name;
MessageUtils.handleMessageError( MessageUtils.handleMessageError(
model.sendFileMessage(inputElement: inputElem, fileName: fileName, convID: convID, convType: convType), model.sendFileMessage(
inputElement: inputElem,
fileName: fileName,
convID: convID,
convType: convType),
context); context);
} else { } else {
File file = File(result.files.single.path!); File file = File(result.files.single.path!);
@ -479,7 +486,12 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
final String savePath = file.path; final String savePath = file.path;
MessageUtils.handleMessageError( MessageUtils.handleMessageError(
model.sendFileMessage(filePath: savePath, size: size, convID: convID, convType: convType), context); model.sendFileMessage(
filePath: savePath,
size: size,
convID: convID,
convType: convType),
context);
} }
} else { } else {
throw TypeError(); throw TypeError();
@ -490,7 +502,8 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
} }
} }
List<Widget> generateBarIcons(List<DesktopControlBarItem> items, TUITheme theme) { List<Widget> generateBarIcons(
List<DesktopControlBarItem> items, TUITheme theme) {
final defaultItems = defaultControlBarItems.map((e) => e.item); final defaultItems = defaultControlBarItems.map((e) => e.item);
return items.map((e) { return items.map((e) {
final GlobalKey key = GlobalKey(); final GlobalKey key = GlobalKey();
@ -498,12 +511,15 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
margin: const EdgeInsets.only(right: 10), margin: const EdgeInsets.only(right: 10),
child: InkWell( child: InkWell(
onTap: () { onTap: () {
final alignBox = key.currentContext?.findRenderObject() as RenderBox?; final alignBox =
key.currentContext?.findRenderObject() as RenderBox?;
var offset = alignBox?.localToGlobal(Offset.zero); var offset = alignBox?.localToGlobal(Offset.zero);
final double? dx = (offset?.dx != null) ? offset!.dx : null; final double? dx = (offset?.dx != null) ? offset!.dx : null;
final double? dy = (offset?.dy != null && alignBox?.size.height != null) final double? dy =
? offset!.dy - (widget.chatConfig.desktopStickerPanelHeight + 20) (offset?.dy != null && alignBox?.size.height != null)
: null; ? offset!.dy -
(widget.chatConfig.desktopStickerPanelHeight + 20)
: null;
e.onClick((dx != null && dy != null) ? Offset(dx, dy) : null); e.onClick((dx != null && dy != null) ? Offset(dx, dy) : null);
}, },
child: Tooltip( child: Tooltip(
@ -517,7 +533,9 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
if (TencentUtils.checkString(e.svgPath) != null) { if (TencentUtils.checkString(e.svgPath) != null) {
return SvgPicture.asset( return SvgPicture.asset(
e.svgPath!, e.svgPath!,
package: defaultItems.contains(e.item) ? 'tencent_cloud_chat_uikit' : null, package: defaultItems.contains(e.item)
? 'tencent_cloud_chat_uikit'
: null,
key: key, key: key,
width: e.size ?? 16, width: e.size ?? 16,
height: e.size ?? 16, height: e.size ?? 16,
@ -526,7 +544,9 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
if (TencentUtils.checkString(e.imgPath) != null) { if (TencentUtils.checkString(e.imgPath) != null) {
return Image.asset( return Image.asset(
e.imgPath!, e.imgPath!,
package: defaultItems.contains(e.item) ? 'tencent_cloud_chat_uikit' : null, package: defaultItems.contains(e.item)
? 'tencent_cloud_chat_uikit'
: null,
key: key, key: key,
width: e.size ?? 16, width: e.size ?? 16,
height: e.size ?? 16, height: e.size ?? 16,
@ -555,12 +575,17 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
fileContent = imageContent; fileContent = imageContent;
html.Node? inputElem; html.Node? inputElem;
inputElem = html.document.getElementById("__image_picker_web-file-input")?.querySelector("input"); inputElem = html.document
.getElementById("__image_picker_web-file-input")
?.querySelector("input");
final convID = widget.conversationID; final convID = widget.conversationID;
final convType = widget.conversationType; final convType = widget.conversationType;
MessageUtils.handleMessageError( MessageUtils.handleMessageError(
model.sendImageMessage( model.sendImageMessage(
inputElement: inputElem, imagePath: tempFile?.path, convID: convID, convType: convType), inputElement: inputElem,
imagePath: tempFile?.path,
convID: convID,
convType: convType),
context); context);
} catch (e) { } catch (e) {
// ignore: avoid_print // ignore: avoid_print
@ -577,18 +602,25 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
fileContent = videoContent; fileContent = videoContent;
if (fileName!.split(".")[fileName!.split(".").length - 1] != "mp4") { if (fileName!.split(".")[fileName!.split(".").length - 1] != "mp4") {
onTIMCallback( onTIMCallback(TIMCallback(
TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频消息仅限 mp4 格式"), infoCode: 6660412)); type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("视频消息仅限 mp4 格式"),
infoCode: 6660412));
return; return;
} }
html.Node? inputElem; html.Node? inputElem;
inputElem = html.document.getElementById("__image_picker_web-file-input")?.querySelector("input"); inputElem = html.document
.getElementById("__image_picker_web-file-input")
?.querySelector("input");
final convID = widget.conversationID; final convID = widget.conversationID;
final convType = widget.conversationType; final convType = widget.conversationType;
MessageUtils.handleMessageError( MessageUtils.handleMessageError(
model.sendVideoMessage( model.sendVideoMessage(
inputElement: inputElem, videoPath: tempFile?.path, convID: convID, convType: convType), inputElement: inputElem,
videoPath: tempFile?.path,
convID: convID,
convType: convType),
context); context);
} catch (e) { } catch (e) {
// ignore: avoid_print // ignore: avoid_print
@ -602,8 +634,10 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
final originFile = await asset.originFile; final originFile = await asset.originFile;
final size = await originFile!.length(); final size = await originFile!.length();
if (size >= 104857600) { if (size >= 104857600) {
onTIMCallback( onTIMCallback(TIMCallback(
TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("发送失败,视频不能大于100MB"), infoCode: 6660405)); type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("发送失败,视频不能大于100MB"),
infoCode: 6660405));
return; return;
} }
@ -612,7 +646,9 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
final convID = widget.conversationID; final convID = widget.conversationID;
final convType = widget.conversationType; final convType = widget.conversationType;
String tempPath = (await getTemporaryDirectory()).path + p.extension(originFile.path, 3) + ".jpeg"; String tempPath = (await getTemporaryDirectory()).path +
p.extension(originFile.path, 3) +
".jpeg";
await plugin.getVideoThumbnail( await plugin.getVideoThumbnail(
srcFile: originFile.path, srcFile: originFile.path,
@ -624,14 +660,22 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
); );
MessageUtils.handleMessageError( MessageUtils.handleMessageError(
model.sendVideoMessage( model.sendVideoMessage(
videoPath: filePath, duration: duration, snapshotPath: tempPath, convID: convID, convType: convType), videoPath: filePath,
duration: duration,
snapshotPath: tempPath,
convID: convID,
convType: convType),
context); context);
} catch (e) { } catch (e) {
onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频文件异常"), infoCode: 6660415)); onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("视频文件异常"),
infoCode: 6660415));
} }
} }
_sendMediaMessage(TUIChatSeparateViewModel model, TUITheme theme, FileType fileType) async { _sendMediaMessage(
TUIChatSeparateViewModel model, TUITheme theme, FileType fileType) async {
try { try {
final convID = widget.conversationID; final convID = widget.conversationID;
final convType = widget.conversationType; final convType = widget.conversationType;
@ -647,7 +691,11 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
if (filePath != null) { if (filePath != null) {
if (type == AssetType.image) { if (type == AssetType.image) {
MessageUtils.handleMessageError( MessageUtils.handleMessageError(
model.sendImageMessage(imagePath: filePath, convID: convID, convType: convType), context); model.sendImageMessage(
imagePath: filePath,
convID: convID,
convType: convType),
context);
} }
if (type == AssetType.video) { if (type == AssetType.video) {
@ -659,20 +707,26 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
} else { } else {
final plugin = FcNativeVideoThumbnail(); final plugin = FcNativeVideoThumbnail();
_addGreyOverlay(); _addGreyOverlay();
FilePickerResult? result = await FilePicker.platform.pickFiles(type: fileType); FilePickerResult? result =
await FilePicker.platform.pickFiles(type: fileType);
_removeOverlay(); _removeOverlay();
if (result != null && result.files.isNotEmpty) { if (result != null && result.files.isNotEmpty) {
File file = File(result.files.single.path!); File file = File(result.files.single.path!);
final String savePath = file.path; final String savePath = file.path;
final String type = final String type = TencentUtils.getFileType(
TencentUtils.getFileType((savePath.split(".")[savePath.split(".").length - 1]).toLowerCase()) (savePath.split(".")[savePath.split(".").length - 1])
.split("/")[0]; .toLowerCase())
.split("/")[0];
if (type == "image") { if (type == "image") {
MessageUtils.handleMessageError( MessageUtils.handleMessageError(
model.sendImageMessage(imagePath: savePath, convID: convID, convType: convType), context); model.sendImageMessage(
imagePath: savePath, convID: convID, convType: convType),
context);
} else if (type == "video") { } else if (type == "video") {
String tempPath = (await getTemporaryDirectory()).path + p.basename(savePath) + ".jpeg"; String tempPath = (await getTemporaryDirectory()).path +
p.basename(savePath) +
".jpeg";
await plugin.getVideoThumbnail( await plugin.getVideoThumbnail(
srcFile: savePath, srcFile: savePath,
destFile: tempPath, destFile: tempPath,
@ -682,7 +736,11 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
height: 128, height: 128,
); );
MessageUtils.handleMessageError( MessageUtils.handleMessageError(
model.sendVideoMessage(videoPath: savePath, convID: convID, convType: convType, snapshotPath: tempPath), model.sendVideoMessage(
videoPath: savePath,
convID: convID,
convType: convType,
snapshotPath: tempPath),
context); context);
} }
} else { } else {
@ -692,13 +750,17 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
} catch (err) { } catch (err) {
// ignore: avoid_print // ignore: avoid_print
outputLogger.i("send media err: $err"); outputLogger.i("send media err: $err");
onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("视频文件异常"), infoCode: 6660415)); onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: TIM_t("视频文件异常"),
infoCode: 6660415));
} }
} }
_sendImageWithConfirmation({String? fileName, Size? fileSize, required String filePath}) async { _sendImageWithConfirmation(
final option1 = {String? fileName, Size? fileSize, required String filePath}) async {
widget.currentConversation.showName ?? (widget.conversationType == ConvType.group ? TIM_t("群聊") : TIM_t("对方")); final option1 = widget.currentConversation.showName ??
(widget.conversationType == ConvType.group ? TIM_t("群聊") : TIM_t("对方"));
final size = fileSize ?? await ScreenshotHelper.getImageSize(filePath); final size = fileSize ?? await ScreenshotHelper.getImageSize(filePath);
TUIKitWidePopup.showPopupWindow( TUIKitWidePopup.showPopupWindow(
@ -717,7 +779,9 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
height: min(360, size.height / 2), height: min(360, size.height / 2),
child: InkWell( child: InkWell(
onTap: () { onTap: () {
launchUrl(PlatformUtils().isWeb ? Uri.parse(filePath) : Uri.file(filePath)); launchUrl(PlatformUtils().isWeb
? Uri.parse(filePath)
: Uri.file(filePath));
}, },
child: PlatformUtils().isWeb child: PlatformUtils().isWeb
? Image.network( ? Image.network(
@ -770,7 +834,8 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
} }
generateDefaultControlBarItems() { generateDefaultControlBarItems() {
final DesktopControlBarConfig config = widget.chatConfig.desktopControlBarConfig ?? DesktopControlBarConfig(); final DesktopControlBarConfig config =
widget.chatConfig.desktopControlBarConfig ?? DesktopControlBarConfig();
final List<DesktopControlBarItem> itemsList = [ final List<DesktopControlBarItem> itemsList = [
if (config.showStickerPanel) if (config.showStickerPanel)
DesktopControlBarItem( DesktopControlBarItem(
@ -835,9 +900,13 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
keyword: '', keyword: '',
initMessageList: widget.model initMessageList: widget.model
.getOriginMessageList() .getOriginMessageList()
.getRange(0, min(widget.model.getOriginMessageList().length, 100)) .getRange(
0,
min(widget.model.getOriginMessageList().length,
100))
.toList(), .toList(),
onTapConversation: (V2TimConversation conversation, V2TimMessage? message) {}, onTapConversation: (V2TimConversation conversation,
V2TimMessage? message) {},
), ),
theme: widget.theme); theme: widget.theme);
}, },
@ -846,7 +915,8 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
defaultControlBarItems = itemsList; defaultControlBarItems = itemsList;
} }
List<Widget> generateControlBar(TUIChatSeparateViewModel model, TUITheme theme) { List<Widget> generateControlBar(
TUIChatSeparateViewModel model, TUITheme theme) {
final List<DesktopControlBarItem> itemsList = [ final List<DesktopControlBarItem> itemsList = [
...defaultControlBarItems, ...defaultControlBarItems,
...(widget.chatConfig.additionalDesktopControlBarItems ?? []) ...(widget.chatConfig.additionalDesktopControlBarItems ?? [])
@ -860,22 +930,29 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
final type = mimeType[0]; final type = mimeType[0];
final blobUrl = html.Url.createObjectUrl(file); final blobUrl = html.Url.createObjectUrl(file);
if (type == 'image') { if (type == 'image') {
_sendImageWithConfirmation(filePath: blobUrl, fileName: file.name, fileSize: const Size(500, 500)); _sendImageWithConfirmation(
filePath: blobUrl,
fileName: file.name,
fileSize: const Size(500, 500));
} }
} }
Future<void> _handleKeyEvent(RawKeyEvent event) async { Future<void> _handleKeyEvent(RawKeyEvent event) async {
if (PlatformUtils().isDesktop && if (PlatformUtils().isDesktop &&
((event.isKeyPressed(LogicalKeyboardKey.controlLeft) && event.logicalKey == LogicalKeyboardKey.keyV) || ((event.isKeyPressed(LogicalKeyboardKey.controlLeft) &&
(event.isMetaPressed && event.logicalKey == LogicalKeyboardKey.keyV))) { event.logicalKey == LogicalKeyboardKey.keyV) ||
(event.isMetaPressed &&
event.logicalKey == LogicalKeyboardKey.keyV))) {
final bytes = await Pasteboard.image; final bytes = await Pasteboard.image;
if (bytes != null) { if (bytes != null) {
String directory; String directory;
if (PlatformUtils().isWindows) { if (PlatformUtils().isWindows) {
final String documentsDirectoryPath = "${Platform.environment['USERPROFILE']}"; final String documentsDirectoryPath =
"${Platform.environment['USERPROFILE']}";
PackageInfo packageInfo = await PackageInfo.fromPlatform(); PackageInfo packageInfo = await PackageInfo.fromPlatform();
String pkgName = packageInfo.packageName; String pkgName = packageInfo.packageName;
directory = p.join(documentsDirectoryPath, "Documents", ".TencentCloudChat", pkgName, "screenshots"); directory = p.join(documentsDirectoryPath, "Documents",
".TencentCloudChat", pkgName, "screenshots");
} else { } else {
final dic = await getApplicationSupportDirectory(); final dic = await getApplicationSupportDirectory();
directory = dic.path; directory = dic.path;
@ -883,7 +960,8 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
const uuid = Uuid(); const uuid = Uuid();
final fileName = 'paste_image_${uuid.v4()}.png'; final fileName = 'paste_image_${uuid.v4()}.png';
final scDirectory = Directory(directory); final scDirectory = Directory(directory);
final filePath = '${scDirectory.path}${PlatformUtils().isWindows ? "\\" : "/"}$fileName'; final filePath =
'${scDirectory.path}${PlatformUtils().isWindows ? "\\" : "/"}$fileName';
final file = File(filePath); final file = File(filePath);
if (!await scDirectory.exists()) { if (!await scDirectory.exists()) {
await scDirectory.create(recursive: true); await scDirectory.create(recursive: true);
@ -924,61 +1002,67 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
child: Column( child: Column(
children: [ children: [
_buildRepliedMessage(widget.repliedMessage), _buildRepliedMessage(widget.repliedMessage),
SizedBox(height: 1, child: Container(color: theme.weakDividerColor ?? Colors.black12)), SizedBox(
Container( height: 1,
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12), child: Container(
child: Row( color: theme.weakDividerColor ?? Colors.black12)),
mainAxisAlignment: MainAxisAlignment.start, Container(
children: generateControlBar(widget.model, theme), padding:
), const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: generateControlBar(widget.model, theme),
), ),
),
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),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
child: ExtendedTextField( child: ExtendedTextField(
scrollController: _scrollController, scrollController: _scrollController,
autofocus: true, autofocus: true,
maxLines: widget.chatConfig.desktopMessageInputFieldLines, maxLines:
minLines: widget.chatConfig.desktopMessageInputFieldLines, widget.chatConfig.desktopMessageInputFieldLines,
focusNode: widget.focusNode, minLines:
onChanged: debounceFunc, widget.chatConfig.desktopMessageInputFieldLines,
keyboardType: TextInputType.multiline, focusNode: widget.focusNode,
onEditingComplete: () { onChanged: debounceFunc,
// // widget.onSubmitted(); keyboardType: TextInputType.multiline,
}, onEditingComplete: () {
textAlignVertical: TextAlignVertical.top, // // widget.onSubmitted();
style: const TextStyle(fontSize: 14), },
decoration: InputDecoration( textAlignVertical: TextAlignVertical.top,
hoverColor: Colors.transparent, style: const TextStyle(fontSize: 14),
border: InputBorder.none, decoration: InputDecoration(
hintStyle: const TextStyle( hoverColor: Colors.transparent,
color: Color(0xffAEA4A3), border: InputBorder.none,
), hintStyle: const TextStyle(
fillColor: widget.backgroundColor ?? color: Color(0xffAEA4A3),
theme.desktopChatMessageInputBgColor ??
hexToColor("fafafa"),
filled: true,
isDense: true,
hintText: widget.hintText ?? '',
), ),
controller: widget.textEditingController, fillColor: widget.backgroundColor ??
specialTextSpanBuilder: PlatformUtils().isWeb theme.desktopChatMessageInputBgColor ??
? null hexToColor("fafafa"),
: DefaultSpecialTextSpanBuilder( filled: true,
isUseQQPackage: (widget.model.chatConfig.stickerPanelConfig isDense: true,
?.useTencentCloudChatStickerPackage ?? hintText: widget.hintText ?? '',
true) || ),
widget.isUseDefaultEmoji, controller: widget.textEditingController,
isUseTencentCloudChatPackage: specialTextSpanBuilder: PlatformUtils().isWeb
widget.model.chatConfig.stickerPanelConfig?.useTencentCloudChatStickerPackage ?? ? null
true, : DefaultSpecialTextSpanBuilder(
customEmojiStickerList: widget.customEmojiStickerList, isUseTencentCloudChatPackage: widget
showAtBackground: true, .model
)), .chatConfig
), .stickerPanelConfig
?.useTencentCloudChatStickerPackage ??
true,
customEmojiStickerList:
widget.customEmojiStickerList,
showAtBackground: true,
)),
),
], ],
), ),
), ),

View File

@ -54,7 +54,8 @@ class TIMUIKitChat extends StatefulWidget {
final ConvType? conversationType; final ConvType? conversationType;
/// use for customize avatar /// use for customize avatar
final Widget Function(BuildContext context, V2TimMessage message)? userAvatarBuilder; final Widget Function(BuildContext context, V2TimMessage message)?
userAvatarBuilder;
/// Use for show conversation name. /// Use for show conversation name.
/// This field is not necessary to be provided, when `conversation` is provided, unless you want to cover this field manually. /// This field is not necessary to be provided, when `conversation` is provided, unless you want to cover this field manually.
@ -64,9 +65,11 @@ class TIMUIKitChat extends StatefulWidget {
final void Function(String userID, TapDownDetails tapDetails)? onTapAvatar; final void Function(String userID, TapDownDetails tapDetails)? onTapAvatar;
/// 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)? onSecondaryTapAvatar; final void Function(String userID, TapDownDetails tapDetails)?
onSecondaryTapAvatar;
@Deprecated("Nickname will not shows in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead") @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")
/// Should show the nick name. /// Should show the nick name.
final bool showNickName; final bool showNickName;
@ -78,10 +81,12 @@ class TIMUIKitChat extends StatefulWidget {
final bool showTotalUnReadCount; final bool showTotalUnReadCount;
/// Deprecated("Please use [extraTipsActionItemBuilder] instead") /// Deprecated("Please use [extraTipsActionItemBuilder] instead")
final Widget? Function(V2TimMessage message, Function() closeTooltip, [Key? key, BuildContext? context])? exteraTipsActionItemBuilder; final Widget? Function(V2TimMessage message, Function() closeTooltip,
[Key? key, BuildContext? context])? exteraTipsActionItemBuilder;
/// The builder for extra tips action. /// The builder for extra tips action.
final Widget? Function(V2TimMessage message, Function() closeTooltip, [Key? key, BuildContext? context])? extraTipsActionItemBuilder; final Widget? Function(V2TimMessage message, Function() closeTooltip,
[Key? key, BuildContext? context])? extraTipsActionItemBuilder;
/// The text of draft shows in TextField. /// The text of draft shows in TextField.
/// [Recommend]: You can specify this field with the draftText from V2TimConversation. /// [Recommend]: You can specify this field with the draftText from V2TimConversation.
@ -172,10 +177,13 @@ class TIMUIKitChat extends StatefulWidget {
this.conversationShowName, this.conversationShowName,
this.abstractMessageBuilder, this.abstractMessageBuilder,
this.onTapAvatar, this.onTapAvatar,
@Deprecated("Nickname will not show in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead") this.showNickName = false, @Deprecated(
"Nickname will not show in one-to-one chat, if you tend to control it in group chat, please use `isShowSelfNameInGroup` and `isShowOthersNameInGroup` from `config: TIMUIKitChatConfig` instead")
this.showNickName = false,
this.showTotalUnReadCount = false, this.showTotalUnReadCount = false,
this.messageItemBuilder, this.messageItemBuilder,
@Deprecated("Please use [extraTipsActionItemBuilder] instead") this.exteraTipsActionItemBuilder, @Deprecated("Please use [extraTipsActionItemBuilder] instead")
this.exteraTipsActionItemBuilder,
this.extraTipsActionItemBuilder, this.extraTipsActionItemBuilder,
this.draftText, this.draftText,
this.textFieldHintText, this.textFieldHintText,
@ -209,24 +217,30 @@ class TIMUIKitChat extends StatefulWidget {
class _TUIChatState extends TIMUIKitState<TIMUIKitChat> { class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
TUIChatSeparateViewModel model = TUIChatSeparateViewModel(); TUIChatSeparateViewModel model = TUIChatSeparateViewModel();
final TUISelfInfoViewModel selfInfoViewModel = serviceLocator<TUISelfInfoViewModel>(); final TUISelfInfoViewModel selfInfoViewModel =
serviceLocator<TUISelfInfoViewModel>();
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>(); final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
final TUIConversationViewModel conversationViewModel = serviceLocator<TUIConversationViewModel>(); final TUIConversationViewModel conversationViewModel =
TIMUIKitInputTextFieldController textFieldController = TIMUIKitInputTextFieldController(); serviceLocator<TUIConversationViewModel>();
TIMUIKitInputTextFieldController textFieldController =
TIMUIKitInputTextFieldController();
bool isInit = false; bool isInit = false;
final TUIChatGlobalModel chatGlobalModel = serviceLocator<TUIChatGlobalModel>(); final TUIChatGlobalModel chatGlobalModel =
serviceLocator<TUIChatGlobalModel>();
bool _dragging = false; bool _dragging = false;
final GlobalKey alignKey = GlobalKey(); final GlobalKey alignKey = GlobalKey();
final GlobalKey listContainerKey = GlobalKey(); final GlobalKey listContainerKey = GlobalKey();
late AutoScrollController autoController = AutoScrollController( late AutoScrollController autoController = AutoScrollController(
viewportBoundaryGetter: () => Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom), viewportBoundaryGetter: () =>
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: () => Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom), viewportBoundaryGetter: () =>
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
axis: Axis.vertical, axis: Axis.vertical,
); );
@ -293,7 +307,11 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
updateDraft() async { updateDraft() async {
final isTopic = widget.conversation.conversationID.contains("@TOPIC#"); final isTopic = widget.conversation.conversationID.contains("@TOPIC#");
if (isTopic) { if (isTopic) {
final topicInfoList = await TencentImSDKPlugin.v2TIMManager.getGroupManager().getTopicInfoList(groupID: widget.groupID!, topicIDList: [widget.conversation.conversationID]); final topicInfoList = await TencentImSDKPlugin.v2TIMManager
.getGroupManager()
.getTopicInfoList(
groupID: widget.groupID!,
topicIDList: [widget.conversation.conversationID]);
final topicInfo = topicInfoList.data?.first.topicInfo; final topicInfo = topicInfoList.data?.first.topicInfo;
final draftText = topicInfo?.draftText; final draftText = topicInfo?.draftText;
if (TencentUtils.checkString(draftText) != null) { if (TencentUtils.checkString(draftText) != null) {
@ -318,7 +336,8 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text( Text(
TIM_t_para("{{option1}} 条入群请求", "$option1 条入群请求")(option1: option1), TIM_t_para("{{option1}} 条入群请求", "$option1 条入群请求")(
option1: option1),
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
), ),
@ -337,11 +356,17 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
} }
String _getTitle() { String _getTitle() {
return TencentUtils.checkString(widget.conversationShowName) ?? widget.conversation.showName ?? "Chat"; return TencentUtils.checkString(widget.conversationShowName) ??
widget.conversation.showName ??
"Chat";
} }
String _getConvID() { String _getConvID() {
return TencentUtils.checkString(widget.conversationID) ?? (widget.conversation.type == 1 ? widget.conversation.userID : widget.conversation.groupID) ?? ""; return TencentUtils.checkString(widget.conversationID) ??
(widget.conversation.type == 1
? widget.conversation.userID
: widget.conversation.groupID) ??
"";
} }
ConvType _getConvType() { ConvType _getConvType() {
@ -352,9 +377,9 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
if (_getConvType() != ConvType.group) { if (_getConvType() != ConvType.group) {
return; return;
} }
final w = await TUICore.instance.raiseExtension(TUIExtensionID.joinInGroup, {GROUP_ID: widget.conversationID!}); final w = await TUICore.instance.raiseExtension(
if(w != _joinInGroupCallWidget){ TUIExtensionID.joinInGroup, {GROUP_ID: widget.conversationID!});
if (w != _joinInGroupCallWidget) {
setState(() { setState(() {
_joinInGroupCallWidget = w; _joinInGroupCallWidget = w;
}); });
@ -383,22 +408,28 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
Provider(create: (_) => widget.config), Provider(create: (_) => widget.config),
], ],
builder: (context, model, w) { builder: (context, model, w) {
final TUIChatGlobalModel chatGlobalModel = Provider.of<TUIChatGlobalModel>(context, listen: true); final TUIChatGlobalModel chatGlobalModel =
Provider.of<TUIChatGlobalModel>(context, listen: true);
widget.controller?.model = model; widget.controller?.model = model;
widget.controller?.textFieldController = textFieldController; widget.controller?.textFieldController = textFieldController;
widget.controller?.scrollController = autoController; widget.controller?.scrollController = autoController;
List<V2TimGroupApplication> filteredApplicationList = []; List<V2TimGroupApplication> filteredApplicationList = [];
if (widget.conversationType == ConvType.group && widget.onDealWithGroupApplication != null) { if (widget.conversationType == ConvType.group &&
filteredApplicationList = chatGlobalModel.groupApplicationList.where((item) { widget.onDealWithGroupApplication != null) {
return (item.groupID == widget.conversationID) && item.handleStatus == 0; filteredApplicationList =
chatGlobalModel.groupApplicationList.where((item) {
return (item.groupID == widget.conversationID) &&
item.handleStatus == 0;
}).toList(); }).toList();
} }
final selfUserID = selfInfoViewModel.loginInfo?.userID; final selfUserID = selfInfoViewModel.loginInfo?.userID;
final TUIGroupListenerModel groupListenerModel = Provider.of<TUIGroupListenerModel>(context, listen: true); final TUIGroupListenerModel groupListenerModel =
Provider.of<TUIGroupListenerModel>(context, listen: true);
final NeedUpdate? needUpdate = groupListenerModel.needUpdate; final NeedUpdate? needUpdate = groupListenerModel.needUpdate;
if (needUpdate != null && needUpdate.groupID == widget.conversationID) { if (needUpdate != null &&
needUpdate.groupID == widget.conversationID) {
groupListenerModel.needUpdate = null; groupListenerModel.needUpdate = null;
switch (needUpdate.updateType) { switch (needUpdate.updateType) {
case UpdateType.groupInfo: case UpdateType.groupInfo:
@ -416,13 +447,24 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
} }
List<CustomEmojiFaceData> customImageSmallPngEmojiPackages = []; List<CustomEmojiFaceData> customImageSmallPngEmojiPackages = [];
if (widget.config?.stickerPanelConfig?.customStickerPackages != null && widget.config!.stickerPanelConfig!.customStickerPackages.isNotEmpty) { if (widget.config?.stickerPanelConfig?.customStickerPackages !=
customImageSmallPngEmojiPackages = widget.config!.stickerPanelConfig!.customStickerPackages.where((element) => element.isEmoji == true).map((e) { null &&
return CustomEmojiFaceData(name: e.name, isEmoji: true, icon: e.menuItem.url ?? "", list: e.stickerList.map((e) => e.url ?? "").toList()); widget.config!.stickerPanelConfig!.customStickerPackages
.isNotEmpty) {
customImageSmallPngEmojiPackages = widget
.config!.stickerPanelConfig!.customStickerPackages
.where((element) => element.isEmoji == true)
.map((e) {
return CustomEmojiFaceData(
name: e.name,
isEmoji: true,
icon: e.menuItem.url ?? "",
list: e.stickerList.map((e) => e.url ?? "").toList());
}).toList(); }).toList();
} }
if (customImageSmallPngEmojiPackages.isEmpty) { if (customImageSmallPngEmojiPackages.isEmpty) {
customImageSmallPngEmojiPackages.addAll(widget.customEmojiStickerList); customImageSmallPngEmojiPackages
.addAll(widget.customEmojiStickerList);
} }
return GestureDetector( return GestureDetector(
@ -437,14 +479,21 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
config: widget.appBarConfig, config: widget.appBarConfig,
conversationShowName: _getTitle(), conversationShowName: _getTitle(),
conversationID: _getConvID(), conversationID: _getConvID(),
showC2cMessageEditStatus: widget.config?.showC2cMessageEditStatus ?? true, showC2cMessageEditStatus:
widget.config?.showC2cMessageEditStatus ?? true,
) )
: null, : null,
body: DropTarget( body: DropTarget(
onDragDone: (detail) { onDragDone: (detail) {
setState(() { setState(() {
_dragging = false; _dragging = false;
sendFileWithConfirmation(files: detail.files, conversation: widget.conversation, conversationType: _getConvType(), model: model, theme: theme, context: context); sendFileWithConfirmation(
files: detail.files,
conversation: widget.conversation,
conversationType: _getConvType(),
model: model,
theme: theme,
context: context);
}); });
}, },
onDragEntered: (detail) { onDragEntered: (detail) {
@ -463,9 +512,12 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (widget.customAppBar != null) widget.customAppBar!, if (widget.customAppBar != null) widget.customAppBar!,
if (filteredApplicationList.isNotEmpty) _renderJoinGroupApplication(filteredApplicationList.length, theme), if (filteredApplicationList.isNotEmpty)
_renderJoinGroupApplication(
filteredApplicationList.length, theme),
if (widget.topFixWidget != null) widget.topFixWidget!, if (widget.topFixWidget != null) widget.topFixWidget!,
if (_joinInGroupCallWidget != null) Center(child: _joinInGroupCallWidget!), if (_joinInGroupCallWidget != null)
Center(child: _joinInGroupCallWidget!),
Expanded( Expanded(
child: Container( child: Container(
color: theme.chatBgColor, color: theme.chatBgColor,
@ -474,31 +526,43 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: Listener( child: Listener(
child: TIMUIKitHistoryMessageListContainer( child: TIMUIKitHistoryMessageListContainer(
customMessageHoverBarOnDesktop: widget.customMessageHoverBarOnDesktop, customMessageHoverBarOnDesktop:
widget.customMessageHoverBarOnDesktop,
conversation: widget.conversation, conversation: widget.conversation,
groupMemberInfo: model.groupMemberList?.firstWhere((element) => element?.userID == selfUserID, orElse: () => null), groupMemberInfo: model.groupMemberList
?.firstWhere(
(element) =>
element?.userID == selfUserID,
orElse: () => null),
textFieldController: textFieldController, textFieldController: textFieldController,
customEmojiStickerList: widget.customEmojiStickerList, customEmojiStickerList:
isUseDefaultEmoji: widget.config!.isUseDefaultEmoji, widget.customEmojiStickerList,
key: listContainerKey, key: listContainerKey,
isAllowScroll: true, isAllowScroll: true,
userAvatarBuilder: widget.userAvatarBuilder, userAvatarBuilder: widget.userAvatarBuilder,
toolTipsConfig: widget.toolTipsConfig, toolTipsConfig: widget.toolTipsConfig,
groupAtInfoList: widget.groupAtInfoList, groupAtInfoList: widget.groupAtInfoList,
tongueItemBuilder: widget.tongueItemBuilder, tongueItemBuilder: widget.tongueItemBuilder,
onLongPressForOthersHeadPortrait: (String? userId, String? nickName) { onLongPressForOthersHeadPortrait:
textFieldController.longPressToAt(nickName, userId); (String? userId, String? nickName) {
textFieldController.longPressToAt(
nickName, userId);
}, },
mainHistoryListConfig: widget.mainHistoryListConfig, mainHistoryListConfig:
widget.mainHistoryListConfig,
initFindingMsg: widget.initFindingMsg, initFindingMsg: widget.initFindingMsg,
extraTipsActionItemBuilder: widget.extraTipsActionItemBuilder ?? widget.exteraTipsActionItemBuilder, extraTipsActionItemBuilder:
widget.extraTipsActionItemBuilder ??
widget.exteraTipsActionItemBuilder,
conversationType: _getConvType(), conversationType: _getConvType(),
scrollController: autoController, scrollController: autoController,
onSecondaryTapAvatar: widget.onSecondaryTapAvatar, 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: widget.messageItemBuilder, messageItemBuilder:
widget.messageItemBuilder,
conversationID: _getConvID(), conversationID: _getConvID(),
), ),
)), )),
@ -515,26 +579,45 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
: TIMUIKitInputTextField( : TIMUIKitInputTextField(
chatConfig: widget.config, chatConfig: widget.config,
groupID: widget.groupID, groupID: widget.groupID,
atMemberPanelScroll: atMemberPanelScroll, atMemberPanelScroll:
groupType: widget.conversation.groupType, atMemberPanelScroll,
currentConversation: widget.conversation, groupType:
widget.conversation.groupType,
currentConversation:
widget.conversation,
model: model, model: model,
controller: textFieldController, controller: textFieldController,
customEmojiStickerList: customImageSmallPngEmojiPackages, customEmojiStickerList:
isUseDefaultEmoji: widget.config!.isUseDefaultEmoji, customImageSmallPngEmojiPackages,
customStickerPanel: widget.customStickerPanel, customStickerPanel:
morePanelConfig: widget.morePanelConfig, widget.customStickerPanel,
morePanelConfig:
widget.morePanelConfig,
scrollController: autoController, scrollController: autoController,
conversationID: _getConvID(), conversationID: _getConvID(),
conversationType: _getConvType(), conversationType: _getConvType(),
initText: TencentUtils.checkString(widget.draftText) ?? initText: TencentUtils.checkString(
widget.draftText) ??
(PlatformUtils().isWeb (PlatformUtils().isWeb
? TencentUtils.checkString(conversationViewModel.getWebDraft(conversationID: widget.conversation.conversationID)) ? TencentUtils.checkString(
: TencentUtils.checkString(widget.conversation.draftText)), conversationViewModel
.getWebDraft(
conversationID: widget
.conversation
.conversationID))
: TencentUtils.checkString(
widget.conversation
.draftText)),
hintText: widget.textFieldHintText, hintText: widget.textFieldHintText,
showMorePanel: widget.config?.isAllowShowMorePanel ?? true, showMorePanel: widget.config
showSendAudio: widget.config?.isAllowSoundMessage ?? true, ?.isAllowShowMorePanel ??
showSendEmoji: widget.config?.isAllowEmojiPanel ?? true, true,
showSendAudio: widget.config
?.isAllowSoundMessage ??
true,
showSendEmoji: widget
.config?.isAllowEmojiPanel ??
true,
)); ));
}, },
selector: (c, model) { selector: (c, model) {
@ -549,7 +632,8 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
), ),
AtMemberPanel( AtMemberPanel(
atMemberPanelScroll: atMemberPanelScroll, atMemberPanelScroll: atMemberPanelScroll,
onSelectMember: (member) => textFieldController.handleAtMember(member), onSelectMember: (member) =>
textFieldController.handleAtMember(member),
) )
], ],
), ),
@ -562,12 +646,14 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
class TIMUIKitChatProviderScope extends StatelessWidget { class TIMUIKitChatProviderScope extends StatelessWidget {
final TUIChatGlobalModel globalModel = serviceLocator<TUIChatGlobalModel>(); final TUIChatGlobalModel globalModel = serviceLocator<TUIChatGlobalModel>();
TUIChatSeparateViewModel? model; TUIChatSeparateViewModel? model;
final TUIGroupListenerModel groupListenerModel = serviceLocator<TUIGroupListenerModel>(); final TUIGroupListenerModel groupListenerModel =
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?) builder; final Widget Function(BuildContext, TUIChatSeparateViewModel, Widget?)
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.
@ -638,13 +724,16 @@ class TIMUIKitChatProviderScope extends StatelessWidget {
preGroupMemberList: groupMemberList, preGroupMemberList: groupMemberList,
groupID: groupID, groupID: groupID,
); );
model?.showC2cMessageEditStatus = (conversationType == ConvType.c2c ? config?.showC2cMessageEditStatus ?? true : false); model?.showC2cMessageEditStatus = (conversationType == ConvType.c2c
? config?.showC2cMessageEditStatus ?? true
: false);
loadData(); loadData();
} }
loadData() { loadData() {
// if (model!.haveMoreData) { // if (model!.haveMoreData) {
model!.loadChatRecord(count: kIsWeb ? 15 : HistoryMessageDartConstant.getCount); model!.loadChatRecord(
count: kIsWeb ? 15 : HistoryMessageDartConstant.getCount);
// } // }
} }

View File

@ -24,29 +24,18 @@ class TimeDividerConfig {
/// StickerPanelConfig is a configuration class for the sticker panel component. /// StickerPanelConfig is a configuration class for the sticker panel component.
/// It allows customization of specific features such as display options for the /// It allows customization of specific features such as display options for the
/// message area, sticker packages, unicode emoji lists, and custom sticker packages. /// message area, sticker packages, and custom sticker packages.
class StickerPanelConfig { class StickerPanelConfig {
/// Determines whether to use the QQ Sticker Package.
/// Default value: true
final bool useQQStickerPackage;
/// Determines whether to use the Tencent Cloud Chat Sticker Package. /// Determines whether to use the Tencent Cloud Chat Sticker Package.
/// Default value: true /// Default value: true
final bool useTencentCloudChatStickerPackage; final bool useTencentCloudChatStickerPackage;
/// A list of unicode emoji, represented as integers.
/// Default value: a list of common Unicode Emojis.
/// To exclude Unicode Emoji from the display, pass an empty list.
final List<int> unicodeEmojiList;
/// A list of CustomStickerPackage instances, where each instance represents a sticker package. /// A list of CustomStickerPackage instances, where each instance represents a sticker package.
/// Default value: an empty list. /// Default value: an empty list.
final List<CustomStickerPackage> customStickerPackages; final List<CustomStickerPackage> customStickerPackages;
StickerPanelConfig({ StickerPanelConfig({
this.useQQStickerPackage = true,
this.useTencentCloudChatStickerPackage = true, this.useTencentCloudChatStickerPackage = true,
this.unicodeEmojiList = TUIKitStickerConstData.defaultUnicodeEmojiList,
this.customStickerPackages = const [], this.customStickerPackages = const [],
}); });
} }
@ -185,9 +174,6 @@ class TIMUIKitChatConfig {
/// The default action is opening the link with the default browser of system. /// The default action is opening the link with the default browser of system.
final void Function(String url)? onTapLink; final void Function(String url)? onTapLink;
/// Whether to use the default emoji
final bool isUseDefaultEmoji;
/// Whether shows avatar on history message list. /// Whether shows avatar on history message list.
/// [Default]: true. /// [Default]: true.
final bool isShowAvatar; final bool isShowAvatar;
@ -273,7 +259,7 @@ class TIMUIKitChatConfig {
this.isUseMessageReaction = true, this.isUseMessageReaction = true,
this.isShowAvatar = true, this.isShowAvatar = true,
this.isShowSelfNameInGroup = false, this.isShowSelfNameInGroup = false,
this.isAtWhenReplyDynamic, this.isAtWhenReplyDynamic,
this.offlinePushInfo, this.offlinePushInfo,
@Deprecated("Please use [isShowReadingStatus] instead") @Deprecated("Please use [isShowReadingStatus] instead")
this.isShowGroupMessageReadReceipt = true, this.isShowGroupMessageReadReceipt = true,
@ -285,10 +271,8 @@ class TIMUIKitChatConfig {
this.notificationTitle = "", this.notificationTitle = "",
this.notificationIOSSound = "", this.notificationIOSSound = "",
this.isAllowSoundMessage = true, this.isAllowSoundMessage = true,
@Deprecated("not support") @Deprecated("not support") this.groupReadReceiptPermisionList,
this.groupReadReceiptPermisionList, @Deprecated("not support") this.groupReadReceiptPermissionList,
@Deprecated("not support")
this.groupReadReceiptPermissionList,
this.isAllowEmojiPanel = true, this.isAllowEmojiPanel = true,
this.isAllowShowMorePanel = true, this.isAllowShowMorePanel = true,
this.isShowReadingStatus = true, this.isShowReadingStatus = true,
@ -304,6 +288,5 @@ class TIMUIKitChatConfig {
this.showC2cMessageEditStatus = true, this.showC2cMessageEditStatus = true,
this.additionalDesktopControlBarItems, this.additionalDesktopControlBarItems,
this.isAllowLongPressAvatarToAt = true, this.isAllowLongPressAvatarToAt = true,
this.isUseDefaultEmoji = false,
this.isMemberCanAtAll = false}); this.isMemberCanAtAll = false});
} }

View File

@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart'; import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_state.dart';
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.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/message.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
@ -82,18 +83,29 @@ class _TIMUIKitLastMsgState extends TIMUIKitState<TIMUIKitLastMsg> {
final isAdminRevoke = revokeStatus.$2; final isAdminRevoke = revokeStatus.$2;
if (isRevokedMessage) { if (isRevokedMessage) {
final isSelf = widget.lastMsg!.isSelf ?? true; final isSelf = widget.lastMsg!.isSelf ?? true;
final option1 = final option1 = isAdminRevoke
isAdminRevoke ? TIM_t("管理员") : (isSelf ? TIM_t("") : widget.lastMsg!.nickName ?? widget.lastMsg?.sender); ? TIM_t("管理员")
: (isSelf
? TIM_t("")
: widget.lastMsg!.nickName ?? widget.lastMsg?.sender);
if (mounted) { if (mounted) {
setState(() { setState(() {
groupTipsAbstractText = TIM_t_para("{{option1}}撤回了一条消息", "$option1撤回了一条消息")(option1: option1); groupTipsAbstractText = TIM_t_para(
"{{option1}}撤回了一条消息", "$option1撤回了一条消息")(option1: option1);
}); });
} }
} else { } else {
String msgShowText = await _getLastMsgShowText(widget.lastMsg, widget.context) ?? ""; String originalText =
await _getLastMsgShowText(widget.lastMsg, widget.context) ?? "";
String replaceText = TUIKitStickerConstData.emojiZhNameMap.keys
.fold(originalText, (previousValue, key) {
return previousValue.replaceAll(
key, TIM_t(TUIKitStickerConstData.emojiZhNameMap[key]!));
});
if (mounted) { if (mounted) {
setState(() { setState(() {
groupTipsAbstractText = msgShowText; groupTipsAbstractText = replaceText;
}); });
} }
} }
@ -102,14 +114,16 @@ class _TIMUIKitLastMsgState extends TIMUIKitState<TIMUIKitLastMsg> {
String _getDisturbUnreadCountInfo() { String _getDisturbUnreadCountInfo() {
if (widget.isDisturb && widget.unreadCount > 0) { if (widget.isDisturb && widget.unreadCount > 0) {
final option1 = widget.unreadCount.toString(); final option1 = widget.unreadCount.toString();
String unreadCountText = TIM_t_para("[{{option1}} 条]", "[$option1 条]")(option1: option1); String unreadCountText =
TIM_t_para("[{{option1}} 条]", "[$option1 条]")(option1: option1);
return unreadCountText; return unreadCountText;
} }
return ""; return "";
} }
Future<String?> _getLastMsgShowText(V2TimMessage? message, BuildContext context) async { Future<String?> _getLastMsgShowText(
V2TimMessage? message, BuildContext context) async {
final msgType = message!.elemType; final msgType = message!.elemType;
switch (msgType) { switch (msgType) {
case MessageElemType.V2TIM_ELEM_TYPE_CUSTOM: case MessageElemType.V2TIM_ELEM_TYPE_CUSTOM:
@ -122,9 +136,11 @@ class _TIMUIKitLastMsgState extends TIMUIKitState<TIMUIKitLastMsg> {
return TIM_t("[表情]"); return TIM_t("[表情]");
case MessageElemType.V2TIM_ELEM_TYPE_FILE: case MessageElemType.V2TIM_ELEM_TYPE_FILE:
final option1 = widget.lastMsg!.fileElem!.fileName; final option1 = widget.lastMsg!.fileElem!.fileName;
return TIM_t_para("[文件] {{option1}}", "[文件] $option1")(option1: option1); return TIM_t_para("[文件] {{option1}}", "[文件] $option1")(
option1: option1);
case MessageElemType.V2TIM_ELEM_TYPE_GROUP_TIPS: case MessageElemType.V2TIM_ELEM_TYPE_GROUP_TIPS:
return await MessageUtils.groupTipsMessageAbstract(widget.lastMsg!.groupTipsElem!, []); return await MessageUtils.groupTipsMessageAbstract(
widget.lastMsg!.groupTipsElem!, []);
case MessageElemType.V2TIM_ELEM_TYPE_IMAGE: case MessageElemType.V2TIM_ELEM_TYPE_IMAGE:
return TIM_t("[图片]"); return TIM_t("[图片]");
case MessageElemType.V2TIM_ELEM_TYPE_VIDEO: case MessageElemType.V2TIM_ELEM_TYPE_VIDEO:
@ -186,7 +202,8 @@ class _TIMUIKitLastMsgState extends TIMUIKitState<TIMUIKitLastMsg> {
@override @override
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
final TUITheme theme = value.theme; final TUITheme theme = value.theme;
final icon = _getIconByMsgStatus(context); final icon = _getIconByMsgStatus(context);
String disturbUnreadCountInfo = _getDisturbUnreadCountInfo(); String disturbUnreadCountInfo = _getDisturbUnreadCountInfo();
@ -197,39 +214,44 @@ class _TIMUIKitLastMsgState extends TIMUIKitState<TIMUIKitLastMsg> {
child: icon, child: icon,
), ),
if (widget.groupAtInfoList.isNotEmpty) if (widget.groupAtInfoList.isNotEmpty)
Text(_getAtMessage(), style: TextStyle(color: theme.cautionColor, fontSize: widget.fontSize)), Text(_getAtMessage(),
style: TextStyle(
color: theme.cautionColor, fontSize: widget.fontSize)),
if (widget.draftText != null && widget.draftText != "") if (widget.draftText != null && widget.draftText != "")
Text(_getDraftShowText(), style: TextStyle(color: theme.conversationItemDraftTextColor, fontSize: widget.fontSize)), Text(_getDraftShowText(),
style: TextStyle(
color: theme.conversationItemDraftTextColor,
fontSize: widget.fontSize)),
if (disturbUnreadCountInfo != "") if (disturbUnreadCountInfo != "")
Text(disturbUnreadCountInfo, style: TextStyle(color: theme.weakTextColor, fontSize: widget.fontSize)), Text(disturbUnreadCountInfo,
style: TextStyle(
color: theme.weakTextColor, fontSize: widget.fontSize)),
if (widget.draftText != null && widget.draftText != "") if (widget.draftText != null && widget.draftText != "")
Expanded(
child: ExtendedText(
groupTipsAbstractText,
softWrap: true,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(height: 1, color: theme.weakTextColor, fontSize: widget.fontSize),
specialTextSpanBuilder: DefaultSpecialTextSpanBuilder(
isUseQQPackage: true,
isUseTencentCloudChatPackage: true,
showAtBackground: true,
)
),
),
if (widget.draftText == null || widget.draftText == "" && TencentUtils.checkString(groupTipsAbstractText) != null)
Expanded( Expanded(
child: ExtendedText( child: ExtendedText(
groupTipsAbstractText, groupTipsAbstractText,
softWrap: true, softWrap: true,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle(height: 1, color: theme.weakTextColor, fontSize: widget.fontSize), style: TextStyle(
specialTextSpanBuilder: DefaultSpecialTextSpanBuilder( height: 1,
isUseQQPackage: true, color: theme.weakTextColor,
isUseTencentCloudChatPackage: true, fontSize: widget.fontSize),
showAtBackground: true, ),
) ),
if (widget.draftText == null ||
widget.draftText == "" &&
TencentUtils.checkString(groupTipsAbstractText) != null)
Expanded(
child: ExtendedText(
groupTipsAbstractText,
softWrap: true,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
height: 1,
color: theme.weakTextColor,
fontSize: widget.fontSize),
), ),
) )
]); ]);

View File

@ -3,15 +3,14 @@ import 'package:tim_ui_kit_sticker_plugin/utils/tim_custom_face_data.dart';
RegExp emojiExp = RegExp(r'\[([\u4e00-\u9fa5A-Za-z0-9]+)\]'); RegExp emojiExp = RegExp(r'\[([\u4e00-\u9fa5A-Za-z0-9]+)\]');
String mdTextCompiler(String originalText, { String mdTextCompiler(
bool isUseQQPackage = false, String originalText, {
bool isUseTencentCloudChatPackage = false, bool isUseTencentCloudChatPackage = false,
List<CustomEmojiFaceData> customEmojiStickerList = const [], List<CustomEmojiFaceData> customEmojiStickerList = const [],
}) { }) {
String text = originalText; String text = originalText;
final EmojiUtil emojiUtil = EmojiUtil( final EmojiUtil emojiUtil = EmojiUtil(
isUseTencentCloudChatPackage: isUseTencentCloudChatPackage, isUseTencentCloudChatPackage: isUseTencentCloudChatPackage,
isUseQQPackage: isUseQQPackage,
customEmojiStickerList: customEmojiStickerList); customEmojiStickerList: customEmojiStickerList);
text = text.replaceAllMapped(emojiExp, (match) { text = text.replaceAllMapped(emojiExp, (match) {
@ -26,4 +25,4 @@ String mdTextCompiler(String originalText, {
}); });
return text; return text;
} }

View File

@ -12,13 +12,11 @@ class LinkPreviewEntry {
static LinkPreviewText? getHyperlinksText(String messageText, bool isMarkdown, static LinkPreviewText? getHyperlinksText(String messageText, bool isMarkdown,
{Function(String)? onLinkTap, {Function(String)? onLinkTap,
bool isEnableTextSelection = false, bool isEnableTextSelection = false,
bool isUseQQPackage = false,
bool isUseTencentCloudChatPackage = false, bool isUseTencentCloudChatPackage = false,
List<CustomEmojiFaceData> customEmojiStickerList = const []}) { List<CustomEmojiFaceData> customEmojiStickerList = const []}) {
return ({TextStyle? style}) { return ({TextStyle? style}) {
return isMarkdown return isMarkdown
? LinkTextMarkdown( ? LinkTextMarkdown(
isUseQQPackage: isUseQQPackage,
isUseTencentCloudChatPackage: isUseTencentCloudChatPackage, isUseTencentCloudChatPackage: isUseTencentCloudChatPackage,
customEmojiStickerList: customEmojiStickerList, customEmojiStickerList: customEmojiStickerList,
isEnableTextSelection: isEnableTextSelection, isEnableTextSelection: isEnableTextSelection,
@ -31,7 +29,6 @@ class LinkPreviewEntry {
messageText: messageText, messageText: messageText,
style: style, style: style,
onLinkTap: onLinkTap, onLinkTap: onLinkTap,
isUseQQPackage: isUseQQPackage,
isUseTencentCloudChatPackage: isUseTencentCloudChatPackage, isUseTencentCloudChatPackage: isUseTencentCloudChatPackage,
customEmojiStickerList: customEmojiStickerList); customEmojiStickerList: customEmojiStickerList);
}; };

View File

@ -28,8 +28,6 @@ class LinkTextMarkdown extends TIMStatelessWidget {
final bool? isEnableTextSelection; final bool? isEnableTextSelection;
final bool isUseQQPackage;
final bool isUseTencentCloudChatPackage; final bool isUseTencentCloudChatPackage;
final List<CustomEmojiFaceData> customEmojiStickerList; final List<CustomEmojiFaceData> customEmojiStickerList;
@ -37,7 +35,6 @@ class LinkTextMarkdown extends TIMStatelessWidget {
const LinkTextMarkdown( const LinkTextMarkdown(
{Key? key, {Key? key,
required this.messageText, required this.messageText,
this.isUseQQPackage = false,
this.isUseTencentCloudChatPackage = false, this.isUseTencentCloudChatPackage = false,
this.customEmojiStickerList = const [], this.customEmojiStickerList = const [],
this.isEnableTextSelection, this.isEnableTextSelection,
@ -49,7 +46,6 @@ class LinkTextMarkdown extends TIMStatelessWidget {
Widget timBuild(BuildContext context) { Widget timBuild(BuildContext context) {
return MarkdownBody( return MarkdownBody(
data: mdTextCompiler(messageText, data: mdTextCompiler(messageText,
isUseQQPackage: isUseQQPackage,
isUseTencentCloudChatPackage: isUseTencentCloudChatPackage, isUseTencentCloudChatPackage: isUseTencentCloudChatPackage,
customEmojiStickerList: customEmojiStickerList), customEmojiStickerList: customEmojiStickerList),
selectable: isEnableTextSelection ?? false, selectable: isEnableTextSelection ?? false,
@ -85,8 +81,6 @@ class LinkText extends TIMStatelessWidget {
/// text style for default words /// text style for default words
final TextStyle? style; final TextStyle? style;
final bool isUseQQPackage;
final bool isUseTencentCloudChatPackage; final bool isUseTencentCloudChatPackage;
final List<CustomEmojiFaceData> customEmojiStickerList; final List<CustomEmojiFaceData> customEmojiStickerList;
@ -99,7 +93,6 @@ class LinkText extends TIMStatelessWidget {
this.onLinkTap, this.onLinkTap,
this.isEnableTextSelection, this.isEnableTextSelection,
this.style, this.style,
this.isUseQQPackage = false,
this.isUseTencentCloudChatPackage = false, this.isUseTencentCloudChatPackage = false,
this.customEmojiStickerList = const []}) this.customEmojiStickerList = const []})
: super(key: key); : super(key: key);
@ -172,7 +165,6 @@ class LinkText extends TIMStatelessWidget {
}, },
style: style ?? const TextStyle(fontSize: 16.0), style: style ?? const TextStyle(fontSize: 16.0),
specialTextSpanBuilder: DefaultSpecialTextSpanBuilder( specialTextSpanBuilder: DefaultSpecialTextSpanBuilder(
isUseQQPackage: isUseQQPackage,
isUseTencentCloudChatPackage: isUseTencentCloudChatPackage, isUseTencentCloudChatPackage: isUseTencentCloudChatPackage,
customEmojiStickerList: customEmojiStickerList, customEmojiStickerList: customEmojiStickerList,
showAtBackground: true, showAtBackground: true,

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: 3.1.0+2 version: 4.0.0
homepage: https://trtc.io/products/chat?utm_source=gfs&utm_medium=link&utm_campaign=%E6%B8%A0%E9%81%93&_channel_track_key=k6WgfCKn 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/chat-uikit-flutter repository: https://github.com/TencentCloud/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