feat: Upgrade to UIKit 2.3.2
This commit is contained in:
parent
c28e1e9529
commit
038a3d483d
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -1,3 +1,14 @@
|
||||||
|
# 2.3.2
|
||||||
|
|
||||||
|
## Improvements
|
||||||
|
|
||||||
|
* Enhanced message list performance.
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
* Fixed an issue that prevented the group member addition/removal modal from closing.
|
||||||
|
* Addressed several other bugs.
|
||||||
|
|
||||||
# 2.3.1
|
# 2.3.1
|
||||||
|
|
||||||
## Bug Fixes
|
## Bug Fixes
|
||||||
|
|
|
||||||
|
|
@ -706,7 +706,6 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
|
|
||||||
Future<void> onMessageDownloadProgressCallback(
|
Future<void> onMessageDownloadProgressCallback(
|
||||||
V2TimMessageDownloadProgress messageProgress) async {
|
V2TimMessageDownloadProgress messageProgress) async {
|
||||||
outputLogger.i(messageProgress.toJson());
|
|
||||||
final currentProgress = getMessageProgress(messageProgress.msgID);
|
final currentProgress = getMessageProgress(messageProgress.msgID);
|
||||||
|
|
||||||
if (messageProgress.isFinish && currentProgress < 100) {
|
if (messageProgress.isFinish && currentProgress < 100) {
|
||||||
|
|
@ -1120,9 +1119,7 @@ class TUIChatGlobalModel extends ChangeNotifier implements TIMUIKitClass {
|
||||||
listWithTimestamp.add(V2TimMessage.fromJson(item.toJson()));
|
listWithTimestamp.add(V2TimMessage.fromJson(item.toJson()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final returnValue = listWithTimestamp.reversed.toList();
|
return listWithTimestamp.reversed.toList();
|
||||||
outputLogger.i(returnValue.map((e) => e.toJson()).toList().toString());
|
|
||||||
return returnValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryMessagePosition getMessageListPosition(String? conversationID) {
|
HistoryMessagePosition getMessageListPosition(String? conversationID) {
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class TUIKitOutput extends LogOutput {
|
||||||
|
|
||||||
Future<String> getPlatformLogPath({String? path}) async {
|
Future<String> getPlatformLogPath({String? path}) async {
|
||||||
if (TencentUtils.checkString(path) != null) {
|
if (TencentUtils.checkString(path) != null) {
|
||||||
outputLogger.i("The path to local log: $path");
|
print("The path to local log: $path");
|
||||||
return path!;
|
return path!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ class TUIKitOutput extends LogOutput {
|
||||||
"${DateTime.now().year}-${DateTime.now().month}-${DateTime.now().day}";
|
"${DateTime.now().year}-${DateTime.now().month}-${DateTime.now().day}";
|
||||||
final logPath = p.join(documentsDirectoryPath, "Documents", ".TencentCloudChat",
|
final logPath = p.join(documentsDirectoryPath, "Documents", ".TencentCloudChat",
|
||||||
pkgName, "uikit_log", 'Flutter-TUIKit-$timeName.log');
|
pkgName, "uikit_log", 'Flutter-TUIKit-$timeName.log');
|
||||||
outputLogger.i("The path to local log: $logPath");
|
print("The path to local log: $logPath");
|
||||||
|
|
||||||
return logPath;
|
return logPath;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,17 @@ import 'package:provider/provider.dart';
|
||||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
import 'package:scroll_to_index/scroll_to_index.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_im_base/tencent_im_base.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
|
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/logger.dart';
|
||||||
// ignore: unused_import
|
// ignore: unused_import
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/optimize_utils.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/optimize_utils.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_history_message_list_config.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKItMessageList/tim_uikit_chat_history_message_list_config.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKItMessageList/utils.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKItMessageList/utils.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/keepalive_wrapper.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/keepalive_wrapper.dart';
|
||||||
|
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||||
|
|
||||||
import 'TIMUIKitTongue/tim_uikit_chat_history_message_list_tongue.dart';
|
import 'TIMUIKitTongue/tim_uikit_chat_history_message_list_tongue.dart';
|
||||||
import 'TIMUIKitTongue/tim_uikit_chat_history_message_list_tongue_container.dart';
|
import 'TIMUIKitTongue/tim_uikit_chat_history_message_list_tongue_container.dart';
|
||||||
|
|
||||||
|
|
@ -73,8 +75,7 @@ class TIMUIKitHistoryMessageList extends StatefulWidget {
|
||||||
final V2TimMessage? initFindingMsg;
|
final V2TimMessage? initFindingMsg;
|
||||||
|
|
||||||
/// use for load more message
|
/// use for load more message
|
||||||
final Future<void> Function(String?, LoadDirection direction, [int?])
|
final Future<void> Function(String?, LoadDirection direction, [int?]) onLoadMore;
|
||||||
onLoadMore;
|
|
||||||
|
|
||||||
/// configuration for list view
|
/// configuration for list view
|
||||||
final TIMUIKitHistoryMessageListConfig? mainHistoryListConfig;
|
final TIMUIKitHistoryMessageListConfig? mainHistoryListConfig;
|
||||||
|
|
@ -104,8 +105,7 @@ class TIMUIKitHistoryMessageList extends StatefulWidget {
|
||||||
State<StatefulWidget> createState() => _TIMUIKitHistoryMessageListState();
|
State<StatefulWidget> createState() => _TIMUIKitHistoryMessageListState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TIMUIKitHistoryMessageListState
|
class _TIMUIKitHistoryMessageListState extends TIMUIKitState<TIMUIKitHistoryMessageList> {
|
||||||
extends TIMUIKitState<TIMUIKitHistoryMessageList> {
|
|
||||||
V2TimMessage? findingMsg;
|
V2TimMessage? findingMsg;
|
||||||
String findingSeq = "";
|
String findingSeq = "";
|
||||||
late TIMUIKitHistoryMessageListController _controller;
|
late TIMUIKitHistoryMessageListController _controller;
|
||||||
|
|
@ -116,8 +116,7 @@ class _TIMUIKitHistoryMessageListState
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller = widget.controller ?? TIMUIKitHistoryMessageListController();
|
_controller = widget.controller ?? TIMUIKitHistoryMessageListController();
|
||||||
_autoScrollController =
|
_autoScrollController = _controller.scrollController ?? AutoScrollController();
|
||||||
_controller.scrollController ?? AutoScrollController();
|
|
||||||
_controller.addListener(_controllerListener);
|
_controller.addListener(_controllerListener);
|
||||||
initFinding();
|
initFinding();
|
||||||
}
|
}
|
||||||
|
|
@ -163,18 +162,14 @@ class _TIMUIKitHistoryMessageListState
|
||||||
findingMsg = null;
|
findingMsg = null;
|
||||||
findingSeq = "";
|
findingSeq = "";
|
||||||
loadingPlace = LoadingPlace.none;
|
loadingPlace = LoadingPlace.none;
|
||||||
onTIMCallback(TIMCallback(
|
onTIMCallback(TIMCallback(type: TIMCallbackType.INFO, infoRecommendText: TIM_t("无法定位到原消息"), infoCode: 6660401));
|
||||||
type: TIMCallbackType.INFO,
|
|
||||||
infoRecommendText: TIM_t("无法定位到原消息"),
|
|
||||||
infoCode: 6660401));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onScrollToIndex(V2TimMessage targetMsg) {
|
_onScrollToIndex(V2TimMessage targetMsg) {
|
||||||
// This method called by @ messages or messages been searched, aims to jump to target message
|
// This method called by @ messages or messages been searched, aims to jump to target message
|
||||||
loadingPlace = LoadingPlace.top;
|
loadingPlace = LoadingPlace.top;
|
||||||
const int singleLoadAmount = kIsWeb ? 15 : 40;
|
const int singleLoadAmount = kIsWeb ? 15 : 40;
|
||||||
final lastTimestamp =
|
final lastTimestamp = widget.messageList[widget.messageList.length - 1]?.timestamp;
|
||||||
widget.messageList[widget.messageList.length - 1]?.timestamp;
|
|
||||||
final msgList = widget.messageList;
|
final msgList = widget.messageList;
|
||||||
final targetTimeStamp = targetMsg.timestamp!;
|
final targetTimeStamp = targetMsg.timestamp!;
|
||||||
|
|
||||||
|
|
@ -184,9 +179,7 @@ class _TIMUIKitHistoryMessageListState
|
||||||
int targetIndex = 1;
|
int targetIndex = 1;
|
||||||
for (int i = msgList.length - 1; i >= 0; i--) {
|
for (int i = msgList.length - 1; i >= 0; i--) {
|
||||||
final currentMsg = msgList[i];
|
final currentMsg = msgList[i];
|
||||||
if (currentMsg?.timestamp == targetTimeStamp &&
|
if (currentMsg?.timestamp == targetTimeStamp && currentMsg?.elemType != 11 && currentMsg!.msgID == targetMsg.msgID) {
|
||||||
currentMsg?.elemType != 11 &&
|
|
||||||
currentMsg!.msgID == targetMsg.msgID) {
|
|
||||||
// find the target index by timestamp and msgID
|
// find the target index by timestamp and msgID
|
||||||
isFound = true;
|
isFound = true;
|
||||||
targetIndex = -i;
|
targetIndex = -i;
|
||||||
|
|
@ -202,10 +195,8 @@ class _TIMUIKitHistoryMessageListState
|
||||||
);
|
);
|
||||||
|
|
||||||
// execute twice for accurate position, as the position located firstly can be wrong
|
// execute twice for accurate position, as the position located firstly can be wrong
|
||||||
_autoScrollController.scrollToIndex(targetIndex,
|
_autoScrollController.scrollToIndex(targetIndex, preferPosition: AutoScrollPosition.middle);
|
||||||
preferPosition: AutoScrollPosition.middle);
|
_autoScrollController.scrollToIndex(targetIndex, preferPosition: AutoScrollPosition.middle);
|
||||||
_autoScrollController.scrollToIndex(targetIndex,
|
|
||||||
preferPosition: AutoScrollPosition.middle);
|
|
||||||
|
|
||||||
widget.model.jumpMsgID = targetMsg.msgID!;
|
widget.model.jumpMsgID = targetMsg.msgID!;
|
||||||
loadingPlace = LoadingPlace.none;
|
loadingPlace = LoadingPlace.none;
|
||||||
|
|
@ -258,8 +249,7 @@ class _TIMUIKitHistoryMessageListState
|
||||||
targetIndex,
|
targetIndex,
|
||||||
preferPosition: AutoScrollPosition.middle,
|
preferPosition: AutoScrollPosition.middle,
|
||||||
);
|
);
|
||||||
_autoScrollController.scrollToIndex(targetIndex,
|
_autoScrollController.scrollToIndex(targetIndex, preferPosition: AutoScrollPosition.middle);
|
||||||
preferPosition: AutoScrollPosition.middle);
|
|
||||||
if (targetMsgID != null && targetMsgID != "") {
|
if (targetMsgID != null && targetMsgID != "") {
|
||||||
widget.model.jumpMsgID = targetMsgID;
|
widget.model.jumpMsgID = targetMsgID;
|
||||||
}
|
}
|
||||||
|
|
@ -270,8 +260,7 @@ class _TIMUIKitHistoryMessageListState
|
||||||
} else {
|
} else {
|
||||||
if (widget.model.haveMoreData) {
|
if (widget.model.haveMoreData) {
|
||||||
findingSeq = targetSeq;
|
findingSeq = targetSeq;
|
||||||
widget.onLoadMore(_getMessageId(widget.messageList.length - 1),
|
widget.onLoadMore(_getMessageId(widget.messageList.length - 1), LoadDirection.previous, singleLoadAmount);
|
||||||
LoadDirection.previous, singleLoadAmount);
|
|
||||||
} else {
|
} else {
|
||||||
showCantFindMsg();
|
showCantFindMsg();
|
||||||
}
|
}
|
||||||
|
|
@ -279,8 +268,7 @@ class _TIMUIKitHistoryMessageListState
|
||||||
}
|
}
|
||||||
|
|
||||||
_onScrollToIndexBegin(V2TimMessage targetMsg) {
|
_onScrollToIndexBegin(V2TimMessage targetMsg) {
|
||||||
final lastTimestamp =
|
final lastTimestamp = widget.messageList[widget.messageList.length - 1]?.timestamp;
|
||||||
widget.messageList[widget.messageList.length - 1]?.timestamp;
|
|
||||||
final msgList = widget.messageList;
|
final msgList = widget.messageList;
|
||||||
final int targetTimeStamp = targetMsg.timestamp!;
|
final int targetTimeStamp = targetMsg.timestamp!;
|
||||||
|
|
||||||
|
|
@ -289,9 +277,7 @@ class _TIMUIKitHistoryMessageListState
|
||||||
int targetIndex = 1;
|
int targetIndex = 1;
|
||||||
for (int i = msgList.length - 1; i >= 0; i--) {
|
for (int i = msgList.length - 1; i >= 0; i--) {
|
||||||
final currentMsg = msgList[i];
|
final currentMsg = msgList[i];
|
||||||
if (currentMsg?.timestamp == targetTimeStamp &&
|
if (currentMsg?.timestamp == targetTimeStamp && currentMsg?.elemType != 11 && currentMsg!.msgID == targetMsg.msgID) {
|
||||||
currentMsg?.elemType != 11 &&
|
|
||||||
currentMsg!.msgID == targetMsg.msgID) {
|
|
||||||
isFound = true;
|
isFound = true;
|
||||||
targetIndex = -i;
|
targetIndex = -i;
|
||||||
break;
|
break;
|
||||||
|
|
@ -310,11 +296,8 @@ class _TIMUIKitHistoryMessageListState
|
||||||
if (receivedMessageListCount == 0) {
|
if (receivedMessageListCount == 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
final haveTimeStampMessage =
|
final haveTimeStampMessage = widget.messageList[receivedMessageListCount]?.elemType == 11;
|
||||||
widget.messageList[receivedMessageListCount]?.elemType == 11;
|
final endPoint = haveTimeStampMessage ? receivedMessageListCount + 1 : receivedMessageListCount;
|
||||||
final endPoint = haveTimeStampMessage
|
|
||||||
? receivedMessageListCount + 1
|
|
||||||
: receivedMessageListCount;
|
|
||||||
return widget.messageList.sublist(0, endPoint).reversed.toList();
|
return widget.messageList.sublist(0, endPoint).reversed.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,19 +316,14 @@ class _TIMUIKitHistoryMessageListState
|
||||||
final receivedNewMessageList = globalModel.receivedMessageListCount;
|
final receivedNewMessageList = globalModel.receivedMessageListCount;
|
||||||
final shouldShowUnreadMessage = receivedNewMessageList > 0;
|
final shouldShowUnreadMessage = receivedNewMessageList > 0;
|
||||||
final unreadMessageList = _getReceivedMessageList(receivedNewMessageList);
|
final unreadMessageList = _getReceivedMessageList(receivedNewMessageList);
|
||||||
final readMessageList = messageList
|
final readMessageList = messageList.sublist(unreadMessageList.length, messageList.length).toList();
|
||||||
.sublist(unreadMessageList.length, messageList.length)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final throttleFunction =
|
final throttleFunction = OptimizeUtils.multiThrottle((index, LoadDirection direction) async {
|
||||||
OptimizeUtils.multiThrottle((index, LoadDirection direction) async {
|
final msgID = TIMUIKitChatUtils.getMessageIDWithinIndex(readMessageList, index);
|
||||||
final msgID =
|
|
||||||
TIMUIKitChatUtils.getMessageIDWithinIndex(readMessageList, index);
|
|
||||||
await widget.onLoadMore(msgID, direction);
|
await widget.onLoadMore(msgID, direction);
|
||||||
}, 20);
|
}, 20);
|
||||||
|
|
||||||
final throttleFunctionWithMsgID =
|
final throttleFunctionWithMsgID = OptimizeUtils.multiThrottle((msgID, LoadDirection direction) async {
|
||||||
OptimizeUtils.multiThrottle((msgID, LoadDirection direction) async {
|
|
||||||
await widget.onLoadMore(msgID, direction);
|
await widget.onLoadMore(msgID, direction);
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
|
|
@ -368,63 +346,43 @@ class _TIMUIKitHistoryMessageListState
|
||||||
center: shouldShowUnreadMessage ? centerKey : null,
|
center: shouldShowUnreadMessage ? centerKey : null,
|
||||||
key: widget.mainHistoryListConfig?.key,
|
key: widget.mainHistoryListConfig?.key,
|
||||||
primary: widget.mainHistoryListConfig?.primary,
|
primary: widget.mainHistoryListConfig?.primary,
|
||||||
physics: (widget.isAllowScroll == false)
|
physics: (widget.isAllowScroll == false) ? const NeverScrollableScrollPhysics() : widget.mainHistoryListConfig?.physics,
|
||||||
? const NeverScrollableScrollPhysics()
|
|
||||||
: widget.mainHistoryListConfig?.physics,
|
|
||||||
// padding: widget.mainHistoryListConfig?.padding ?? EdgeInsets.zero,
|
// padding: widget.mainHistoryListConfig?.padding ?? EdgeInsets.zero,
|
||||||
// itemExtent: widget.mainHistoryListConfig?.itemExtent,
|
// itemExtent: widget.mainHistoryListConfig?.itemExtent,
|
||||||
// prototypeItem: widget.mainHistoryListConfig?.prototypeItem,
|
// prototypeItem: widget.mainHistoryListConfig?.prototypeItem,
|
||||||
cacheExtent: widget.mainHistoryListConfig?.cacheExtent ?? 1500,
|
cacheExtent: widget.mainHistoryListConfig?.cacheExtent ?? 1500,
|
||||||
semanticChildCount:
|
semanticChildCount: widget.mainHistoryListConfig?.semanticChildCount,
|
||||||
widget.mainHistoryListConfig?.semanticChildCount,
|
dragStartBehavior: widget.mainHistoryListConfig?.dragStartBehavior ?? DragStartBehavior.start,
|
||||||
dragStartBehavior:
|
keyboardDismissBehavior: widget.mainHistoryListConfig?.keyboardDismissBehavior ?? ScrollViewKeyboardDismissBehavior.manual,
|
||||||
widget.mainHistoryListConfig?.dragStartBehavior ??
|
|
||||||
DragStartBehavior.start,
|
|
||||||
keyboardDismissBehavior:
|
|
||||||
widget.mainHistoryListConfig?.keyboardDismissBehavior ??
|
|
||||||
ScrollViewKeyboardDismissBehavior.manual,
|
|
||||||
restorationId: widget.mainHistoryListConfig?.restorationId,
|
restorationId: widget.mainHistoryListConfig?.restorationId,
|
||||||
clipBehavior:
|
clipBehavior: widget.mainHistoryListConfig?.clipBehavior ?? Clip.hardEdge,
|
||||||
widget.mainHistoryListConfig?.clipBehavior ?? Clip.hardEdge,
|
|
||||||
reverse: true,
|
reverse: true,
|
||||||
shrinkWrap: !shouldShowUnreadMessage,
|
shrinkWrap: !shouldShowUnreadMessage,
|
||||||
controller: _autoScrollController,
|
controller: _autoScrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
SliverPadding(
|
SliverPadding(
|
||||||
padding:
|
padding: widget.mainHistoryListConfig?.padding ?? EdgeInsets.zero,
|
||||||
widget.mainHistoryListConfig?.padding ?? EdgeInsets.zero,
|
|
||||||
sliver: SliverList(
|
sliver: SliverList(
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(BuildContext context, int index) {
|
(BuildContext context, int index) {
|
||||||
final messageItem = unreadMessageList[index];
|
final messageItem = unreadMessageList[index];
|
||||||
if (index == unreadMessageList.length - 1 &&
|
if (index == unreadMessageList.length - 1 && widget.model.haveMoreLatestData == true) {
|
||||||
widget.model.haveMoreLatestData == true) {
|
throttleFunctionWithMsgID(messageItem?.msgID ?? "", LoadDirection.latest);
|
||||||
throttleFunctionWithMsgID(
|
|
||||||
messageItem?.msgID ?? "",
|
|
||||||
LoadDirection.latest);
|
|
||||||
}
|
}
|
||||||
|
outputLogger.i("Rendering a unread message: ${getMessageIdentifier(messageItem, 0)}, message Type: ${messageItem?.elemType}");
|
||||||
return AutoScrollTag(
|
return AutoScrollTag(
|
||||||
controller: _autoScrollController,
|
controller: _autoScrollController,
|
||||||
index: -index,
|
index: -index,
|
||||||
key: ValueKey(
|
key: ValueKey(getMessageIdentifier(messageItem, index)),
|
||||||
getMessageIdentifier(messageItem, index)),
|
|
||||||
highlightColor: Colors.black.withOpacity(0.1),
|
highlightColor: Colors.black.withOpacity(0.1),
|
||||||
child: KeepAliveWrapper(
|
child: KeepAliveWrapper(keepAlive: messageItem?.elemType == MessageElemType.V2TIM_ELEM_TYPE_SOUND, child: Container(child: _getMessageItemBuilder(messageItem))),
|
||||||
keepAlive: messageItem?.elemType ==
|
|
||||||
MessageElemType.V2TIM_ELEM_TYPE_SOUND,
|
|
||||||
child: Container(
|
|
||||||
child:
|
|
||||||
_getMessageItemBuilder(messageItem))),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: unreadMessageList.length,
|
childCount: unreadMessageList.length,
|
||||||
findChildIndexCallback: (Key key) {
|
findChildIndexCallback: (Key key) {
|
||||||
final ValueKey<String> valueKey =
|
final ValueKey<String> valueKey = key as ValueKey<String>;
|
||||||
key as ValueKey<String>;
|
|
||||||
final String data = valueKey.value;
|
final String data = valueKey.value;
|
||||||
final int index = unreadMessageList.indexWhere(
|
final int index = unreadMessageList.indexWhere((element) => getMessageIdentifier(element, 0) == data);
|
||||||
(element) =>
|
|
||||||
getMessageIdentifier(element, 0) == data);
|
|
||||||
return index != -1 ? index : null;
|
return index != -1 ? index : null;
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
|
|
@ -433,8 +391,7 @@ class _TIMUIKitHistoryMessageListState
|
||||||
key: centerKey,
|
key: centerKey,
|
||||||
),
|
),
|
||||||
SliverPadding(
|
SliverPadding(
|
||||||
padding:
|
padding: widget.mainHistoryListConfig?.padding ?? EdgeInsets.zero,
|
||||||
widget.mainHistoryListConfig?.padding ?? EdgeInsets.zero,
|
|
||||||
sliver: Selector<TUIChatSeparateViewModel, bool>(
|
sliver: Selector<TUIChatSeparateViewModel, bool>(
|
||||||
selector: (context, model) {
|
selector: (context, model) {
|
||||||
return model.haveMoreData;
|
return model.haveMoreData;
|
||||||
|
|
@ -449,64 +406,41 @@ class _TIMUIKitHistoryMessageListState
|
||||||
final messageItem = readMessageList[index];
|
final messageItem = readMessageList[index];
|
||||||
if (index == readMessageList.length - 1) {
|
if (index == readMessageList.length - 1) {
|
||||||
if (haveMoreData) {
|
if (haveMoreData) {
|
||||||
throttleFunction(
|
throttleFunction(index, LoadDirection.previous);
|
||||||
index, LoadDirection.previous);
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
LoadingAnimationWidget
|
LoadingAnimationWidget.staggeredDotsWave(
|
||||||
.staggeredDotsWave(
|
color: theme.weakTextColor ?? Colors.grey,
|
||||||
color: theme.weakTextColor ??
|
|
||||||
Colors.grey,
|
|
||||||
size: 28,
|
size: 28,
|
||||||
),
|
),
|
||||||
AutoScrollTag(
|
AutoScrollTag(
|
||||||
controller: _autoScrollController,
|
controller: _autoScrollController,
|
||||||
index: -index,
|
index: -index,
|
||||||
key: ValueKey(getMessageIdentifier(
|
key: ValueKey(getMessageIdentifier(messageItem, index)),
|
||||||
messageItem, index)),
|
highlightColor: Colors.black.withOpacity(0.1),
|
||||||
highlightColor:
|
child: KeepAliveWrapper(keepAlive: messageItem?.elemType == MessageElemType.V2TIM_ELEM_TYPE_SOUND, child: Container(child: _getMessageItemBuilder(messageItem))),
|
||||||
Colors.black.withOpacity(0.1),
|
|
||||||
child: KeepAliveWrapper(
|
|
||||||
keepAlive: messageItem
|
|
||||||
?.elemType ==
|
|
||||||
MessageElemType
|
|
||||||
.V2TIM_ELEM_TYPE_SOUND,
|
|
||||||
child: Container(
|
|
||||||
child: _getMessageItemBuilder(
|
|
||||||
messageItem))),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (index == 0 &&
|
if (index == 0 && widget.model.haveMoreLatestData == true && globalModel.receivedMessageListCount < 10) {
|
||||||
widget.model.haveMoreLatestData == true &&
|
|
||||||
globalModel.receivedMessageListCount < 10) {
|
|
||||||
throttleFunction(index, LoadDirection.latest);
|
throttleFunction(index, LoadDirection.latest);
|
||||||
}
|
}
|
||||||
|
outputLogger.i("Rendering a read message: ${getMessageIdentifier(messageItem, 0)}, message Type: ${messageItem?.elemType}");
|
||||||
return AutoScrollTag(
|
return AutoScrollTag(
|
||||||
controller: _autoScrollController,
|
controller: _autoScrollController,
|
||||||
index: -index,
|
index: -index,
|
||||||
key: ValueKey(
|
key: ValueKey(getMessageIdentifier(messageItem, index)),
|
||||||
getMessageIdentifier(messageItem, index)),
|
|
||||||
highlightColor: Colors.black.withOpacity(0.1),
|
highlightColor: Colors.black.withOpacity(0.1),
|
||||||
child: KeepAliveWrapper(
|
child: KeepAliveWrapper(keepAlive: messageItem?.elemType == MessageElemType.V2TIM_ELEM_TYPE_SOUND, child: Container(child: _getMessageItemBuilder(messageItem))),
|
||||||
keepAlive: messageItem?.elemType ==
|
|
||||||
MessageElemType.V2TIM_ELEM_TYPE_SOUND,
|
|
||||||
child: Container(
|
|
||||||
child: _getMessageItemBuilder(
|
|
||||||
messageItem))),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
childCount: readMessageList.length,
|
childCount: readMessageList.length,
|
||||||
findChildIndexCallback: (Key key) {
|
findChildIndexCallback: (Key key) {
|
||||||
final ValueKey<String> valueKey =
|
final ValueKey<String> valueKey = key as ValueKey<String>;
|
||||||
key as ValueKey<String>;
|
|
||||||
final String data = valueKey.value;
|
final String data = valueKey.value;
|
||||||
final int index = readMessageList.indexWhere(
|
final int index = readMessageList.indexWhere((element) => getMessageIdentifier(element, 0) == data);
|
||||||
(element) =>
|
|
||||||
getMessageIdentifier(element, 0) ==
|
|
||||||
data);
|
|
||||||
return index > -1 ? index : null;
|
return index > -1 ? index : null;
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
@ -539,17 +473,14 @@ class TIMUIKitHistoryMessageListSelector extends TIMUIKitStatelessWidget {
|
||||||
final Widget Function(BuildContext, List<V2TimMessage?>, Widget?) builder;
|
final Widget Function(BuildContext, List<V2TimMessage?>, Widget?) builder;
|
||||||
final String conversationID;
|
final String conversationID;
|
||||||
|
|
||||||
TIMUIKitHistoryMessageListSelector(
|
TIMUIKitHistoryMessageListSelector({Key? key, required this.builder, required this.conversationID}) : super(key: key);
|
||||||
{Key? key, required this.builder, required this.conversationID})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
|
||||||
return Selector<TUIChatGlobalModel, List<V2TimMessage?>>(
|
return Selector<TUIChatGlobalModel, List<V2TimMessage?>>(
|
||||||
builder: builder,
|
builder: builder,
|
||||||
shouldRebuild: (previous, next) {
|
shouldRebuild: (previous, next) {
|
||||||
final isEquals =
|
final isEquals = const DeepCollectionEquality.unordered().equals(previous, next);
|
||||||
const DeepCollectionEquality.unordered().equals(previous, next);
|
|
||||||
return !isEquals;
|
return !isEquals;
|
||||||
},
|
},
|
||||||
selector: (context, model) {
|
selector: (context, model) {
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,27 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:diff_match_patch/diff_match_patch.dart';
|
import 'package:diff_match_patch/diff_match_patch.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/emoji_text.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
import 'package:scroll_to_index/scroll_to_index.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/business_logic/separate_models/tui_chat_separate_view_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_chat_separate_view_model.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_chat_global_model.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_conversation_view_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_conversation_view_model.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_self_info_view_model.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/business_logic/view_models/tui_setting_model.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
import 'package:tencent_cloud_chat_uikit/data_services/services_locatar.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/message.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/special_text/emoji_text.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_at_text.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_at_text.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/narrow.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/wide.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitChat/TIMUIKitTextField/tim_uikit_text_field_layout/wide.dart';
|
||||||
|
|
||||||
enum MuteStatus { none, me, all }
|
enum MuteStatus { none, me, all }
|
||||||
|
|
@ -141,8 +142,7 @@ 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 =
|
final TUIConversationViewModel conversationModel = serviceLocator<TUIConversationViewModel>();
|
||||||
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,56 +154,38 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
// Keep using original scheme.
|
// Keep using original scheme.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final stickerConfig =
|
final stickerConfig = widget.model.chatConfig.stickerPanelConfig ?? StickerPanelConfig();
|
||||||
widget.model.chatConfig.stickerPanelConfig ?? StickerPanelConfig();
|
|
||||||
if (stickerConfig.useTencentCloudChatStickerPackage) {
|
if (stickerConfig.useTencentCloudChatStickerPackage) {
|
||||||
final tccEmojiSet = TUIKitStickerConstData.emojiList
|
final tccEmojiSet = TUIKitStickerConstData.emojiList.firstWhere((element) => element.name == "tcc1");
|
||||||
.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
|
stickerList: tccEmojiSet.list.asMap().keys.map((idx) => CustomSticker(index: idx, name: tccEmojiSet.list[idx])).toList(),
|
||||||
.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) {
|
if (stickerConfig.useQQStickerPackage) {
|
||||||
final qqEmojiSet = TUIKitStickerConstData.emojiList
|
final qqEmojiSet = TUIKitStickerConstData.emojiList.firstWhere((element) => element.name == "4349");
|
||||||
.firstWhere((element) => element.name == "4349");
|
|
||||||
stickerPackageList.add(CustomStickerPackage(
|
stickerPackageList.add(CustomStickerPackage(
|
||||||
name: qqEmojiSet.name,
|
name: qqEmojiSet.name,
|
||||||
baseUrl: "assets/custom_face_resource/${qqEmojiSet.name}",
|
baseUrl: "assets/custom_face_resource/${qqEmojiSet.name}",
|
||||||
isEmoji: qqEmojiSet.isEmoji,
|
isEmoji: qqEmojiSet.isEmoji,
|
||||||
isDefaultEmoji: true,
|
isDefaultEmoji: true,
|
||||||
stickerList: qqEmojiSet.list
|
stickerList: qqEmojiSet.list.asMap().keys.map((idx) => CustomSticker(index: idx, name: qqEmojiSet.list[idx])).toList(),
|
||||||
.asMap()
|
|
||||||
.keys
|
|
||||||
.map((idx) =>
|
|
||||||
CustomSticker(index: idx, name: qqEmojiSet.list[idx]))
|
|
||||||
.toList(),
|
|
||||||
menuItem: CustomSticker(
|
menuItem: CustomSticker(
|
||||||
index: 0,
|
index: 0,
|
||||||
name: qqEmojiSet.icon,
|
name: qqEmojiSet.icon,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
if (stickerConfig.unicodeEmojiList.isNotEmpty) {
|
if (stickerConfig.unicodeEmojiList.isNotEmpty) {
|
||||||
final defEmojiList =
|
final defEmojiList = TUIKitStickerConstData.defaultUnicodeEmojiList.map((emojiItem) {
|
||||||
TUIKitStickerConstData.defaultUnicodeEmojiList.map((emojiItem) {
|
return CustomSticker(index: 0, name: emojiItem.toString(), unicode: emojiItem);
|
||||||
return CustomSticker(
|
|
||||||
index: 0, name: emojiItem.toString(), unicode: emojiItem);
|
|
||||||
}).toList();
|
}).toList();
|
||||||
stickerPackageList.add(CustomStickerPackage(
|
stickerPackageList.add(CustomStickerPackage(name: "defaultEmoji", stickerList: defEmojiList, menuItem: defEmojiList[0]));
|
||||||
name: "defaultEmoji",
|
|
||||||
stickerList: defEmojiList,
|
|
||||||
menuItem: defEmojiList[0]));
|
|
||||||
}
|
}
|
||||||
stickerPackageList.addAll(stickerConfig.customStickerPackages);
|
stickerPackageList.addAll(stickerConfig.customStickerPackages);
|
||||||
|
|
||||||
|
|
@ -253,9 +235,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
textEditingController.text = text;
|
textEditingController.text = text;
|
||||||
|
|
||||||
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
||||||
textEditingController.selection = TextSelection.fromPosition(
|
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: currentCursor ?? textEditingController.text.length));
|
||||||
TextPosition(
|
|
||||||
offset: currentCursor ?? textEditingController.text.length));
|
|
||||||
focusNode.requestFocus();
|
focusNode.requestFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -263,9 +243,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
|
|
||||||
void addStickerToText(String sticker) {
|
void addStickerToText(String sticker) {
|
||||||
final currentText = textEditingController.text;
|
final currentText = textEditingController.text;
|
||||||
if (currentCursor != null &&
|
if (currentCursor != null && currentCursor! > -1 && currentCursor! < currentText.length + 1) {
|
||||||
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;
|
||||||
|
|
@ -276,8 +254,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
if (TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop) {
|
||||||
textEditingController.selection = TextSelection.fromPosition(TextPosition(
|
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: currentCursor ?? textEditingController.text.length));
|
||||||
offset: currentCursor ?? textEditingController.text.length));
|
|
||||||
focusNode.requestFocus();
|
focusNode.requestFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -286,23 +263,13 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
return text.replaceAll(RegExp(r'\ufeff'), "");
|
return text.replaceAll(RegExp(r'\ufeff'), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future handleSetDraftText(
|
Future handleSetDraftText({String? id, ConvType? convType, String? groupID}) async {
|
||||||
{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
|
String conversationID = isTopic ? convID : ((convType ?? widget.conversationType) == ConvType.c2c ? "c2c_$convID" : "group_$convID");
|
||||||
? convID
|
|
||||||
: ((convType ?? widget.conversationType) == ConvType.c2c
|
|
||||||
? "c2c_$convID"
|
|
||||||
: "group_$convID");
|
|
||||||
String draftText = _filterU200b(text);
|
String draftText = _filterU200b(text);
|
||||||
return await conversationModel.setConversationDraft(
|
return await conversationModel.setConversationDraft(groupID: groupID ?? widget.groupID, isTopic: isTopic, isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb, conversationID: conversationID, draftText: draftText);
|
||||||
groupID: groupID ?? widget.groupID,
|
|
||||||
isTopic: isTopic,
|
|
||||||
isAllowWeb: widget.model.chatConfig.isUseDraftOnWeb,
|
|
||||||
conversationID: conversationID,
|
|
||||||
draftText: draftText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 和onSubmitted一样,只是保持焦点的不同
|
// 和onSubmitted一样,只是保持焦点的不同
|
||||||
|
|
@ -350,21 +317,9 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widget.model.repliedMessage != null) {
|
if (widget.model.repliedMessage != null) {
|
||||||
MessageUtils.handleMessageError(
|
MessageUtils.handleMessageError(widget.model.sendFaceMessage(index: index, data: data, convID: widget.conversationID, convType: convType), context);
|
||||||
widget.model.sendFaceMessage(
|
|
||||||
index: index,
|
|
||||||
data: data,
|
|
||||||
convID: widget.conversationID,
|
|
||||||
convType: convType),
|
|
||||||
context);
|
|
||||||
} else {
|
} else {
|
||||||
MessageUtils.handleMessageError(
|
MessageUtils.handleMessageError(widget.model.sendFaceMessage(index: index, data: data, convID: widget.conversationID, convType: convType), context);
|
||||||
widget.model.sendFaceMessage(
|
|
||||||
index: index,
|
|
||||||
data: data,
|
|
||||||
convID: widget.conversationID,
|
|
||||||
convType: convType),
|
|
||||||
context);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -384,24 +339,11 @@ 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(
|
MessageUtils.handleMessageError(widget.model.sendReplyMessage(text: text, convID: widget.conversationID, convType: convType, atUserIDList: getUserIdFromMemberInfoMap()), context);
|
||||||
widget.model.sendReplyMessage(
|
|
||||||
text: text,
|
|
||||||
convID: widget.conversationID,
|
|
||||||
convType: convType,
|
|
||||||
atUserIDList: getUserIdFromMemberInfoMap()),
|
|
||||||
context);
|
|
||||||
} else if (mentionedMembersMap.isNotEmpty) {
|
} else if (mentionedMembersMap.isNotEmpty) {
|
||||||
widget.model.sendTextAtMessage(
|
widget.model.sendTextAtMessage(text: text, convType: widget.conversationType, convID: widget.conversationID, atUserList: getUserIdFromMemberInfoMap());
|
||||||
text: text,
|
|
||||||
convType: widget.conversationType,
|
|
||||||
convID: widget.conversationID,
|
|
||||||
atUserList: getUserIdFromMemberInfoMap());
|
|
||||||
} else {
|
} else {
|
||||||
MessageUtils.handleMessageError(
|
MessageUtils.handleMessageError(widget.model.sendTextMessage(text: text, convID: widget.conversationID, convType: convType), context);
|
||||||
widget.model.sendTextMessage(
|
|
||||||
text: text, convID: widget.conversationID, convType: convType),
|
|
||||||
context);
|
|
||||||
}
|
}
|
||||||
textEditingController.clear();
|
textEditingController.clear();
|
||||||
currentCursor = null;
|
currentCursor = null;
|
||||||
|
|
@ -414,8 +356,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void goDownBottom() {
|
void goDownBottom() {
|
||||||
if (globalModel.getMessageListPosition(widget.conversationID) ==
|
if (globalModel.getMessageListPosition(widget.conversationID) == HistoryMessagePosition.notShowLatest) {
|
||||||
HistoryMessagePosition.notShowLatest) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Future.delayed(const Duration(milliseconds: 50), () {
|
Future.delayed(const Duration(milliseconds: 50), () {
|
||||||
|
|
@ -444,18 +385,14 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getShowName(V2TimGroupMemberFullInfo? item) {
|
String _getShowName(V2TimGroupMemberFullInfo? item) {
|
||||||
return TencentUtils.checkStringWithoutSpace(item?.nameCard) ??
|
return TencentUtils.checkStringWithoutSpace(item?.nameCard) ?? TencentUtils.checkStringWithoutSpace(item?.nickName) ?? TencentUtils.checkStringWithoutSpace(item?.userID) ?? "";
|
||||||
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
|
final memberInfo = widget.model.groupMemberList?.firstWhereOrNull((element) => element?.userID == userID) ??
|
||||||
?.firstWhereOrNull((element) => element?.userID == userID) ??
|
|
||||||
V2TimGroupMemberFullInfo(
|
V2TimGroupMemberFullInfo(
|
||||||
userID: userID ?? "",
|
userID: userID ?? "",
|
||||||
nickName: nickName,
|
nickName: nickName,
|
||||||
|
|
@ -466,8 +403,7 @@ 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 =
|
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: text.length));
|
||||||
TextSelection.fromPosition(TextPosition(offset: text.length));
|
|
||||||
lastText = text;
|
lastText = text;
|
||||||
_isComposingText = false;
|
_isComposingText = false;
|
||||||
narrowTextFieldKey.currentState?.showKeyboard = true;
|
narrowTextFieldKey.currentState?.showKeyboard = true;
|
||||||
|
|
@ -495,16 +431,10 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
maxLines: null,
|
maxLines: null,
|
||||||
);
|
);
|
||||||
textPainter.layout(maxWidth: inputWidth);
|
textPainter.layout(maxWidth: inputWidth);
|
||||||
final TextPosition lastLineOffset = textPainter
|
final TextPosition lastLineOffset = textPainter.getPositionForOffset(Offset(textPainter.width, textPainter.height));
|
||||||
.getPositionForOffset(Offset(textPainter.width, textPainter.height));
|
final Offset caretPosition = textPainter.getOffsetForCaret(lastLineOffset, Rect.zero);
|
||||||
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(
|
final dy = max(24, 21 * widget.model.chatConfig.desktopMessageInputFieldLines - caretPosition.dy).toDouble();
|
||||||
24,
|
|
||||||
21 * widget.model.chatConfig.desktopMessageInputFieldLines -
|
|
||||||
caretPosition.dy)
|
|
||||||
.toDouble();
|
|
||||||
|
|
||||||
return Offset(dx, dy);
|
return Offset(dx, dy);
|
||||||
}
|
}
|
||||||
|
|
@ -541,19 +471,13 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
mentionedMembersMap = map;
|
mentionedMembersMap = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
(int, String, bool)? findChangedCharacter(
|
(int, String, bool)? findChangedCharacter(String originalString, String newString) {
|
||||||
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] !=
|
if (originalString[originalStringLength - i - 1] != newString[newStringLength - i - 1]) {
|
||||||
newString[newStringLength - i - 1]) {
|
return (newStringLength - i, originalString[originalStringLength - i - 1], false);
|
||||||
return (
|
|
||||||
newStringLength - i,
|
|
||||||
originalString[originalStringLength - i - 1],
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (newString.length, originalString[newString.length], false);
|
return (newString.length, originalString[newString.length], false);
|
||||||
|
|
@ -572,11 +496,8 @@ 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
|
String? groupID = widget.conversationType == ConvType.group ? widget.conversationID : null;
|
||||||
? widget.conversationID
|
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||||
: null;
|
|
||||||
final isDesktopScreen =
|
|
||||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
|
||||||
|
|
||||||
if (groupID == null) {
|
if (groupID == null) {
|
||||||
lastText = text;
|
lastText = text;
|
||||||
|
|
@ -596,11 +517,9 @@ 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) +
|
final newText = originalText.substring(0, atIndex) + originalText.substring(spaceIndex + 1);
|
||||||
originalText.substring(spaceIndex + 1);
|
|
||||||
textEditingController.text = newText;
|
textEditingController.text = newText;
|
||||||
textEditingController.selection =
|
textEditingController.selection = TextSelection.collapsed(offset: atIndex);
|
||||||
TextSelection.collapsed(offset: atIndex);
|
|
||||||
lastText = newText;
|
lastText = newText;
|
||||||
updateMentionedMap();
|
updateMentionedMap();
|
||||||
return;
|
return;
|
||||||
|
|
@ -610,13 +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 =
|
final bool canAtAll = (selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN || selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER);
|
||||||
(selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN ||
|
|
||||||
selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER);
|
|
||||||
|
|
||||||
if (isDesktopScreen) {
|
if (isDesktopScreen) {
|
||||||
(int, String, bool)? changedCharacterRecord =
|
(int, String, bool)? changedCharacterRecord = findChangedCharacter(originalText, text);
|
||||||
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;
|
||||||
|
|
@ -625,13 +541,10 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
int? atPlace;
|
int? atPlace;
|
||||||
|
|
||||||
if (changedTextPosition != null) {
|
if (changedTextPosition != null) {
|
||||||
subText = isAdded == true
|
subText = isAdded == true ? text.substring(0, changedTextPosition + 1) : text.substring(0, changedTextPosition);
|
||||||
? text.substring(0, changedTextPosition + 1)
|
|
||||||
: text.substring(0, changedTextPosition);
|
|
||||||
atPlace = subText.lastIndexOf('@');
|
atPlace = subText.lastIndexOf('@');
|
||||||
if (atPlace != -1) {
|
if (atPlace != -1) {
|
||||||
keyword = text.substring(
|
keyword = text.substring(atPlace + 1, changedTextPosition + (isAdded ? 1 : 0));
|
||||||
atPlace + 1, changedTextPosition + (isAdded ? 1 : 0));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
atPlace = -1;
|
atPlace = -1;
|
||||||
|
|
@ -644,28 +557,21 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
model.atPositionY = atPosition.dy;
|
model.atPositionY = atPosition.dy;
|
||||||
isAddingAtSearchWords = true;
|
isAddingAtSearchWords = true;
|
||||||
}
|
}
|
||||||
List<V2TimGroupMemberFullInfo> showAtMemberList = (model
|
List<V2TimGroupMemberFullInfo> showAtMemberList = (model.groupMemberList ?? [])
|
||||||
.groupMemberList ??
|
|
||||||
[])
|
|
||||||
.where((element) {
|
.where((element) {
|
||||||
final showName = (TencentUtils.checkStringWithoutSpace(
|
final showName = (TencentUtils.checkStringWithoutSpace(element?.friendRemark) ??
|
||||||
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 &&
|
return element != null && showName.contains(keyword!.toLowerCase()) && TencentUtils.checkString(showName) != null && element.userID != widget.model.selfMemberInfo?.userID;
|
||||||
showName.contains(keyword!.toLowerCase()) &&
|
|
||||||
TencentUtils.checkString(showName) != null &&
|
|
||||||
element.userID != widget.model.selfMemberInfo?.userID;
|
|
||||||
})
|
})
|
||||||
.whereType<V2TimGroupMemberFullInfo>()
|
.whereType<V2TimGroupMemberFullInfo>()
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
showAtMemberList.sort(
|
showAtMemberList.sort((V2TimGroupMemberFullInfo userA, V2TimGroupMemberFullInfo userB) {
|
||||||
(V2TimGroupMemberFullInfo userA, V2TimGroupMemberFullInfo userB) {
|
|
||||||
final isUserAIsGroupAdmin = userA.role == 300;
|
final isUserAIsGroupAdmin = userA.role == 300;
|
||||||
final isUserAIsGroupOwner = userA.role == 400;
|
final isUserAIsGroupOwner = userA.role == 400;
|
||||||
|
|
||||||
|
|
@ -688,11 +594,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
|
|
||||||
keyword ??= "";
|
keyword ??= "";
|
||||||
if (canAtAll && showAtMemberList.isNotEmpty && keyword!.isEmpty) {
|
if (canAtAll && showAtMemberList.isNotEmpty && keyword!.isEmpty) {
|
||||||
showAtMemberList = [
|
showAtMemberList = [V2TimGroupMemberFullInfo(userID: "__kImSDK_MesssageAtALL__", nickName: TIM_t("所有人")), ...showAtMemberList];
|
||||||
V2TimGroupMemberFullInfo(
|
|
||||||
userID: "__kImSDK_MesssageAtALL__", nickName: TIM_t("所有人")),
|
|
||||||
...showAtMemberList
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model.activeAtIndex = 0;
|
model.activeAtIndex = 0;
|
||||||
|
|
@ -704,18 +606,11 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
model.showAtMemberList = [];
|
model.showAtMemberList = [];
|
||||||
isAddingAtSearchWords = false;
|
isAddingAtSearchWords = false;
|
||||||
}
|
}
|
||||||
} else if (textLength > 0 &&
|
} else if (textLength > 0 && text[textLength - 1] == "@" && lastText.length < textLength) {
|
||||||
text[textLength - 1] == "@" &&
|
|
||||||
lastText.length < textLength) {
|
|
||||||
V2TimGroupMemberFullInfo? memberInfo = await Navigator.push(
|
V2TimGroupMemberFullInfo? memberInfo = await Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => AtText(
|
builder: (context) => AtText(groupMemberList: model.groupMemberList, groupInfo: model.groupInfo, groupID: groupID, canAtAll: canAtAll, groupType: widget.groupType),
|
||||||
groupMemberList: model.groupMemberList,
|
|
||||||
groupInfo: model.groupInfo,
|
|
||||||
groupID: groupID,
|
|
||||||
canAtAll: canAtAll,
|
|
||||||
groupType: widget.groupType),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final showName = _getShowName(memberInfo);
|
final showName = _getShowName(memberInfo);
|
||||||
|
|
@ -730,22 +625,17 @@ 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 =
|
int atIndex = textEditingController.text.lastIndexOf('@', cursorPosition - 1);
|
||||||
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 =
|
textEditingController.text = beforeAt + '@' + selectedMember + ' ' + afterAt;
|
||||||
beforeAt + '@' + selectedMember + ' ' + afterAt;
|
textEditingController.selection = TextSelection.collapsed(offset: atIndex + selectedMember.length + 2);
|
||||||
textEditingController.selection =
|
|
||||||
TextSelection.collapsed(offset: atIndex + selectedMember.length + 2);
|
|
||||||
lastText = beforeAt + '@' + selectedMember + ' ' + afterAt;
|
lastText = beforeAt + '@' + selectedMember + ' ' + afterAt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleAtMember(
|
void handleAtMember({V2TimGroupMemberFullInfo? memberInfo, bool? isAddToCursorPosition = false}) {
|
||||||
{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;
|
||||||
|
|
@ -759,24 +649,17 @@ 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) ||
|
final isPressEnter = (event.physicalKey == PhysicalKeyboardKey.enter) || (event.physicalKey == PhysicalKeyboardKey.numpadEnter);
|
||||||
(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 ||
|
} else if ((event.isShiftPressed || event.isAltPressed || event.isControlPressed || event.isMetaPressed) && isPressEnter) {
|
||||||
event.isAltPressed ||
|
|
||||||
event.isControlPressed ||
|
|
||||||
event.isMetaPressed) &&
|
|
||||||
isPressEnter) {
|
|
||||||
final offset = textEditingController.selection.baseOffset;
|
final offset = textEditingController.selection.baseOffset;
|
||||||
textEditingController.text =
|
textEditingController.text = '${lastText.substring(0, offset)}\n${lastText.substring(offset)}';
|
||||||
'${lastText.substring(0, offset)}\n${lastText.substring(offset)}';
|
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: offset + 1));
|
||||||
textEditingController.selection =
|
|
||||||
TextSelection.fromPosition(TextPosition(offset: offset + 1));
|
|
||||||
lastText = textEditingController.text;
|
lastText = textEditingController.text;
|
||||||
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
|
|
@ -786,34 +669,26 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
onSubmitted();
|
onSubmitted();
|
||||||
} else {
|
} else {
|
||||||
isAddingAtSearchWords = false;
|
isAddingAtSearchWords = false;
|
||||||
final V2TimGroupMemberFullInfo? memberInfo =
|
final V2TimGroupMemberFullInfo? memberInfo = showMemberList[activeIndex];
|
||||||
showMemberList[activeIndex];
|
|
||||||
if (memberInfo != null) {
|
if (memberInfo != null) {
|
||||||
handleAtMember(
|
handleAtMember(memberInfo: memberInfo, isAddToCursorPosition: true);
|
||||||
memberInfo: memberInfo, isAddToCursorPosition: true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.isKeyPressed(LogicalKeyboardKey.arrowUp) &&
|
if (event.isKeyPressed(LogicalKeyboardKey.arrowUp) && isAddingAtSearchWords && showMemberList.isNotEmpty) {
|
||||||
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,
|
widget.atMemberPanelScroll?.scrollToIndex(newIndex, preferPosition: AutoScrollPosition.middle);
|
||||||
preferPosition: AutoScrollPosition.middle);
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.isKeyPressed(LogicalKeyboardKey.arrowDown) &&
|
if (event.isKeyPressed(LogicalKeyboardKey.arrowDown) && isAddingAtSearchWords && showMemberList.isNotEmpty) {
|
||||||
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,
|
widget.atMemberPanelScroll?.scrollToIndex(newIndex, preferPosition: AutoScrollPosition.middle);
|
||||||
preferPosition: AutoScrollPosition.middle);
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -831,8 +706,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
} else {
|
} else {
|
||||||
focusNode = FocusNode();
|
focusNode = FocusNode();
|
||||||
}
|
}
|
||||||
textEditingController =
|
textEditingController = widget.controller?.textEditingController ?? TextEditingController();
|
||||||
widget.controller?.textEditingController ?? TextEditingController();
|
|
||||||
if (widget.initText != null) {
|
if (widget.initText != null) {
|
||||||
textEditingController.text = widget.initText!;
|
textEditingController.text = widget.initText!;
|
||||||
}
|
}
|
||||||
|
|
@ -840,10 +714,7 @@ 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 =
|
languageType = (appLocale == AppLocale.zhHans || appLocale == AppLocale.zhHant) ? 'zh' : 'en';
|
||||||
(appLocale == AppLocale.zhHans || appLocale == AppLocale.zhHant)
|
|
||||||
? 'zh'
|
|
||||||
: 'en';
|
|
||||||
textEditingController.addListener(() {
|
textEditingController.addListener(() {
|
||||||
_isComposingText = textEditingController.value.composing.start != -1;
|
_isComposingText = textEditingController.value.composing.start != -1;
|
||||||
});
|
});
|
||||||
|
|
@ -853,13 +724,11 @@ 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(
|
mentionMemberInMessage(widget.controller?.atUserID, widget.controller?.atUserName);
|
||||||
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(
|
textEditingController.selection = TextSelection.fromPosition(TextPosition(offset: textEditingController.text.length));
|
||||||
TextPosition(offset: textEditingController.text.length));
|
|
||||||
lastText = textEditingController.text;
|
lastText = textEditingController.text;
|
||||||
focusNode.requestFocus();
|
focusNode.requestFocus();
|
||||||
return;
|
return;
|
||||||
|
|
@ -877,18 +746,14 @@ 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(
|
handleSetDraftText(id: oldWidget.conversationID, convType: oldWidget.conversationType, groupID: oldWidget.groupID);
|
||||||
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 &&
|
if (widget.initText != oldWidget.initText && TencentUtils.checkString(widget.initText) != null) {
|
||||||
TencentUtils.checkString(widget.initText) != null) {
|
|
||||||
textEditingController.text = widget.initText!;
|
textEditingController.text = widget.initText!;
|
||||||
focusNode.requestFocus();
|
focusNode.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
@ -906,12 +771,8 @@ 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)) ??
|
if (widget.model.groupMemberList?.any((item) => (item?.userID == userID)) ?? false) {
|
||||||
false) {
|
final int muteUntil = widget.model.groupMemberList?.firstWhere((item) => (item?.userID == userID))?.muteUntil ?? 0;
|
||||||
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;
|
||||||
|
|
@ -924,42 +785,28 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
}
|
}
|
||||||
|
|
||||||
final int selfRole = widget.model.selfMemberInfo?.role ?? 0;
|
final int selfRole = widget.model.selfMemberInfo?.role ?? 0;
|
||||||
final bool willNotBeenMuted =
|
final bool willNotBeenMuted = (selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_ADMIN || selfRole == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_OWNER);
|
||||||
(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) &&
|
if ((model.groupInfo?.isAllMuted ?? false) && muteStatus != MuteStatus.all) {
|
||||||
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 &&
|
} else if (selfModel.loginInfo?.userID != null && await getMemberMuteStatus(selfModel.loginInfo!.userID!) && muteStatus != MuteStatus.me) {
|
||||||
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) &&
|
} else if (!(model.groupInfo?.isAllMuted ?? false) && !(selfModel.loginInfo?.userID != null && await getMemberMuteStatus(selfModel.loginInfo!.userID!)) && muteStatus != MuteStatus.none) {
|
||||||
!(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;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Future.delayed(const Duration(seconds: 0), () {
|
|
||||||
setState(() {
|
|
||||||
muteStatus = MuteStatus.none;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -982,8 +829,7 @@ 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 =
|
final TUIChatSeparateViewModel model = Provider.of<TUIChatSeparateViewModel>(context);
|
||||||
Provider.of<TUIChatSeparateViewModel>(context);
|
|
||||||
|
|
||||||
_getMuteType(model);
|
_getMuteType(model);
|
||||||
|
|
||||||
|
|
@ -1003,8 +849,7 @@ class _InputTextFieldState extends TIMUIKitState<TIMUIKitInputTextField> {
|
||||||
}
|
}
|
||||||
|
|
||||||
final forbiddenText = getForbiddenText();
|
final forbiddenText = getForbiddenText();
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
builder: (BuildContext context, BoxConstraints constraints) {
|
|
||||||
inputWidth = constraints.maxWidth;
|
inputWidth = constraints.maxWidth;
|
||||||
return TUIKitScreenUtils.getDeviceWidget(
|
return TUIKitScreenUtils.getDeviceWidget(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
|
||||||
import 'package:tencent_im_base/tencent_im_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_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/business_logic/separate_models/tui_group_profile_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_group_profile_model.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/contact_list.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/contact_list.dart';
|
||||||
|
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||||
|
|
||||||
GlobalKey<_AddGroupMemberPageState> addGroupMemberKey = GlobalKey();
|
GlobalKey<_AddGroupMemberPageState> addGroupMemberKey = GlobalKey();
|
||||||
|
|
||||||
class AddGroupMemberPage extends StatefulWidget {
|
class AddGroupMemberPage extends StatefulWidget {
|
||||||
final TUIGroupProfileModel model;
|
final TUIGroupProfileModel model;
|
||||||
|
final VoidCallback? onClose;
|
||||||
|
|
||||||
const AddGroupMemberPage({Key? key, required this.model}) : super(key: key);
|
const AddGroupMemberPage({Key? key, required this.model, this.onClose}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _AddGroupMemberPageState();
|
State<StatefulWidget> createState() => _AddGroupMemberPageState();
|
||||||
|
|
@ -25,7 +25,7 @@ class _AddGroupMemberPageState extends TIMUIKitState<AddGroupMemberPage> {
|
||||||
if (selectedContacts.isNotEmpty) {
|
if (selectedContacts.isNotEmpty) {
|
||||||
final userIDs = selectedContacts.map((e) => e.userID).toList();
|
final userIDs = selectedContacts.map((e) => e.userID).toList();
|
||||||
await widget.model.inviteUserToGroup(userIDs);
|
await widget.model.inviteUserToGroup(userIDs);
|
||||||
Navigator.pop(context);
|
widget.onClose ?? Navigator.pop(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,8 +68,7 @@ class _AddGroupMemberPageState extends TIMUIKitState<AddGroupMemberPage> {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
shadowColor: theme.weakDividerColor,
|
shadowColor: theme.weakDividerColor,
|
||||||
backgroundColor: theme.appbarBgColor ??
|
backgroundColor: theme.appbarBgColor ?? theme.primaryColor,
|
||||||
theme.primaryColor,
|
|
||||||
iconTheme: IconThemeData(
|
iconTheme: IconThemeData(
|
||||||
color: theme.appbarTextColor,
|
color: theme.appbarTextColor,
|
||||||
)),
|
)),
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,19 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
|
||||||
import 'package:tencent_im_base/tencent_im_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_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/business_logic/separate_models/tui_group_profile_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_group_profile_model.dart';
|
||||||
|
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/group_member_list.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/group_member_list.dart';
|
||||||
|
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||||
|
|
||||||
GlobalKey<_DeleteGroupMemberPageState> deleteGroupMemberKey = GlobalKey();
|
GlobalKey<_DeleteGroupMemberPageState> deleteGroupMemberKey = GlobalKey();
|
||||||
|
|
||||||
class DeleteGroupMemberPage extends StatefulWidget {
|
class DeleteGroupMemberPage extends StatefulWidget {
|
||||||
final TUIGroupProfileModel model;
|
final TUIGroupProfileModel model;
|
||||||
|
final VoidCallback? onClose;
|
||||||
|
|
||||||
const DeleteGroupMemberPage({Key? key, required this.model})
|
const DeleteGroupMemberPage({Key? key, required this.model, this.onClose}) : super(key: key);
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _DeleteGroupMemberPageState();
|
State<StatefulWidget> createState() => _DeleteGroupMemberPageState();
|
||||||
|
|
@ -30,11 +29,8 @@ class _DeleteGroupMemberPageState extends TIMUIKitState<DeleteGroupMemberPage> {
|
||||||
|
|
||||||
handleSearchGroupMembers(String searchText, context) async {
|
handleSearchGroupMembers(String searchText, context) async {
|
||||||
searchText = searchText;
|
searchText = searchText;
|
||||||
List<V2TimGroupMemberFullInfo?> currentGroupMember =
|
List<V2TimGroupMemberFullInfo?> currentGroupMember = Provider.of<TUIGroupProfileModel>(context, listen: false).groupMemberList;
|
||||||
Provider.of<TUIGroupProfileModel>(context, listen: false)
|
final res = await widget.model.searchGroupMember(V2TimGroupMemberSearchParam(
|
||||||
.groupMemberList;
|
|
||||||
final res =
|
|
||||||
await widget.model.searchGroupMember(V2TimGroupMemberSearchParam(
|
|
||||||
keywordList: [searchText],
|
keywordList: [searchText],
|
||||||
groupIDList: [widget.model.groupInfo!.groupID],
|
groupIDList: [widget.model.groupInfo!.groupID],
|
||||||
));
|
));
|
||||||
|
|
@ -55,25 +51,19 @@ class _DeleteGroupMemberPageState extends TIMUIKitState<DeleteGroupMemberPage> {
|
||||||
currentGroupMember = [];
|
currentGroupMember = [];
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
searchMemberList =
|
searchMemberList = isSearchTextExist(searchText) ? currentGroupMember : null;
|
||||||
isSearchTextExist(searchText) ? currentGroupMember : null;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRole(groupMemberList) {
|
handleRole(groupMemberList) {
|
||||||
return groupMemberList
|
return groupMemberList?.where((value) => value?.role == GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_MEMBER).toList() ?? [];
|
||||||
?.where((value) =>
|
|
||||||
value?.role ==
|
|
||||||
GroupMemberRoleType.V2TIM_GROUP_MEMBER_ROLE_MEMBER)
|
|
||||||
.toList() ??
|
|
||||||
[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void submitDelete() async {
|
void submitDelete() async {
|
||||||
if (selectedGroupMember.isNotEmpty) {
|
if (selectedGroupMember.isNotEmpty) {
|
||||||
final userIDs = selectedGroupMember.map((e) => e.userID).toList();
|
final userIDs = selectedGroupMember.map((e) => e.userID).toList();
|
||||||
widget.model.kickOffMember(userIDs);
|
widget.model.kickOffMember(userIDs);
|
||||||
Navigator.pop(context);
|
widget.onClose ?? Navigator.pop(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,8 +76,7 @@ class _DeleteGroupMemberPageState extends TIMUIKitState<DeleteGroupMemberPage> {
|
||||||
desktopWidget: Container(
|
desktopWidget: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: GroupProfileMemberList(
|
child: GroupProfileMemberList(
|
||||||
memberList:
|
memberList: handleRole(searchMemberList ?? widget.model.groupMemberList),
|
||||||
handleRole(searchMemberList ?? widget.model.groupMemberList),
|
|
||||||
canSelectMember: true,
|
canSelectMember: true,
|
||||||
canSlideDelete: false,
|
canSlideDelete: false,
|
||||||
onSelectedMemberChange: (selectedMember) {
|
onSelectedMemberChange: (selectedMember) {
|
||||||
|
|
@ -115,14 +104,12 @@ class _DeleteGroupMemberPageState extends TIMUIKitState<DeleteGroupMemberPage> {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
shadowColor: theme.weakBackgroundColor,
|
shadowColor: theme.weakBackgroundColor,
|
||||||
backgroundColor: theme.appbarBgColor ??
|
backgroundColor: theme.appbarBgColor ?? theme.primaryColor,
|
||||||
theme.primaryColor,
|
|
||||||
iconTheme: IconThemeData(
|
iconTheme: IconThemeData(
|
||||||
color: theme.appbarTextColor,
|
color: theme.appbarTextColor,
|
||||||
)),
|
)),
|
||||||
body: GroupProfileMemberList(
|
body: GroupProfileMemberList(
|
||||||
memberList:
|
memberList: handleRole(searchMemberList ?? widget.model.groupMemberList),
|
||||||
handleRole(searchMemberList ?? widget.model.groupMemberList),
|
|
||||||
canSelectMember: true,
|
canSelectMember: true,
|
||||||
canSlideDelete: false,
|
canSlideDelete: false,
|
||||||
onSelectedMemberChange: (selectedMember) {
|
onSelectedMemberChange: (selectedMember) {
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,15 @@
|
||||||
import 'package:dotted_border/dotted_border.dart';
|
import 'package:dotted_border/dotted_border.dart';
|
||||||
import 'package:flutter/material.dart';
|
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_statelesswidget.dart';
|
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_statelesswidget.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_group_profile_model.dart';
|
import 'package:tencent_cloud_chat_uikit/business_logic/separate_models/tui_group_profile_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/ui/utils/screen_utils.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';
|
||||||
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitGroupProfile/group_member/tui_add_group_member.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitGroupProfile/group_member/tui_add_group_member.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitGroupProfile/group_member/tui_delete_group_member.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitGroupProfile/group_member/tui_delete_group_member.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitGroupProfile/group_member/tui_group_member_list.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/views/TIMUIKitGroupProfile/group_member/tui_group_member_list.dart';
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/avatar.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/avatar.dart';
|
||||||
|
|
||||||
import 'package:tencent_cloud_chat_uikit/base_widgets/tim_ui_kit_base.dart';
|
|
||||||
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';
|
||||||
import 'package:tencent_im_base/tencent_im_base.dart';
|
import 'package:tencent_im_base/tencent_im_base.dart';
|
||||||
|
|
||||||
|
|
@ -38,8 +36,7 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
return friendRemark != "" ? friendRemark : showName;
|
return friendRemark != "" ? friendRemark : showName;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _groupMemberListBuilder(List memberList, TUITheme theme,
|
List<Widget> _groupMemberListBuilder(List memberList, TUITheme theme, TUIGroupProfileModel model, int showRange) {
|
||||||
TUIGroupProfileModel model, int showRange) {
|
|
||||||
final isDesktopScreen = TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
|
final isDesktopScreen = TUIKitScreenUtils.getFormFactor() == DeviceType.Desktop;
|
||||||
return _getMemberList(memberList, showRange).map((element) {
|
return _getMemberList(memberList, showRange).map((element) {
|
||||||
final faceUrl = element?.faceUrl ?? "";
|
final faceUrl = element?.faceUrl ?? "";
|
||||||
|
|
@ -74,10 +71,7 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
showName,
|
showName,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(overflow: TextOverflow.ellipsis, color: theme.weakTextColor, fontSize: 10),
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
color: theme.weakTextColor,
|
|
||||||
fontSize: 10),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -86,21 +80,17 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _inviteMemberBuilder(bool isCanInviteMember,
|
List<Widget> _inviteMemberBuilder(bool isCanInviteMember, bool isCanKickOffMember, theme, BuildContext context) {
|
||||||
bool isCanKickOffMember, theme, BuildContext context) {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
void navigateToMemberList(BuildContext context, TUIGroupProfileModel model,
|
void navigateToMemberList(BuildContext context, TUIGroupProfileModel model, List<V2TimGroupMemberFullInfo?> memberList) {
|
||||||
List<V2TimGroupMemberFullInfo?> memberList) {
|
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||||
final isDesktopScreen =
|
|
||||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
|
||||||
if (!isDesktopScreen) {
|
if (!isDesktopScreen) {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => GroupProfileMemberListPage(
|
builder: (context) => GroupProfileMemberListPage(model: model, memberList: memberList),
|
||||||
model: model, memberList: memberList),
|
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
final option1 = memberList.length.toString();
|
final option1 = memberList.length.toString();
|
||||||
|
|
@ -109,18 +99,15 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
context: context,
|
context: context,
|
||||||
width: MediaQuery.of(context).size.width * 0.5,
|
width: MediaQuery.of(context).size.width * 0.5,
|
||||||
height: MediaQuery.of(context).size.height * 0.8,
|
height: MediaQuery.of(context).size.height * 0.8,
|
||||||
title: TIM_t_para("群成员({{option1}}人)", "群成员($option1人)")(
|
title: TIM_t_para("群成员({{option1}}人)", "群成员($option1人)")(option1: option1),
|
||||||
option1: option1),
|
child: (onClose) => GroupProfileMemberListPage(model: model, memberList: memberList));
|
||||||
child: (onClose) =>
|
|
||||||
GroupProfileMemberListPage(model: model, memberList: memberList));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 isDesktopScreen =
|
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
||||||
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
|
|
||||||
final model = Provider.of<TUIGroupProfileModel>(context);
|
final model = Provider.of<TUIGroupProfileModel>(context);
|
||||||
final memberAmount = model.groupInfo?.memberCount ?? 0;
|
final memberAmount = model.groupInfo?.memberCount ?? 0;
|
||||||
final option1 = memberAmount.toString();
|
final option1 = memberAmount.toString();
|
||||||
|
|
@ -144,13 +131,7 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.only(bottom: 12),
|
padding: const EdgeInsets.only(bottom: 12),
|
||||||
decoration: isDesktopScreen
|
decoration: isDesktopScreen ? null : BoxDecoration(border: Border(bottom: BorderSide(color: theme.weakDividerColor ?? CommonColor.weakDividerColor))),
|
||||||
? null
|
|
||||||
: BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
bottom: BorderSide(
|
|
||||||
color: theme.weakDividerColor ??
|
|
||||||
CommonColor.weakDividerColor))),
|
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
navigateToMemberList(context, model, memberList);
|
navigateToMemberList(context, model, memberList);
|
||||||
|
|
@ -158,18 +139,12 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(TIM_t("群成员"),
|
Text(TIM_t("群成员"), style: TextStyle(color: theme.darkTextColor, fontSize: isDesktopScreen ? 14 : 16)),
|
||||||
style: TextStyle(
|
|
||||||
color: theme.darkTextColor,
|
|
||||||
fontSize: isDesktopScreen ? 14 : 16)),
|
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
TIM_t_para("{{option1}}人", "$option1人")(
|
TIM_t_para("{{option1}}人", "$option1人")(option1: option1),
|
||||||
option1: option1),
|
style: TextStyle(color: theme.darkTextColor, fontSize: isDesktopScreen ? 14 : 16),
|
||||||
style: TextStyle(
|
|
||||||
color: theme.darkTextColor,
|
|
||||||
fontSize: isDesktopScreen ? 14 : 16),
|
|
||||||
),
|
),
|
||||||
Icon(
|
Icon(
|
||||||
Icons.keyboard_arrow_right,
|
Icons.keyboard_arrow_right,
|
||||||
|
|
@ -188,15 +163,11 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(width: 1, color: theme.weakDividerColor ?? CommonColor.weakDividerColor),
|
||||||
width: 1,
|
|
||||||
color: theme.weakDividerColor ??
|
|
||||||
CommonColor.weakDividerColor),
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
||||||
),
|
),
|
||||||
// height: 30,
|
// height: 30,
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -247,6 +218,7 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
},
|
},
|
||||||
child: (onClose) => AddGroupMemberPage(
|
child: (onClose) => AddGroupMemberPage(
|
||||||
model: model,
|
model: model,
|
||||||
|
onClose: onClose,
|
||||||
key: addGroupMemberKey,
|
key: addGroupMemberKey,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -285,11 +257,11 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
title: TIM_t("删除群成员"),
|
title: TIM_t("删除群成员"),
|
||||||
height: 460,
|
height: 460,
|
||||||
onSubmit: () {
|
onSubmit: () {
|
||||||
deleteGroupMemberKey.currentState
|
deleteGroupMemberKey.currentState?.submitDelete();
|
||||||
?.submitDelete();
|
|
||||||
},
|
},
|
||||||
child: (onClose) => DeleteGroupMemberPage(
|
child: (onClose) => DeleteGroupMemberPage(
|
||||||
model: model,
|
model: model,
|
||||||
|
onClose: onClose,
|
||||||
key: deleteGroupMemberKey,
|
key: deleteGroupMemberKey,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -297,8 +269,7 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => DeleteGroupMemberPage(model: model),
|
||||||
DeleteGroupMemberPage(model: model),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -319,9 +290,7 @@ class GroupMemberTile extends TIMUIKitStatelessWidget {
|
||||||
margin: EdgeInsets.only(top: isDesktopScreen ? 12 : 16),
|
margin: EdgeInsets.only(top: isDesktopScreen ? 12 : 16),
|
||||||
child: Text(
|
child: Text(
|
||||||
TIM_t("查看更多群成员"),
|
TIM_t("查看更多群成员"),
|
||||||
style: TextStyle(
|
style: TextStyle(color: theme.weakTextColor, fontSize: isDesktopScreen ? 12 : 14),
|
||||||
color: theme.weakTextColor,
|
|
||||||
fontSize: isDesktopScreen ? 12 : 14),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,13 @@ class KeepAliveWrapper extends StatefulWidget {
|
||||||
_KeepAliveWrapperState createState() => _KeepAliveWrapperState();
|
_KeepAliveWrapperState createState() => _KeepAliveWrapperState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
|
class _KeepAliveWrapperState extends State<KeepAliveWrapper> with AutomaticKeepAliveClientMixin {
|
||||||
with AutomaticKeepAliveClientMixin {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
return widget.child;
|
return RepaintBoundary(
|
||||||
|
child: widget.child,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -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.3.1
|
version: 2.3.2
|
||||||
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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue