From 432705c570c61d63854cde3aaa11b1c3446669d0 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 17 Nov 2024 22:42:09 +0800 Subject: [PATCH] :lipstick: Mergeable chat messages --- lib/screens/chat/room.dart | 31 +++++++++++++++++-- lib/widgets/chat/chat_message.dart | 49 ++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/lib/screens/chat/room.dart b/lib/screens/chat/room.dart index 4218377..1326d73 100644 --- a/lib/screens/chat/room.dart +++ b/lib/screens/chat/room.dart @@ -76,9 +76,10 @@ class _ChatRoomScreenState extends State { Expanded( child: InfiniteList( reverse: true, - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 12, + padding: const EdgeInsets.only( + left: 12, + right: 12, + top: 12, ), hasReachedMax: _messageController.isAllLoaded, itemCount: _messageController.messages.length, @@ -88,8 +89,32 @@ class _ChatRoomScreenState extends State { }, itemBuilder: (context, idx) { final message = _messageController.messages[idx]; + final nextMessage = + idx < _messageController.messages.length - 1 + ? _messageController.messages[idx + 1] + : null; + final previousMessage = + idx > 0 ? _messageController.messages[idx - 1] : null; + + final canMerge = nextMessage != null && + nextMessage.senderId == message.senderId && + message.createdAt + .difference(nextMessage.createdAt) + .inMinutes + .abs() <= + 3; + final canMergePrevious = previousMessage != null && + previousMessage.senderId == message.senderId && + message.createdAt + .difference(previousMessage.createdAt) + .inMinutes + .abs() <= + 3; + return ChatMessage( data: message, + isMerged: canMerge, + hasMerged: canMergePrevious, isPending: _messageController.unconfirmedMessages .contains(message.uuid), ); diff --git a/lib/widgets/chat/chat_message.dart b/lib/widgets/chat/chat_message.dart index 148d270..ef55c08 100644 --- a/lib/widgets/chat/chat_message.dart +++ b/lib/widgets/chat/chat_message.dart @@ -1,3 +1,4 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:provider/provider.dart'; @@ -9,32 +10,60 @@ import 'package:surface/widgets/markdown_content.dart'; class ChatMessage extends StatelessWidget { final SnChatMessage data; + final bool isMerged; + final bool hasMerged; final bool isPending; - const ChatMessage({super.key, required this.data, this.isPending = false}); + const ChatMessage({ + super.key, + required this.data, + this.isMerged = false, + this.hasMerged = false, + this.isPending = false, + }); @override Widget build(BuildContext context) { final ud = context.read(); final user = ud.getAccountFromCache(data.sender.accountId); + final dateFormatter = DateFormat('MM/dd HH:mm'); + return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - AccountImage( - content: user?.avatar, - ), + if (!isMerged) + AccountImage( + content: user?.avatar, + ) + else + const Gap(40), const Gap(8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - (data.sender.nick?.isNotEmpty ?? false) - ? data.sender.nick! - : user!.nick, - ).bold(), + if (!isMerged) + Row( + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + children: [ + Text( + (data.sender.nick?.isNotEmpty ?? false) + ? data.sender.nick! + : user!.nick, + ).bold(), + const Gap(6), + Text( + dateFormatter.format(data.createdAt.toLocal()), + ).fontSize(13), + ], + ), if (data.body['text'] != null) - MarkdownTextContent(content: data.body['text']), + MarkdownTextContent( + content: data.body['text'], + isAutoWarp: true, + ), + if (!hasMerged) const Gap(8), ], ), )