样式修改

This commit is contained in:
Zeew 2025-08-13 15:55:41 +08:00
parent bfd865fdc9
commit 638dae9584
3 changed files with 149 additions and 84 deletions

View File

@ -30,9 +30,12 @@ import 'package:tencent_cloud_chat_uikit/base_widgets/tim_callback.dart';
import 'package:tencent_cloud_chat_uikit/theme/color.dart'; import 'package:tencent_cloud_chat_uikit/theme/color.dart';
import 'package:tencent_cloud_chat_uikit/theme/tui_theme_view_model.dart'; import 'package:tencent_cloud_chat_uikit/theme/tui_theme_view_model.dart';
typedef ConversationItemBuilder = Widget Function(V2TimConversation conversationItem, [V2TimUserStatus? onlineStatus]); typedef ConversationItemBuilder = Widget Function(
V2TimConversation conversationItem,
[V2TimUserStatus? onlineStatus]);
typedef ConversationItemSlideBuilder = List<ConversationItemSlidePanel> Function(V2TimConversation conversationItem); typedef ConversationItemSlideBuilder = List<ConversationItemSlidePanel>
Function(V2TimConversation conversationItem);
typedef ConversationItemSecondaryMenuBuilder = Widget Function( typedef ConversationItemSecondaryMenuBuilder = Widget Function(
V2TimConversation conversationItem, VoidCallback onClose); V2TimConversation conversationItem, VoidCallback onClose);
@ -149,11 +152,14 @@ class ConversationItemSlidePanel extends TIMUIKitStatelessWidget {
} }
class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> { class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
final TUIConversationViewModel model = serviceLocator<TUIConversationViewModel>(); final TUIConversationViewModel model =
serviceLocator<TUIConversationViewModel>();
late TIMUIKitConversationController _timuiKitConversationController; late TIMUIKitConversationController _timuiKitConversationController;
final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>(); final TUIThemeViewModel themeViewModel = serviceLocator<TUIThemeViewModel>();
final TUIFriendShipViewModel friendShipViewModel = serviceLocator<TUIFriendShipViewModel>(); final TUIFriendShipViewModel friendShipViewModel =
final TUIGroupListenerModel groupListenerModel = serviceLocator<TUIGroupListenerModel>(); serviceLocator<TUIFriendShipViewModel>();
final TUIGroupListenerModel groupListenerModel =
serviceLocator<TUIGroupListenerModel>();
late AutoScrollController _autoScrollController; late AutoScrollController _autoScrollController;
@override @override
@ -177,23 +183,30 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
} }
_clearHistory(V2TimConversation conversationItem) { _clearHistory(V2TimConversation conversationItem) {
_timuiKitConversationController.clearHistoryMessage(conversation: conversationItem); _timuiKitConversationController.clearHistoryMessage(
conversation: conversationItem);
} }
_pinConversation(V2TimConversation conversation) { _pinConversation(V2TimConversation conversation) {
_timuiKitConversationController.pinConversation( _timuiKitConversationController.pinConversation(
conversationID: conversation.conversationID, isPinned: !conversation.isPinned!); conversationID: conversation.conversationID,
isPinned: !conversation.isPinned!);
} }
_deleteConversation(V2TimConversation conversation) { _deleteConversation(V2TimConversation conversation) {
_timuiKitConversationController.deleteConversation(conversationID: conversation.conversationID); _timuiKitConversationController.deleteConversation(
conversationID: conversation.conversationID);
} }
List<V2TimConversation?> getFilteredConversation() { List<V2TimConversation?> getFilteredConversation() {
List<V2TimConversation?> filteredConversationList = List<V2TimConversation?> filteredConversationList = model.conversationList
model.conversationList.where((element) => (element?.groupID != null || element?.userID != null)).toList(); .where(
(element) => (element?.groupID != null || element?.userID != null))
.toList();
if (widget.conversationCollector != null) { if (widget.conversationCollector != null) {
filteredConversationList = filteredConversationList.where(widget.conversationCollector!).toList(); filteredConversationList = filteredConversationList
.where(widget.conversationCollector!)
.toList();
} }
return filteredConversationList; return filteredConversationList;
} }
@ -219,7 +232,8 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
} }
} }
Widget _defaultSecondaryMenu(V2TimConversation conversationItem, VoidCallback onClose) { Widget _defaultSecondaryMenu(
V2TimConversation conversationItem, VoidCallback onClose) {
return TUIKitColumnMenu(data: [ return TUIKitColumnMenu(data: [
if (!PlatformUtils().isWeb) if (!PlatformUtils().isWeb)
ColumnMenuItem( ColumnMenuItem(
@ -231,7 +245,11 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
}), }),
ColumnMenuItem( ColumnMenuItem(
label: conversationItem.isPinned! ? TIM_t("取消置顶") : TIM_t("置顶"), label: conversationItem.isPinned! ? TIM_t("取消置顶") : TIM_t("置顶"),
icon: Icon(conversationItem.isPinned! ? Icons.vertical_align_bottom : Icons.vertical_align_top, size: 16), icon: Icon(
conversationItem.isPinned!
? Icons.vertical_align_bottom
: Icons.vertical_align_top,
size: 16),
onClick: () { onClick: () {
onClose(); onClose();
_pinConversation(conversationItem); _pinConversation(conversationItem);
@ -256,7 +274,8 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
onPressed: (context) { onPressed: (context) {
_clearHistory(conversationItem); _clearHistory(conversationItem);
}, },
backgroundColor: theme.conversationItemSliderClearBgColor ?? CommonColor.primaryColor, backgroundColor: theme.conversationItemSliderClearBgColor ??
const Color(0xFF0F7FFF),
foregroundColor: theme.conversationItemSliderTextColor, foregroundColor: theme.conversationItemSliderTextColor,
label: TIM_t("清除"), label: TIM_t("清除"),
spacing: 0, spacing: 0,
@ -266,7 +285,8 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
onPressed: (context) { onPressed: (context) {
_pinConversation(conversationItem); _pinConversation(conversationItem);
}, },
backgroundColor: theme.conversationItemSliderPinBgColor ?? CommonColor.infoColor, backgroundColor:
theme.conversationItemSliderPinBgColor ?? CommonColor.infoColor,
foregroundColor: theme.conversationItemSliderTextColor, foregroundColor: theme.conversationItemSliderTextColor,
label: conversationItem.isPinned! ? TIM_t("取消置顶") : TIM_t("置顶"), label: conversationItem.isPinned! ? TIM_t("取消置顶") : TIM_t("置顶"),
), ),
@ -274,14 +294,16 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
onPressed: (context) { onPressed: (context) {
_deleteConversation(conversationItem); _deleteConversation(conversationItem);
}, },
backgroundColor: theme.conversationItemSliderDeleteBgColor ?? Colors.red, backgroundColor:
theme.conversationItemSliderDeleteBgColor ?? Colors.red,
foregroundColor: theme.conversationItemSliderTextColor, foregroundColor: theme.conversationItemSliderTextColor,
label: TIM_t("删除"), label: TIM_t("删除"),
) )
]; ];
} }
Widget _getSecondaryMenu(V2TimConversation conversation, VoidCallback onClose) { Widget _getSecondaryMenu(
V2TimConversation conversation, VoidCallback onClose) {
if (widget.itemSecondaryMenuBuilder != null) { if (widget.itemSecondaryMenuBuilder != null) {
return widget.itemSecondaryMenuBuilder!(conversation, onClose); return widget.itemSecondaryMenuBuilder!(conversation, onClose);
} }
@ -300,7 +322,8 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
@override @override
Widget tuiBuild(BuildContext context, TUIKitBuildValue value) { Widget tuiBuild(BuildContext context, TUIKitBuildValue value) {
final theme = value.theme; final theme = value.theme;
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider.value(value: model), ChangeNotifierProvider.value(value: model),
@ -310,10 +333,12 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
builder: (BuildContext context, Widget? w) { builder: (BuildContext context, Widget? w) {
final _model = Provider.of<TUIConversationViewModel>(context); final _model = Provider.of<TUIConversationViewModel>(context);
bool haveMoreData = _model.haveMoreData; bool haveMoreData = _model.haveMoreData;
final _friendShipViewModel = Provider.of<TUIFriendShipViewModel>(context); final _friendShipViewModel =
Provider.of<TUIFriendShipViewModel>(context);
_model.lifeCycle = widget.lifeCycle; _model.lifeCycle = widget.lifeCycle;
final TUIGroupListenerModel groupListenerModel = Provider.of<TUIGroupListenerModel>(context, listen: true); final TUIGroupListenerModel groupListenerModel =
Provider.of<TUIGroupListenerModel>(context, listen: true);
final NeedUpdate? needUpdate = groupListenerModel.needUpdate; final NeedUpdate? needUpdate = groupListenerModel.needUpdate;
if (needUpdate != null) { if (needUpdate != null) {
groupListenerModel.needUpdate = null; groupListenerModel.needUpdate = null;
@ -325,12 +350,14 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
} else if (needUpdate.updateType == UpdateType.kickedFromGroup) { } else if (needUpdate.updateType == UpdateType.kickedFromGroup) {
onTIMCallback(TIMCallback( onTIMCallback(TIMCallback(
type: TIMCallbackType.INFO, type: TIMCallbackType.INFO,
infoRecommendText: "${TIM_t("您已被踢出")}${needUpdate!.extraData}", infoRecommendText:
"${TIM_t("您已被踢出")}${needUpdate!.extraData}",
infoCode: 6661402)); infoCode: 6661402));
} }
} }
List<V2TimConversation?> filteredConversationList = getFilteredConversation(); List<V2TimConversation?> filteredConversationList =
getFilteredConversation();
if (TencentUtils.checkString(_model.scrollToConversation) != null) { if (TencentUtils.checkString(_model.scrollToConversation) != null) {
_onScrollToConversation(_model.scrollToConversation!); _onScrollToConversation(_model.scrollToConversation!);
@ -352,17 +379,21 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
final conversationItem = filteredConversationList[index]; final conversationItem = filteredConversationList[index];
final V2TimUserStatus? onlineStatus = _friendShipViewModel.userStatusList.firstWhere( final V2TimUserStatus? onlineStatus =
_friendShipViewModel.userStatusList.firstWhere(
(item) => item.userID == conversationItem?.userID, (item) => item.userID == conversationItem?.userID,
orElse: () => V2TimUserStatus(statusType: 0)); orElse: () => V2TimUserStatus(statusType: 0));
if (widget.itemBuilder != null) { if (widget.itemBuilder != null) {
return widget.itemBuilder!(conversationItem!, onlineStatus); return widget.itemBuilder!(
conversationItem!, onlineStatus);
} }
final slideChildren = _getSlideBuilder()(conversationItem!); final slideChildren =
_getSlideBuilder()(conversationItem!);
final isCurrent = conversationItem.conversationID == model.selectedConversation?.conversationID; final isCurrent = conversationItem.conversationID ==
model.selectedConversation?.conversationID;
final isPined = conversationItem.isPinned ?? false; final isPined = conversationItem.isPinned ?? false;
@ -380,10 +411,13 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
faceUrl: conversationItem.faceUrl ?? "", faceUrl: conversationItem.faceUrl ?? "",
nickName: conversationItem.showName ?? "", nickName: conversationItem.showName ?? "",
isDisturb: isDisturb:
(conversationItem.groupType == "Meeting" ? false : conversationItem.recvOpt != 0), (conversationItem.groupType == "Meeting"
? false
: conversationItem.recvOpt != 0),
lastMsg: conversationItem.lastMessage, lastMsg: conversationItem.lastMessage,
isPined: isPined, isPined: isPined,
groupAtInfoList: conversationItem.groupAtInfoList ?? [], groupAtInfoList:
conversationItem.groupAtInfoList ?? [],
unreadCount: conversationItem.unreadCount ?? 0, unreadCount: conversationItem.unreadCount ?? 0,
draftText: conversationItem.draftText, draftText: conversationItem.draftText,
onlineStatus: (widget.isShowOnlineStatus && onlineStatus: (widget.isShowOnlineStatus &&
@ -407,14 +441,23 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
child: InkWell( child: InkWell(
onSecondaryTapDown: (details) { onSecondaryTapDown: (details) {
TUIKitWidePopup.showPopupWindow( TUIKitWidePopup.showPopupWindow(
operationKey: TUIKitWideModalOperationKey.conversationSecondaryMenu, operationKey: TUIKitWideModalOperationKey
.conversationSecondaryMenu,
isDarkBackground: false, isDarkBackground: false,
borderRadius: const BorderRadius.all(Radius.circular(4)), borderRadius: const BorderRadius.all(
Radius.circular(4)),
context: context, context: context,
offset: Offset( offset: Offset(
min(details.globalPosition.dx, MediaQuery.of(context).size.width - 80), min(
min(details.globalPosition.dy, MediaQuery.of(context).size.height - 130)), details.globalPosition.dx,
child: (onClose) => _getSecondaryMenu(conversationItem, onClose)); MediaQuery.of(context).size.width -
80),
min(
details.globalPosition.dy,
MediaQuery.of(context).size.height -
130)),
child: (onClose) => _getSecondaryMenu(
conversationItem, onClose));
}, },
child: conversationLineItem(), child: conversationLineItem(),
), ),
@ -427,17 +470,22 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
groupTag: 'conversation-list', groupTag: 'conversation-list',
child: conversationLineItem(), child: conversationLineItem(),
endActionPane: ActionPane( endActionPane: ActionPane(
extentRatio: slideChildren.length > 2 ? 0.77 : 0.5, extentRatio:
slideChildren.length > 2 ? 0.77 : 0.5,
motion: const DrawerMotion(), motion: const DrawerMotion(),
children: slideChildren)), children: slideChildren)),
)); ));
}) })
: (widget.emptyBuilder != null ? widget.emptyBuilder!() : Container()); : (widget.emptyBuilder != null
? widget.emptyBuilder!()
: Container());
} }
return TUIKitScreenUtils.getDeviceWidget( return TUIKitScreenUtils.getDeviceWidget(
context: context, context: context,
defaultWidget: SlidableAutoCloseBehavior( defaultWidget: Container(
color: Colors.white,
child: SlidableAutoCloseBehavior(
child: EasyRefresh( child: EasyRefresh(
header: CustomizeBallPulseHeader(color: theme.primaryColor), header: CustomizeBallPulseHeader(color: theme.primaryColor),
onRefresh: () async { onRefresh: () async {
@ -446,7 +494,13 @@ class _TIMUIKitConversationState extends TIMUIKitState<TIMUIKitConversation> {
child: conversationList(), child: conversationList(),
), ),
), ),
desktopWidget: Scrollbar(controller: _autoScrollController, child: conversationList())); ),
desktopWidget: Container(
color: Colors.white,
child: Scrollbar(
controller: _autoScrollController,
child: conversationList()),
));
}); });
} }
} }

