1、更新第三方库 extended_text 和 extended_text_field 版本,支持 flutter sdk 3.24

2、修复和优化若干问题
This commit is contained in:
vinsonswang 2024-10-21 19:54:44 +08:00
parent 3f4f7afb4e
commit 157f48e653
18 changed files with 196 additions and 93 deletions

View File

@ -1,3 +1,9 @@
# 3.0.0
## Breaking Changes
* Migrated to Flutter 3.24.0
## Bug Fixes
* Fix and optimize some issues
# 2.7.2 # 2.7.2
* Fix the issue where failed messages cannot be resent. * Fix the issue where failed messages cannot be resent.
* Fix the issue where image messages that failed to send are not loaded using the local path. * Fix the issue where image messages that failed to send are not loaded using the local path.
@ -79,7 +85,6 @@
## Bug Fixes ## Bug Fixes
* Fixed an issue on time tag creator. * Fixed an issue on time tag creator.
* Fixed an issue on Video Message LocalURL.
# 2.3.2 # 2.3.2

View File

@ -7,14 +7,16 @@ import 'package:tencent_im_base/tencent_im_base.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
import 'package:tencent_cloud_chat_uikit/data_services/group/group_services.dart'; import 'package:tencent_cloud_chat_uikit/data_services/group/group_services.dart';
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart'; import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
enum UpdateType { groupInfo, memberList, joinApplicationList } enum UpdateType { groupInfo, memberList, joinApplicationList, groupDismissed, kickedFromGroup }
class NeedUpdate { class NeedUpdate {
final String groupID; final String groupID;
final UpdateType updateType; final UpdateType updateType;
final String extraData;
NeedUpdate(this.groupID, this.updateType); NeedUpdate(this.groupID, this.updateType, this.extraData);
} }
class TUIGroupListenerModel extends ChangeNotifier { class TUIGroupListenerModel extends ChangeNotifier {
@ -22,6 +24,8 @@ class TUIGroupListenerModel extends ChangeNotifier {
V2TimGroupListener? _groupListener; V2TimGroupListener? _groupListener;
NeedUpdate? _needUpdate; NeedUpdate? _needUpdate;
final TUIChatGlobalModel chatViewModel = serviceLocator<TUIChatGlobalModel>(); final TUIChatGlobalModel chatViewModel = serviceLocator<TUIChatGlobalModel>();
late CoreServicesImpl coreInstance = TIMUIKitCore.getInstance();
late V2TIMManager sdkInstance = TIMUIKitCore.getSDKInstance();
NeedUpdate? get needUpdate => _needUpdate; NeedUpdate? get needUpdate => _needUpdate;
@ -34,23 +38,27 @@ class TUIGroupListenerModel extends ChangeNotifier {
TUIGroupListenerModel() { TUIGroupListenerModel() {
_groupListener = V2TimGroupListener( _groupListener = V2TimGroupListener(
onMemberInvited: (groupID, opUser, memberList) { onMemberInvited: (groupID, opUser, memberList) {
_needUpdate = NeedUpdate(groupID, UpdateType.memberList); _needUpdate = NeedUpdate(groupID, UpdateType.memberList, "");
notifyListeners(); notifyListeners();
}, },
onMemberKicked: (groupID, opUser, memberList) { onMemberKicked: (groupID, opUser, memberList) async {
_needUpdate = NeedUpdate(groupID, UpdateType.memberList); if (_isLoginUserKickedFromGroup(groupID, memberList)) {
_deleteGroupConversation(groupID);
}
final groupName = await _getGroupName(groupID);
_needUpdate = NeedUpdate(groupID, UpdateType.kickedFromGroup, groupName);
notifyListeners(); notifyListeners();
}, },
onMemberEnter: (String groupID, List<V2TimGroupMemberInfo> memberList) { onMemberEnter: (String groupID, List<V2TimGroupMemberInfo> memberList) {
_needUpdate = NeedUpdate(groupID, UpdateType.memberList); _needUpdate = NeedUpdate(groupID, UpdateType.memberList, "");
notifyListeners(); notifyListeners();
}, },
onMemberLeave: (String groupID, V2TimGroupMemberInfo member) { onMemberLeave: (String groupID, V2TimGroupMemberInfo member) {
_needUpdate = NeedUpdate(groupID, UpdateType.memberList); _needUpdate = NeedUpdate(groupID, UpdateType.memberList, "");
notifyListeners(); notifyListeners();
}, },
onGroupInfoChanged: (groupID, changeInfos) { onGroupInfoChanged: (groupID, changeInfos) {
_needUpdate = NeedUpdate(groupID, UpdateType.groupInfo); _needUpdate = NeedUpdate(groupID, UpdateType.groupInfo, "");
notifyListeners(); notifyListeners();
}, },
onReceiveJoinApplication: onReceiveJoinApplication:
@ -59,6 +67,12 @@ class TUIGroupListenerModel extends ChangeNotifier {
chatViewModel.refreshGroupApplicationList(); chatViewModel.refreshGroupApplicationList();
notifyListeners(); notifyListeners();
}, },
onGroupDismissed: (String groupID, V2TimGroupMemberInfo opUser) async {
_deleteGroupConversation(groupID);
final groupName = await _getGroupName(groupID);
_needUpdate = NeedUpdate(groupID, UpdateType.groupDismissed, groupName);
notifyListeners();
}
); );
} }
@ -122,4 +136,29 @@ class TUIGroupListenerModel extends ChangeNotifier {
Future.delayed(const Duration(milliseconds: 500), Future.delayed(const Duration(milliseconds: 500),
() => chatViewModel.refreshGroupApplicationList()); () => chatViewModel.refreshGroupApplicationList());
} }
Future<String> _getGroupName(String groupID) async {
final groupInfoList = await sdkInstance.getGroupManager().getGroupsInfo(groupIDList: [groupID]);
String groupName = TIM_t("群组");
if (groupInfoList.data != null) {
groupName = groupInfoList.data!.first!.groupInfo!.groupName!;
}
return groupName;
}
void _deleteGroupConversation(String groupID) async {
sdkInstance.getConversationManager().deleteConversation(conversationID: "group_${groupID}");
}
bool _isLoginUserKickedFromGroup(String groupID, List<V2TimGroupMemberInfo> memberList) {
final loginUserInfo = coreInstance.loginInfo;
int index = memberList.indexWhere((element) => element.userID == loginUserInfo.userID);
if (index > -1) {
return true;
}
return false;
}
} }

