diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index c526616390..7682b26924 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -103,11 +103,15 @@ class ChatEventList extends StatelessWidget { } // The message at this index: - final event = controller.timeline!.events[i - 1]; - + final currentEventIndex = i - 1; + final event = controller.timeline!.events[currentEventIndex]; + final previousEvent = currentEventIndex > 0 ? controller.timeline!.events[currentEventIndex - 1] : null; + final nextEvent = i < controller.timeline!.events.length + ? controller.timeline!.events[currentEventIndex + 1] + : null; return AutoScrollTag( key: ValueKey(event.eventId), - index: i - 1, + index: currentEventIndex, controller: controller.scrollController, child: event.isVisibleInGui ? Message( @@ -131,9 +135,8 @@ class ChatEventList extends StatelessWidget { selected: controller.selectedEvents .any((e) => e.eventId == event.eventId), timeline: controller.timeline!, - nextEvent: i < controller.timeline!.events.length - ? controller.timeline!.events[i] - : null, + previousEvent: previousEvent, + nextEvent: nextEvent, controller: controller, ) : Container(), diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index bf7da1d091..c63fe6e7f5 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -21,6 +21,7 @@ import 'verification_request_content.dart'; class Message extends StatelessWidget { final Event event; + final Event? previousEvent; final Event? nextEvent; final void Function(Event)? onSelect; final void Function(Event)? onAvatarTab; @@ -34,6 +35,7 @@ class Message extends StatelessWidget { const Message( this.event, { + this.previousEvent, this.nextEvent, this.longPressSelect = false, this.onSelect, @@ -78,14 +80,6 @@ class Message extends StatelessWidget { final displayTime = event.type == EventTypes.RoomCreate || nextEvent == null || !event.originServerTs.sameEnvironment(nextEvent!.originServerTs); - final sameSender = nextEvent != null && - [ - EventTypes.Message, - EventTypes.Sticker, - EventTypes.Encrypted, - ].contains(nextEvent!.type) - ? nextEvent!.senderId == event.senderId && !displayTime - : false; final textColor = Theme.of(context).colorScheme.onBackground; final rowMainAxisAlignment = ownMessage ? MainAxisAlignment.end : MainAxisAlignment.start; @@ -107,7 +101,7 @@ class Message extends StatelessWidget { }.contains(event.messageType); final rowChildren = [ - _placeHolderWidget(sameSender, ownMessage, event), + _placeHolderWidget(isSameSender(previousEvent, event), ownMessage, event), Expanded( child: Row( mainAxisSize: MainAxisSize.min, @@ -448,25 +442,11 @@ class Message extends StatelessWidget { } Widget _placeHolderWidget(bool sameSender, bool ownMessage, Event event) { - if (controller.selectMode) { + if (controller.selectMode || event.room.isDirectChat) { return const SizedBox(); - } else if (sameSender || ownMessage) { - return SizedBox( - width: MessageStyle.avatarSize, - child: Padding( - padding: const EdgeInsets.only(top: 4.0), - child: Center( - child: SizedBox( - width: MessageStyle.errorStatusPlaceHolderWidth, - height: MessageStyle.errorStatusPlaceHolderHeight, - child: event.status == EventStatus.error - ? const Icon(Icons.error, color: Colors.red) - : null, - ), - ), - ), - ); - } else { + } + + if (sameSender && !ownMessage) { return FutureBuilder( future: event.fetchSenderUser(), builder: (context, snapshot) { @@ -481,6 +461,22 @@ class Message extends StatelessWidget { }, ); } + + return SizedBox( + width: MessageStyle.avatarSize, + child: Padding( + padding: const EdgeInsets.only(top: 4.0), + child: Center( + child: SizedBox( + width: MessageStyle.errorStatusPlaceHolderWidth, + height: MessageStyle.errorStatusPlaceHolderHeight, + child: event.status == EventStatus.error + ? const Icon(Icons.error, color: Colors.red) + : null, + ), + ), + ), + ); } Widget _messageSelectedWidget(BuildContext context, Widget child) { @@ -516,6 +512,28 @@ class Message extends StatelessWidget { ), ); } + + // Check if the sender of the current event is the same as the previous event. + bool isSameSender(Event? previousEvent, Event currentEvent) { + // If the previous event is null, it is assumed that the message is the newest. + if (previousEvent == null) { + return true; + } + + final isPreviousEventMessage = { + EventTypes.Message, + EventTypes.Sticker, + EventTypes.Encrypted, + EventTypes.Redaction, + }.contains(previousEvent.type); + + // Ignoring events that are not messages, stickers, encrypted or redaction. + if (!isPreviousEventMessage) { + return true; + } + + return previousEvent.senderId != currentEvent.senderId; + } } class ReplyIconWidget extends StatelessWidget { diff --git a/lib/pages/chat/events/message/message_style.dart b/lib/pages/chat/events/message/message_style.dart index 43e73244c3..fcd418f3bb 100644 --- a/lib/pages/chat/events/message/message_style.dart +++ b/lib/pages/chat/events/message/message_style.dart @@ -5,7 +5,7 @@ class MessageStyle { static final bubbleBorderRadius = BorderRadius.circular(20); static final errorStatusPlaceHolderWidth = 16 * AppConfig.bubbleSizeFactor; static final errorStatusPlaceHolderHeight = 16 * AppConfig.bubbleSizeFactor; - static const double avatarSize = 36; + static const double avatarSize = 40; static const double fontSize = 15; static const notSameSenderPadding = EdgeInsets.only(left: 8.0, bottom: 4);