View File

@ -18,7 +18,8 @@ import 'package:tencent_cloud_chat_uikit/theme/color.dart';
import 'package:tencent_cloud_chat_uikit/theme/tui_theme.dart'; import 'package:tencent_cloud_chat_uikit/theme/tui_theme.dart';
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart'; import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';
typedef LastMessageBuilder = Widget? Function(V2TimMessage? lastMsg, List<V2TimGroupAtInfo?> groupAtInfoList); typedef LastMessageBuilder = Widget? Function(
V2TimMessage? lastMsg, List<V2TimGroupAtInfo?> groupAtInfoList);
class TIMUIKitConversationItem extends TIMUIKitStatelessWidget { class TIMUIKitConversationItem extends TIMUIKitStatelessWidget {
final String faceUrl; final String faceUrl;
@ -53,15 +54,17 @@ class TIMUIKitConversationItem extends TIMUIKitStatelessWidget {
}) : super(key: key); }) : super(key: key);
Widget _getShowMsgWidget(BuildContext context) { Widget _getShowMsgWidget(BuildContext context) {
final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
final isAndroid = PlatformUtils().isAndroid; final isAndroid = PlatformUtils().isAndroid;
// //
final msgFontSize = isDesktopScreen final msgFontSize =
? 12.0 isDesktopScreen ? 12.0 : (isAndroid ? 13.0 : 14.0); // 使
: (isAndroid ? 13.0 : 14.0); // 使
if (lastMsg != null && lastMessageBuilder != null && lastMessageBuilder!(lastMsg, groupAtInfoList) != null) { if (lastMsg != null &&
lastMessageBuilder != null &&
lastMessageBuilder!(lastMsg, groupAtInfoList) != null) {
return lastMessageBuilder!(lastMsg, groupAtInfoList)!; return lastMessageBuilder!(lastMsg, groupAtInfoList)!;
} }
@ -91,13 +94,14 @@ class TIMUIKitConversationItem extends TIMUIKitStatelessWidget {
if (draftTimestamp != null && draftTimestamp != 0) { if (draftTimestamp != null && draftTimestamp != 0) {
return Text(TimeAgo().getTimeStringForChat(draftTimestamp as int) ?? "", return Text(TimeAgo().getTimeStringForChat(draftTimestamp as int) ?? "",
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 14,
color: theme.conversationItemTitmeTextColor, color: theme.conversationItemTitmeTextColor,
)); ));
} else if (lastMsg != null) { } else if (lastMsg != null) {
return Text(TimeAgo().getTimeStringForChat(lastMsg!.timestamp as int) ?? "", return Text(
TimeAgo().getTimeStringForChat(lastMsg!.timestamp as int) ?? "",
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 13,
color: theme.conversationItemTitmeTextColor, color: theme.conversationItemTitmeTextColor,
)); ));
} }
@ -109,24 +113,25 @@ class TIMUIKitConversationItem extends TIMUIKitStatelessWidget {
@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 = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop; final isDesktopScreen =
TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
final isAndroid = PlatformUtils().isAndroid; final isAndroid = PlatformUtils().isAndroid;
// //
final titleFontSize = isDesktopScreen final titleFontSize =
? 14.0 isDesktopScreen ? 12.0 : (isAndroid ? 14.0 : 15.0); // 使
: (isAndroid ? 16.0 : 18.0); // 使
return Container( return Container(
padding: const EdgeInsets.only(top: 6, bottom: 6, left: 16, right: 16), padding: const EdgeInsets.only(top: 6, bottom: 6, left: 16, right: 16),
decoration: BoxDecoration( // decoration: BoxDecoration(
border: Border( // border: Border(
bottom: BorderSide( // bottom: BorderSide(
color: theme.conversationItemBorderColor ?? CommonColor.weakDividerColor, // color: theme.conversationItemBorderColor ?? Color(0xFFF0F0F0),
width: 1, // width: 0.5,
), // ),
), // ),
), // ),
decoration: BoxDecoration(),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
@ -139,7 +144,11 @@ class TIMUIKitConversationItem extends TIMUIKitStatelessWidget {
fit: StackFit.expand, fit: StackFit.expand,
clipBehavior: Clip.none, clipBehavior: Clip.none,
children: [ children: [
Avatar(onlineStatus: onlineStatus, faceUrl: faceUrl, showName: nickName, type: convType), Avatar(
onlineStatus: onlineStatus,
faceUrl: faceUrl,
showName: nickName,
type: convType),
if (unreadCount != 0) if (unreadCount != 0)
Positioned( Positioned(
top: isDisturb ? -2.5 : -4.5, top: isDisturb ? -2.5 : -4.5,
@ -214,7 +223,8 @@ class TIMUIKitConversationItem extends TIMUIKitStatelessWidget {
height: 18, height: 18,
child: Icon( child: Icon(
Icons.notifications_off, Icons.notifications_off,
color: theme.conversationItemNoNotificationIconColor, color:
theme.conversationItemNoNotificationIconColor,
size: isDesktopScreen ? 14 : 16.0, size: isDesktopScreen ? 14 : 16.0,
), ),
), ),

View File

@ -72,6 +72,7 @@ class Avatar extends TIMUIKitStatelessWidget {
return CachedNetworkImage( return CachedNetworkImage(
imageUrl: faceUrl, imageUrl: faceUrl,
fadeInDuration: const Duration(milliseconds: 0), fadeInDuration: const Duration(milliseconds: 0),
fit: BoxFit.cover,
errorWidget: (BuildContext context, String c, dynamic s) { errorWidget: (BuildContext context, String c, dynamic s) {
return defaultAvatar(); return defaultAvatar();
}, },