View File

@ -1136,26 +1136,32 @@ class TUIChatSeparateViewModel extends ChangeNotifier {
required List<V2TimConversation> conversationList, required List<V2TimConversation> conversationList,
}) async { }) async {
final selectedMessages = List.from(_multiSelectedMessageList); final selectedMessages = List.from(_multiSelectedMessageList);
if (conversationType == ConvType.c2c) {
selectedMessages.sort((a, b) => a.timestamp.compareTo(b.timestamp));
} else if (conversationType == ConvType.group) {
selectedMessages.sort((a, b) => a.seq.compareTo(b.seq));
}
for (var conversation in conversationList) { for (var conversation in conversationList) {
final convID = conversation.groupID ?? conversation.userID ?? ""; final convID = conversation.groupID ?? conversation.userID ?? "";
final convType = conversation.type; final convType = conversation.type;
for (var message in selectedMessages) { for (var message in selectedMessages) {
final forwardMessageInfo = final forwardMessageInfo = await _messageService.createForwardMessage(msgID: message.msgID!);
await _messageService.createForwardMessage(msgID: message.msgID!);
final messageInfo = forwardMessageInfo!.messageInfo; final messageInfo = forwardMessageInfo!.messageInfo;
if (messageInfo != null) { if (messageInfo != null) {
tools.setUserInfoForMessage(messageInfo, forwardMessageInfo.id); tools.setUserInfoForMessage(messageInfo, forwardMessageInfo.id);
messageInfo.status = MessageStatus.V2TIM_MSG_STATUS_SENDING; messageInfo.status = MessageStatus.V2TIM_MSG_STATUS_SENDING;
addSendingMessageID(messageInfo.id); addSendingMessageID(messageInfo.id);
_sendMessage( await Future.delayed(Duration(milliseconds: 100), () {
id: forwardMessageInfo.id!, _sendMessage(
convID: convID, id: forwardMessageInfo.id!,
convType: convType == 1 ? ConvType.c2c : ConvType.group, convID: convID,
offlinePushInfo: tools.buildMessagePushInfo( convType: convType == 1 ? ConvType.c2c : ConvType.group,
forwardMessageInfo.messageInfo!, offlinePushInfo: tools.buildMessagePushInfo(
convID, forwardMessageInfo.messageInfo!,
convType == 1 ? ConvType.c2c : ConvType.group), convID,
); convType == 1 ? ConvType.c2c : ConvType.group),
);
});
} }
} }
} }

View File

@ -122,6 +122,8 @@ class TUIConversationViewModel extends ChangeNotifier {
if (!PlatformUtils().isWeb) { if (!PlatformUtils().isWeb) {
loadInitConversation(); loadInitConversation();
} }
}, onConversationDeleted:(List<String> conversationIDList) {
_onConversationDeleted(conversationIDList);
}); });
} }
@ -219,6 +221,17 @@ class TUIConversationViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
_onConversationDeleted(List<String> list) {
for (int i = 0; i < list.length; i++) {
int index = _conversationList.indexWhere((item) => item!.conversationID == list[i]);
if (index > -1) {
_conversationList.removeAt(index);
_conversationList = removeDuplicates<V2TimConversation?>(_conversationList, (item1, item2) => item1?.conversationID == item2?.conversationID);
}
}
notifyListeners();
}
_addNewConversation(List<V2TimConversation> list) { _addNewConversation(List<V2TimConversation> list) {
_conversationList.addAll(list); _conversationList.addAll(list);
_conversationList = removeDuplicates<V2TimConversation?>(_conversationList, (item1, item2) => item1?.conversationID == item2?.conversationID); _conversationList = removeDuplicates<V2TimConversation?>(_conversationList, (item1, item2) => item1?.conversationID == item2?.conversationID);

View File

@ -37,6 +37,26 @@ class MessageUtils {
return false; return false;
} }
static String getCustomGroupCreatedOrDismissedString(V2TimMessage message) {
try {
final isGroup = message.groupID != null;
final isCustomMessage = message.elemType == MessageElemType.V2TIM_ELEM_TYPE_CUSTOM;
if (isCustomMessage && isGroup) {
final data = message.customElem?.data ?? "";
Map<String, dynamic> customMap = jsonDecode(data);
if (customMap.containsKey('businessID') && customMap['businessID'] == "group_create") {
final content = "${customMap['opUser']}${customMap['content']}";
return content;
}
return "";
}
return "";
} catch (e) {
outputLogger.i("getCustomGroupCreatedOrDismissedString json parse error");
return "";
}
}
static Future<String> _getGroupChangeType(V2TimGroupChangeInfo info, static Future<String> _getGroupChangeType(V2TimGroupChangeInfo info,
List<V2TimGroupMemberFullInfo?> groupMemberList) async { List<V2TimGroupMemberFullInfo?> groupMemberList) async {
int? type = info.type; int? type = info.type;
@ -139,17 +159,26 @@ class MessageUtils {
final String? option7 = opUserNickName ?? ""; final String? option7 = opUserNickName ?? "";
final groupChangeInfoList = groupTipsElem.groupChangeInfoList ?? []; final groupChangeInfoList = groupTipsElem.groupChangeInfoList ?? [];
String changedInfoString = ""; String changedInfoString = "";
bool changedValue = false;
for (V2TimGroupChangeInfo? element in groupChangeInfoList) { for (V2TimGroupChangeInfo? element in groupChangeInfoList) {
final newText = await _getGroupChangeType(element!, groupMemberList); final newText = await _getGroupChangeType(element!, groupMemberList);
changedInfoString += changedInfoString +=
(changedInfoString.isEmpty ? "" : " / ") + newText; (changedInfoString.isEmpty ? "" : " / ") + newText;
changedValue = element!.boolValue ?? false;
} }
if (changedInfoString.isEmpty) { if (changedInfoString.isEmpty) {
changedInfoString = TIM_t("群资料"); changedInfoString = TIM_t("群资料");
} }
displayMessage = if (changedInfoString == TIM_t("全员禁言状态")) {
TIM_t_para("{{option7}}修改", "$option7修改")(option7: option7) + changedInfoString = TIM_t("全员禁言");
changedInfoString; displayMessage = changedValue == false ? TIM_t_para("{{option7}} 取消", "$option7 取消")(option7: option7) +
changedInfoString : TIM_t_para("{{option7}} 开启", "$option7 开启")(option7: option7) +
changedInfoString;
} else {
displayMessage =
TIM_t_para("{{option7}}修改", "$option7修改")(option7: option7) +
changedInfoString;
}
break; break;
case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_QUIT: case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_QUIT:
final String? option6 = opUserNickName ?? ""; final String? option6 = opUserNickName ?? "";

View File

@ -60,6 +60,9 @@ class _TIMUIKitAddGroupState extends TIMUIKitState<TIMUIKitAddGroup> {
case GroupType.Work: case GroupType.Work:
groupType = TIM_t("工作群"); groupType = TIM_t("工作群");
break; break;
case GroupType.Community:
groupType = TIM_t("社群");
break;
default: default:
groupType = TIM_t("未知群"); groupType = TIM_t("未知群");
break; break;
@ -86,7 +89,6 @@ class _TIMUIKitAddGroupState extends TIMUIKitState<TIMUIKitAddGroup> {
if (widget.closeFunc != null) { if (widget.closeFunc != null) {
widget.closeFunc!(); widget.closeFunc!();
} }
widget.onTapExistGroup(groupID, groupConversation);
return; return;
} }
@ -106,7 +108,7 @@ class _TIMUIKitAddGroupState extends TIMUIKitState<TIMUIKitAddGroup> {
), ),
); );
}else{ }else{
Navigator.pushReplacement( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => SendJoinGroupApplication( builder: (context) => SendJoinGroupApplication(

View File

@ -61,6 +61,9 @@ class _SendJoinGroupApplicationState
case GroupType.Work: case GroupType.Work:
groupType = TIM_t("工作群"); groupType = TIM_t("工作群");
break; break;
case GroupType.Community:
groupType = TIM_t("社群");
break;
default: default:
groupType = TIM_t("未知群"); groupType = TIM_t("未知群");
break; break;

View File

@ -49,6 +49,9 @@ class TIMUIKitMessageReadReceipt extends TIMUIKitStatelessWidget {
readCount: value?.readCount ?? 0) readCount: value?.readCount ?? 0)
); );
}else{ }else{
if (value?.unreadCount == 0) {
return;
}
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(

View File

@ -529,7 +529,10 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
} }
final int selfRole = widget.model.selfMemberInfo?.role ?? 0; final int selfRole = widget.model.selfMemberInfo?.role ?? 0;
final bool canAtAll = (selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN || selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER); final bool canAtAll = widget.model.chatConfig.isMemberCanAtAll ? true : (selfRole == GroupMemberRoleType
.V2TIM_GROUP_MEMBER_ROLE_ADMIN || 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);
@ -860,7 +863,6 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
backSpaceText: deleteStickerFromText, backSpaceText: deleteStickerFromText,
addStickerToText: addStickerToText, addStickerToText: addStickerToText,
customStickerPanel: widget.customStickerPanel, customStickerPanel: widget.customStickerPanel,
forbiddenText: forbiddenText,
onChanged: widget.onChanged, onChanged: widget.onChanged,
backgroundColor: widget.backgroundColor, backgroundColor: widget.backgroundColor,
morePanelConfig: widget.morePanelConfig, morePanelConfig: widget.morePanelConfig,
@ -898,7 +900,6 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
backSpaceText: deleteStickerFromText, backSpaceText: deleteStickerFromText,
addStickerToText: addStickerToText, addStickerToText: addStickerToText,
customStickerPanel: widget.customStickerPanel, customStickerPanel: widget.customStickerPanel,
forbiddenText: forbiddenText,
onChanged: widget.onChanged, onChanged: widget.onChanged,
backgroundColor: widget.backgroundColor, backgroundColor: widget.backgroundColor,
morePanelConfig: widget.morePanelConfig, morePanelConfig: widget.morePanelConfig,

View File

@ -84,8 +84,6 @@ class TIMUIKitTextFieldLayoutNarrow extends StatefulWidget {
/// show send emoji icon /// show send emoji icon
final bool showSendEmoji; final bool showSendEmoji;
final String? forbiddenText;
final VoidCallback onSubmitted; final VoidCallback onSubmitted;
final VoidCallback goDownBottom; final VoidCallback goDownBottom;
@ -118,7 +116,6 @@ class TIMUIKitTextFieldLayoutNarrow extends StatefulWidget {
required this.handleAtText, required this.handleAtText,
required this.handleSoftKeyBoardDelete, required this.handleSoftKeyBoardDelete,
this.repliedMessage, this.repliedMessage,
this.forbiddenText,
required this.onSubmitted, required this.onSubmitted,
required this.goDownBottom, required this.goDownBottom,
required this.showSendAudio, required this.showSendAudio,
@ -414,23 +411,7 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
constraints: const BoxConstraints(minHeight: 50), constraints: const BoxConstraints(minHeight: 50),
child: Row( child: Row(
children: [ children: [
if (widget.forbiddenText != null) if (PlatformUtils().isMobile && widget.showSendAudio)
Expanded(
child: Container(
height: 35,
color: theme.weakBackgroundColor,
alignment: Alignment.center,
child: Text(
TIM_t(widget.forbiddenText!),
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: theme.weakTextColor,
),
),
)),
if (PlatformUtils().isMobile && widget.showSendAudio && widget.forbiddenText == null)
InkWell( InkWell(
onTap: () async { onTap: () async {
showKeyboard = showSendSoundText; showKeyboard = showSendSoundText;
@ -457,11 +438,9 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
width: 28, width: 28,
), ),
), ),
if (widget.forbiddenText == null)
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
if (widget.forbiddenText == null)
Expanded( Expanded(
child: showSendSoundText child: showSendSoundText
? SendSoundMessage(onDownBottom: widget.goDownBottom, conversationID: widget.conversationID, conversationType: widget.conversationType) ? SendSoundMessage(onDownBottom: widget.goDownBottom, conversationID: widget.conversationID, conversationType: widget.conversationType)
@ -520,11 +499,10 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
} }
}), }),
), ),
if (widget.forbiddenText == null)
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
if (widget.showSendEmoji && widget.forbiddenText == null) if (widget.showSendEmoji)
InkWell( InkWell(
onTap: () { onTap: () {
_openEmojiPanel(); _openEmojiPanel();
@ -540,11 +518,10 @@ class _TIMUIKitTextFieldLayoutNarrowState extends TIMUIKitState<TIMUIKitTextFiel
width: 28, width: 28,
), ),
), ),
if (widget.forbiddenText == null)
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
if (widget.showMorePanel && widget.forbiddenText == null && showMoreButton) if (widget.showMorePanel && showMoreButton)
InkWell( InkWell(
onTap: () { onTap: () {
// model.sendCustomMessage(data: "a", convID: model.currentSelectedConv, convType: model.currentSelectedConvType == 1 ? ConvType.c2c : ConvType.group); // model.sendCustomMessage(data: "a", convID: model.currentSelectedConv, convType: model.currentSelectedConvType == 1 ? ConvType.c2c : ConvType.group);

View File

@ -139,8 +139,6 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget {
/// show send emoji icon /// show send emoji icon
final bool showSendEmoji; final bool showSendEmoji;
final String? forbiddenText;
final VoidCallback onSubmitted; final VoidCallback onSubmitted;
final VoidCallback goDownBottom; final VoidCallback goDownBottom;
@ -175,7 +173,6 @@ class TIMUIKitTextFieldLayoutWide extends StatefulWidget {
required this.handleSendEditStatus, required this.handleSendEditStatus,
required this.handleAtText, required this.handleAtText,
this.repliedMessage, this.repliedMessage,
this.forbiddenText,
required this.onSubmitted, required this.onSubmitted,
required this.goDownBottom, required this.goDownBottom,
required this.showSendAudio, required this.showSendAudio,
@ -928,7 +925,6 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
children: [ children: [
_buildRepliedMessage(widget.repliedMessage), _buildRepliedMessage(widget.repliedMessage),
SizedBox(height: 1, child: Container(color: theme.weakDividerColor ?? Colors.black12)), SizedBox(height: 1, child: Container(color: theme.weakDividerColor ?? Colors.black12)),
if (widget.forbiddenText == null)
Container( Container(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12), padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12),
child: Row( child: Row(
@ -941,23 +937,6 @@ class _TIMUIKitTextFieldLayoutWideState extends TIMUIKitState<TIMUIKitTextFieldL
constraints: const BoxConstraints(minHeight: 50), constraints: const BoxConstraints(minHeight: 50),
child: Row( child: Row(
children: [ children: [
if (widget.forbiddenText != null)
Expanded(
child: Container(
height: 35,
color: widget.backgroundColor ?? theme.desktopChatMessageInputBgColor,
alignment: Alignment.center,
child: Text(
TIM_t(widget.forbiddenText!),
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: theme.weakTextColor,
),
),
)),
if (widget.forbiddenText == null)
Expanded( Expanded(
child: ExtendedTextField( child: ExtendedTextField(
scrollController: _scrollController, scrollController: _scrollController,

View File

@ -364,7 +364,6 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
@override @override
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final TUITheme theme = value.theme; final TUITheme theme = value.theme;
final closePanel = OptimizeUtils.throttle((_) => textFieldController.hideAllPanel(), 60);
final isBuild = isInit; final isBuild = isInit;
isInit = true; isInit = true;
_updateJoinInGroupCallWidget(); _updateJoinInGroupCallWidget();
@ -474,7 +473,6 @@ class _TUIChatState extends TIMUIKitState<TIMUIKitChat> {
key: alignKey, key: alignKey,
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: Listener( child: Listener(
onPointerMove: closePanel,
child: TIMUIKitHistoryMessageListContainer( child: TIMUIKitHistoryMessageListContainer(
customMessageHoverBarOnDesktop: widget.customMessageHoverBarOnDesktop, customMessageHoverBarOnDesktop: widget.customMessageHoverBarOnDesktop,
conversation: widget.conversation, conversation: widget.conversation,

View File

@ -243,6 +243,13 @@ class TIMUIKitChatConfig {
/// [Default]: 400 /// [Default]: 400
final double desktopStickerPanelHeight; final double desktopStickerPanelHeight;
/// Determine whether the normal members can @All in a group chat.
/// If enabled, normal members can @All in a group chat.
/// If disabled, only the group owner or administrators can @All.
///
/// [Default]: false
final bool isMemberCanAtAll;
const TIMUIKitChatConfig( const TIMUIKitChatConfig(
{this.onTapLink, {this.onTapLink,
this.timeDividerConfig, this.timeDividerConfig,
@ -291,5 +298,6 @@ class TIMUIKitChatConfig {
this.showC2cMessageEditStatus = true, this.showC2cMessageEditStatus = true,
this.additionalDesktopControlBarItems, this.additionalDesktopControlBarItems,
this.isAllowLongPressAvatarToAt = true, this.isAllowLongPressAvatarToAt = true,
this.isUseDefaultEmoji = false}); this.isUseDefaultEmoji = false,
this.isMemberCanAtAll = false});
} }

View File

@ -11,6 +11,7 @@ import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget
import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/conversation_life_cycle.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/life_cycle/conversation_life_cycle.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_conversation_view_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_conversation_view_model.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_friendship_view_model.dart'; import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_friendship_view_model.dart';
import 'package:tencent_cloud_chat_uikit/business_logic/listener_model/tui_group_listener_model.dart';
import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal_operation_key.dart'; import 'package:tencent_cloud_chat_uikit/data_services/core/tim_uikit_wide_modal_operation_key.dart';
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart'; import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart'; import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
@ -143,6 +144,7 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
late TIMUIKitConversationController _timuiKitConversationController; late TIMUIKitConversationController _timuiKitConversationController;
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>(); final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
final TUIFriendShipViewModel friendShipViewModel = serviceLocator<TUIFriendShipViewModel>(); final TUIFriendShipViewModel friendShipViewModel = serviceLocator<TUIFriendShipViewModel>();
final TUIGroupListenerModel groupListenerModel = serviceLocator<TUIGroupListenerModel>();
late AutoScrollController _autoScrollController; late AutoScrollController _autoScrollController;
@override @override
@ -289,13 +291,33 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
final theme = value.theme; final theme = value.theme;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
return MultiProvider( return MultiProvider(
providers: [ChangeNotifierProvider.value(value: model), ChangeNotifierProvider.value(value: friendShipViewModel)], providers: [
ChangeNotifierProvider.value(value: model),
ChangeNotifierProvider.value(value: friendShipViewModel),
ChangeNotifierProvider.value(value: groupListenerModel)],
builder: (BuildContext context, Widget? w) { builder: (BuildContext context, Widget? w) {
final _model = Provider.of<TUIConversationViewModel>(context); final _model = Provider.of<TUIConversationViewModel>(context);
bool haveMoreData = _model.haveMoreData; bool haveMoreData = _model.haveMoreData;
final _friendShipViewModel = Provider.of<TUIFriendShipViewModel>(context); final _friendShipViewModel = Provider.of<TUIFriendShipViewModel>(context);
_model.lifeCycle = widget.lifeCycle; _model.lifeCycle = widget.lifeCycle;
final TUIGroupListenerModel groupListenerModel = Provider.of<TUIGroupListenerModel>(context, listen: true);
final NeedUpdate? needUpdate = groupListenerModel.needUpdate;
if (needUpdate != null) {
groupListenerModel.needUpdate = null;
if (needUpdate.updateType == UpdateType.groupDismissed) {
onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: "${needUpdate!.extraData}${TIM_t("已解散")}",
infoCode: 6661402));
} else if (needUpdate.updateType == UpdateType.kickedFromGroup) {
onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: "${TIM_t("您已被踢出")}${needUpdate!.extraData}",
infoCode: 6661402));
}
}
List<V2TimConversation?> filteredConversationList = getFilteredConversation(); List<V2TimConversation?> filteredConversationList = getFilteredConversation();
if (TencentUtils.checkString(_model.scrollToConversation) != null) { if (TencentUtils.checkString(_model.scrollToConversation) != null) {
@ -344,7 +366,8 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
lastMessageBuilder: widget.lastMessageBuilder, lastMessageBuilder: widget.lastMessageBuilder,
faceUrl: conversationItem.faceUrl ?? "", faceUrl: conversationItem.faceUrl ?? "",
nickName: conversationItem.showName ?? "", nickName: conversationItem.showName ?? "",
isDisturb: conversationItem.recvOpt != 0, isDisturb: (conversationItem.groupType == "Meeting" ? false : conversationItem
.recvOpt != 0),
lastMsg: conversationItem.lastMessage, lastMsg: conversationItem.lastMessage,
isPined: isPined, isPined: isPined,
groupAtInfoList: conversationItem.groupAtInfoList ?? [], groupAtInfoList: conversationItem.groupAtInfoList ?? [],

View File

@ -94,7 +94,7 @@ class GroupProfileButtonArea extends TIMUIKitStatelessWidget {
} }
}, },
child: Text( child: Text(
TIM_t("清空聊天记录"), TIM_t("确定"),
style: TextStyle(color: theme.cautionColor), style: TextStyle(color: theme.cautionColor),
), ),
isDefaultAction: false, isDefaultAction: false,
@ -157,6 +157,10 @@ class GroupProfileButtonArea extends TIMUIKitStatelessWidget {
if (deleteConvRes.code == 0) { if (deleteConvRes.code == 0) {
model.lifeCycle?.didLeaveGroup(); model.lifeCycle?.didLeaveGroup();
} }
onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO,
infoRecommendText: "${TIM_t("您已退出")}${model.groupInfo?.groupName}",
infoCode: 6661402));
} }
}, },
child: Text( child: Text(

View File

@ -13,7 +13,11 @@ class GroupMessageDisturb extends TIMUIKitStatelessWidget {
@override @override
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final model = Provider.of<TUIGroupProfileModel>(context); final model = Provider.of<TUIGroupProfileModel>(context);
final isShowDisturb = model.groupInfo?.groupType == "Meeting" ? false : true;
final isDisturb = model.conversation?.recvOpt != 0; final isDisturb = model.conversation?.recvOpt != 0;
if (!isShowDisturb) {
return Container();
}
return TIMUIKitOperationItem( return TIMUIKitOperationItem(
isEmpty: false, isEmpty: false,
operationName: TIM_t("消息免打扰"), operationName: TIM_t("消息免打扰"),

View File

@ -33,6 +33,9 @@ class GroupProfileType extends TIMUIKitStatelessWidget {
case GroupType.Work: case GroupType.Work:
groupType = TIM_t("工作群"); groupType = TIM_t("工作群");
break; break;
case GroupType.Community:
groupType = TIM_t("社群");
break;
default: default:
groupType = TIM_t("未知群"); groupType = TIM_t("未知群");
break; break;
@ -42,22 +45,26 @@ class GroupProfileType extends TIMUIKitStatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
border: isDesktopScreen ? null : Border( border: isDesktopScreen
bottom: BorderSide( ? null
color: : Border(
theme.weakDividerColor ?? CommonColor.weakDividerColor))), bottom: BorderSide(
color: theme.weakDividerColor ??
CommonColor.weakDividerColor))),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
TIM_t("群类型"), TIM_t("群类型"),
style: TextStyle( style: TextStyle(
fontSize: isDesktopScreen ? 14 : 16, color: theme.darkTextColor), fontSize: isDesktopScreen ? 14 : 16,
color: theme.darkTextColor),
), ),
Text( Text(
groupType, groupType,
style: TextStyle( style: TextStyle(
fontSize: isDesktopScreen ? 14 : 16, color: theme.weakTextColor), fontSize: isDesktopScreen ? 14 : 16,
color: theme.weakTextColor),
) )
], ],
), ),

View File

@ -1,6 +1,6 @@
name: tencent_cloud_chat_uikit name: tencent_cloud_chat_uikit
description: A powerful chat UI component library and business logic for Tencent Cloud Chat, creating seamless in-app chat modules for delightful user experiences. description: A powerful chat UI component library and business logic for Tencent Cloud Chat, creating seamless in-app chat modules for delightful user experiences.
version: 2.7.2 version: 3.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
@ -14,7 +14,7 @@ platforms:
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
flutter: ">=3.22.0" flutter: ">=3.24.0"
dependencies: dependencies:
flutter: flutter:
@ -44,8 +44,8 @@ dependencies:
wechat_camera_picker: ^4.2.0-dev.2 wechat_camera_picker: ^4.2.0-dev.2
flutter_easyrefresh: ^2.2.1 flutter_easyrefresh: ^2.2.1
extended_image: '>=8.2.0 <=8.2.4' extended_image: '>=8.2.0 <=8.2.4'
extended_text_field: ^15.0.0 extended_text_field: ^16.0.0
extended_text: ^13.0.0 extended_text: ^14.0.0
package_info_plus: ^4.0.1 package_info_plus: ^4.0.1
loading_animation_widget: ^1.1.0+3 loading_animation_widget: ^1.1.0+3
permission_handler: ^10.2.0 permission_handler: ^10.2.0
@ -83,9 +83,11 @@ dev_dependencies:
lints: ^1.0.1 lints: ^1.0.1
dependency_overrides: dependency_overrides:
# tencent_chat_i18n_tool:
# path: ../../../tencent_chat_i18n_tool
# tencent_chat_i18n_tool: # tencent_cloud_chat_sdk:
# path: D:\Project\tencent-chat-i18n-tool # path: ../../../tencent_cloud_chat_sdk
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec