From 87568235d560b5ca2ef127df2a8c522548d98228 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 25 Jun 2021 10:22:49 +0200 Subject: [PATCH 1/8] add copyWith to Messagewidget --- .../lib/src/message_widget.dart | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index a976547f..cc0f0d3c 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -397,6 +397,117 @@ class MessageWidget extends StatefulWidget { /// Customize onTap on attachment final void Function(Message message, Attachment attachment)? onAttachmentTap; + /// Creates a copy of [MessageWidget] with specified attributes overridden. + MessageWidget copyWith({ + Key? key, + void Function(User)? onMentionTap, + void Function(Message)? onThreadTap, + void Function(Message)? onReplyTap, + Widget Function(BuildContext, Message)? editMessageInputBuilder, + Widget Function(BuildContext, Message)? textBuilder, + Widget Function(BuildContext, Message)? usernameBuilder, + void Function(BuildContext, Message)? onMessageActions, + Message? message, + MessageTheme? messageTheme, + bool? reverse, + ShapeBorder? shape, + ShapeBorder? attachmentShape, + BorderSide? borderSide, + BorderSide? attachmentBorderSide, + BorderRadiusGeometry? borderRadiusGeometry, + BorderRadiusGeometry? attachmentBorderRadiusGeometry, + EdgeInsetsGeometry? padding, + EdgeInsets? textPadding, + EdgeInsetsGeometry? attachmentPadding, + DisplayWidget? showUserAvatar, + bool? showSendingIndicator, + bool? showReactions, + bool? allRead, + bool? showThreadReplyIndicator, + bool? showInChannelIndicator, + void Function(User)? onUserAvatarTap, + void Function(String)? onLinkTap, + bool? showReactionPickerIndicator, + List? readList, + ShowMessageCallback? onShowMessage, + ValueChanged? onReturnAction, + bool? showUsername, + bool? showTimestamp, + bool? showReplyMessage, + bool? showThreadReplyMessage, + bool? showEditMessage, + bool? showCopyMessage, + bool? showDeleteMessage, + bool? showResendMessage, + bool? showFlagButton, + bool? showPinButton, + bool? showPinHighlight, + Map? customAttachmentBuilders, + bool? translateUserAvatar, + OnQuotedMessageTap? onQuotedMessageTap, + void Function(Message)? onMessageTap, + List? customActions, + void Function(Message message, Attachment attachment)? onAttachmentTap, + }) => + MessageWidget( + key: key ?? this.key, + onMentionTap: onMentionTap ?? this.onMentionTap, + onThreadTap: onThreadTap ?? this.onThreadTap, + onReplyTap: onReplyTap ?? this.onReplyTap, + editMessageInputBuilder: + editMessageInputBuilder ?? this.editMessageInputBuilder, + textBuilder: textBuilder ?? this.textBuilder, + usernameBuilder: usernameBuilder ?? this.usernameBuilder, + onMessageActions: onMessageActions ?? this.onMessageActions, + message: message ?? this.message, + messageTheme: messageTheme ?? this.messageTheme, + reverse: reverse ?? this.reverse, + shape: shape ?? this.shape, + attachmentShape: attachmentShape ?? this.attachmentShape, + borderSide: borderSide ?? this.borderSide, + attachmentBorderSide: attachmentBorderSide ?? this.attachmentBorderSide, + borderRadiusGeometry: borderRadiusGeometry ?? this.borderRadiusGeometry, + attachmentBorderRadiusGeometry: attachmentBorderRadiusGeometry ?? + this.attachmentBorderRadiusGeometry, + padding: padding ?? this.padding, + textPadding: textPadding ?? this.textPadding, + attachmentPadding: attachmentPadding ?? this.attachmentPadding, + showUserAvatar: showUserAvatar ?? this.showUserAvatar, + showSendingIndicator: showSendingIndicator ?? this.showSendingIndicator, + showReactions: showReactions ?? this.showReactions, + allRead: allRead ?? this.allRead, + showThreadReplyIndicator: + showThreadReplyIndicator ?? this.showThreadReplyIndicator, + showInChannelIndicator: + showInChannelIndicator ?? this.showInChannelIndicator, + onUserAvatarTap: onUserAvatarTap ?? this.onUserAvatarTap, + onLinkTap: onLinkTap ?? this.onLinkTap, + showReactionPickerIndicator: + showReactionPickerIndicator ?? this.showReactionPickerIndicator, + readList: readList ?? this.readList, + onShowMessage: onShowMessage ?? this.onShowMessage, + onReturnAction: onReturnAction ?? this.onReturnAction, + showUsername: showUsername ?? this.showUsername, + showTimestamp: showTimestamp ?? this.showTimestamp, + showReplyMessage: showReplyMessage ?? this.showReplyMessage, + showThreadReplyMessage: + showThreadReplyMessage ?? this.showThreadReplyMessage, + showEditMessage: showEditMessage ?? this.showEditMessage, + showCopyMessage: showCopyMessage ?? this.showCopyMessage, + showDeleteMessage: showDeleteMessage ?? this.showDeleteMessage, + showResendMessage: showResendMessage ?? this.showResendMessage, + showFlagButton: showFlagButton ?? this.showFlagButton, + showPinButton: showPinButton ?? this.showPinButton, + showPinHighlight: showPinHighlight ?? this.showPinHighlight, + customAttachmentBuilders: + customAttachmentBuilders ?? this.attachmentBuilders, + translateUserAvatar: translateUserAvatar ?? this.translateUserAvatar, + onQuotedMessageTap: onQuotedMessageTap ?? this.onQuotedMessageTap, + onMessageTap: onMessageTap ?? this.onMessageTap, + customActions: customActions ?? this.customActions, + onAttachmentTap: onAttachmentTap ?? this.onAttachmentTap, + ); + @override _MessageWidgetState createState() => _MessageWidgetState(); } From dd7fafb3cff20bbbd263bff4a5adeab0adf95005 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 25 Jun 2021 10:39:03 +0200 Subject: [PATCH 2/8] use MessageWidget.copyWith in reactions modal --- .../lib/src/message_reactions_modal.dart | 60 ++----------------- .../lib/src/message_widget.dart | 33 ++++++---- 2 files changed, 27 insertions(+), 66 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart index 842fe79d..0292a05a 100644 --- a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart @@ -1,7 +1,6 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; @@ -15,17 +14,16 @@ class MessageReactionsModal extends StatelessWidget { const MessageReactionsModal({ Key? key, required this.message, + required this.messageWidget, required this.messageTheme, this.showReactions = true, - this.messageShape, - this.attachmentShape, this.reverse = false, - this.showUserAvatar = DisplayWidget.show, this.onUserAvatarTap, - this.attachmentBorderRadiusGeometry, - this.textBuilder, }) : super(key: key); + /// Widget that shows the message + final Widget messageWidget; + /// Message to display reactions of final Message message; @@ -38,24 +36,9 @@ class MessageReactionsModal extends StatelessWidget { /// Flag to show reactions on message final bool showReactions; - /// Enum to change user avatar config - final DisplayWidget showUserAvatar; - - /// [ShapeBorder] to apply to message - final ShapeBorder? messageShape; - - /// [ShapeBorder] to apply to attachment - final ShapeBorder? attachmentShape; - /// Callback when user avatar is tapped final void Function(User)? onUserAvatarTap; - /// [BorderRadius] to apply to attachments - final BorderRadius? attachmentBorderRadiusGeometry; - - /// Customize the MessageWidget textBuilder - final Widget Function(BuildContext context, Message message)? textBuilder; - @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; @@ -77,8 +60,6 @@ class MessageReactionsModal extends StatelessWidget { final divFactor = message.attachments.isNotEmpty == true ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); - final hasFileAttachment = - message.attachments.any((it) => it.type == 'file') == true; final numberOfReactions = StreamChatTheme.of(context).reactionIcons.length; final shiftFactor = @@ -110,38 +91,7 @@ class MessageReactionsModal extends StatelessWidget { ), const SizedBox(height: 8), IgnorePointer( - child: MessageWidget( - key: const Key('MessageWidget'), - reverse: reverse, - message: message.copyWith( - text: message.text!.length > 200 - ? '${message.text!.substring(0, 200)}...' - : message.text, - ), - messageTheme: messageTheme, - showReactions: false, - showUsername: false, - showUserAvatar: showUserAvatar, - showTimestamp: false, - translateUserAvatar: false, - showSendingIndicator: false, - shape: messageShape, - attachmentShape: attachmentShape, - padding: const EdgeInsets.all(0), - attachmentBorderRadiusGeometry: attachmentBorderRadiusGeometry - ?.mirrorBorderIfReversed(reverse: !reverse), - attachmentPadding: EdgeInsets.all( - hasFileAttachment ? 4 : 2, - ), - textPadding: EdgeInsets.symmetric( - vertical: 8, - horizontal: message.text!.isOnlyEmoji ? 0 : 16.0, - ), - showReactionPickerIndicator: showReactions && - (message.status == MessageSendingStatus.sent), - textBuilder: textBuilder, - showPinHighlight: false, - ), + child: messageWidget, ), if (message.latestReactions?.isNotEmpty == true) ...[ const SizedBox(height: 8), diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index cc0f0d3c..aea2f8b9 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -500,7 +500,7 @@ class MessageWidget extends StatefulWidget { showPinButton: showPinButton ?? this.showPinButton, showPinHighlight: showPinHighlight ?? this.showPinHighlight, customAttachmentBuilders: - customAttachmentBuilders ?? this.attachmentBuilders, + customAttachmentBuilders ?? attachmentBuilders, translateUserAvatar: translateUserAvatar ?? this.translateUserAvatar, onQuotedMessageTap: onQuotedMessageTap ?? this.onQuotedMessageTap, onMessageTap: onMessageTap ?? this.onMessageTap, @@ -1075,18 +1075,29 @@ class _MessageWidgetState extends State builder: (context) => StreamChannel( channel: channel, child: MessageReactionsModal( - textBuilder: widget.textBuilder, - attachmentBorderRadiusGeometry: - widget.attachmentBorderRadiusGeometry as BorderRadius?, - showUserAvatar: - widget.message.user!.id == channel.client.state.user!.id - ? DisplayWidget.gone - : DisplayWidget.show, + messageWidget: widget.copyWith( + key: const Key('MessageWidget'), + message: widget.message.copyWith( + text: widget.message.text!.length > 200 + ? '${widget.message.text!.substring(0, 200)}...' + : widget.message.text, + ), + showReactions: false, + showUsername: false, + showTimestamp: false, + translateUserAvatar: false, + showSendingIndicator: false, + padding: const EdgeInsets.all(0), + showReactionPickerIndicator: widget.showReactions && + (widget.message.status == MessageSendingStatus.sent), + showPinHighlight: false, + showUserAvatar: + widget.message.user!.id == channel.client.state.user!.id + ? DisplayWidget.gone + : DisplayWidget.show, + ), onUserAvatarTap: widget.onUserAvatarTap, messageTheme: widget.messageTheme, - messageShape: widget.shape ?? _getDefaultShape(context), - attachmentShape: - widget.attachmentShape ?? _getDefaultAttachmentShape(context), reverse: widget.reverse, message: widget.message, showReactions: widget.showReactions, From 1ceabb90f1f44e87163783984d2aa519d8e18227 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 25 Jun 2021 10:44:28 +0200 Subject: [PATCH 3/8] use MessageWidget.copyWith in actions modal --- .../lib/src/message_actions_modal.dart | 67 ++----------------- .../lib/src/message_widget.dart | 53 ++++++--------- 2 files changed, 26 insertions(+), 94 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index 6f57e7df..296b1e59 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -15,6 +15,7 @@ class MessageActionsModal extends StatefulWidget { const MessageActionsModal({ Key? key, required this.message, + required this.messageWidget, required this.messageTheme, this.showReactions = true, this.showDeleteMessage = true, @@ -27,18 +28,15 @@ class MessageActionsModal extends StatefulWidget { this.showThreadReplyMessage = true, this.showFlagButton = true, this.showPinButton = true, - this.showPinHighlight = false, - this.showUserAvatar = DisplayWidget.show, this.editMessageInputBuilder, - this.messageShape, - this.attachmentShape, this.reverse = false, this.customActions = const [], - this.attachmentBorderRadiusGeometry, this.onCopyTap, - this.textBuilder, }) : super(key: key); + /// Widget that shows the message + final Widget messageWidget; + /// Builder for edit message final Widget Function(BuildContext, Message)? editMessageInputBuilder; @@ -84,30 +82,12 @@ class MessageActionsModal extends StatefulWidget { /// Flag for showing pin action final bool showPinButton; - /// Display Pin Highlight - final bool showPinHighlight; - /// Flag for reversing message final bool reverse; - /// [ShapeBorder] to apply to the widget - final ShapeBorder? messageShape; - - /// [ShapeBorder] to apply to attachment - final ShapeBorder? attachmentShape; - - /// Enum for displaying user avatar - final DisplayWidget showUserAvatar; - - /// [BorderRadius] for attachment border - final BorderRadius? attachmentBorderRadiusGeometry; - /// List of custom actions final List customActions; - /// Customize the MessageWidget textBuilder - final Widget Function(BuildContext context, Message message)? textBuilder; - @override _MessageActionsModalState createState() => _MessageActionsModalState(); } @@ -142,9 +122,6 @@ class _MessageActionsModalState extends State { ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); - final hasFileAttachment = - widget.message.attachments.any((it) => it.type == 'file') == true; - final streamChatThemeData = StreamChatTheme.of(context); final numberOfReactions = streamChatThemeData.reactionIcons.length; @@ -178,41 +155,7 @@ class _MessageActionsModalState extends State { ), const SizedBox(height: 8), IgnorePointer( - child: MessageWidget( - key: const Key('MessageWidget'), - reverse: widget.reverse, - attachmentBorderRadiusGeometry: widget - .attachmentBorderRadiusGeometry - ?.mirrorBorderIfReversed(reverse: !widget.reverse), - message: widget.message.copyWith( - text: widget.message.text!.length > 200 - // ignore: lines_longer_than_80_chars - ? '${widget.message.text!.substring(0, 200)}...' - : widget.message.text, - ), - messageTheme: widget.messageTheme, - showReactions: false, - showUsername: false, - showReplyMessage: false, - showUserAvatar: widget.showUserAvatar, - attachmentPadding: EdgeInsets.all( - hasFileAttachment ? 4 : 2, - ), - showTimestamp: false, - translateUserAvatar: false, - padding: const EdgeInsets.all(0), - textPadding: EdgeInsets.symmetric( - vertical: 8, - horizontal: widget.message.text!.isOnlyEmoji ? 0 : 16.0, - ), - showReactionPickerIndicator: widget.showReactions && - (widget.message.status == MessageSendingStatus.sent), - showSendingIndicator: false, - shape: widget.messageShape, - attachmentShape: widget.attachmentShape, - showPinHighlight: false, - textBuilder: widget.textBuilder, - ), + child: widget.messageWidget, ), const SizedBox(height: 8), Padding( diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index aea2f8b9..49788f80 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -1023,19 +1023,30 @@ class _MessageWidgetState extends State builder: (context) => StreamChannel( channel: channel, child: MessageActionsModal( - textBuilder: widget.textBuilder, + messageWidget: widget.copyWith( + key: const Key('MessageWidget'), + message: widget.message.copyWith( + text: widget.message.text!.length > 200 + ? '${widget.message.text!.substring(0, 200)}...' + : widget.message.text, + ), + showReactions: false, + showUsername: false, + showTimestamp: false, + translateUserAvatar: false, + showSendingIndicator: false, + padding: const EdgeInsets.all(0), + showReactionPickerIndicator: widget.showReactions && + (widget.message.status == MessageSendingStatus.sent), + showPinHighlight: false, + showUserAvatar: + widget.message.user!.id == channel.client.state.user!.id + ? DisplayWidget.gone + : DisplayWidget.show, + ), onCopyTap: (message) => Clipboard.setData(ClipboardData(text: message.text)), - attachmentBorderRadiusGeometry: - widget.attachmentBorderRadiusGeometry as BorderRadius?, - showUserAvatar: - widget.message.user!.id == channel.client.state.user!.id - ? DisplayWidget.gone - : DisplayWidget.show, messageTheme: widget.messageTheme, - messageShape: widget.shape ?? _getDefaultShape(context), - attachmentShape: widget.attachmentShape ?? - _getDefaultAttachmentShape(context), reverse: widget.reverse, showDeleteMessage: widget.showDeleteMessage || isDeleteFailed, message: widget.message, @@ -1106,28 +1117,6 @@ class _MessageWidgetState extends State ); } - ShapeBorder _getDefaultAttachmentShape(BuildContext context) { - final hasFiles = - widget.message.attachments.any((it) => it.type == 'file') == true; - return RoundedRectangleBorder( - side: hasFiles - ? widget.attachmentBorderSide ?? - BorderSide( - color: _streamChatTheme.colorTheme.greyWhisper, - ) - : BorderSide.none, - borderRadius: widget.attachmentBorderRadiusGeometry ?? BorderRadius.zero, - ); - } - - ShapeBorder _getDefaultShape(BuildContext context) => RoundedRectangleBorder( - side: widget.borderSide ?? - BorderSide( - color: _streamChatTheme.colorTheme.greyWhisper, - ), - borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero, - ); - Widget _parseAttachments() { final attachmentGroups = >{}; From 8b71b32bdbf5ae5e34d8ee1199793596eb518ad9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 25 Jun 2021 11:23:52 +0200 Subject: [PATCH 4/8] use MessageWidget.copyWith in messagelistview --- .../lib/src/message_list_view.dart | 112 +++++------------- .../lib/src/message_widget.dart | 15 ++- 2 files changed, 42 insertions(+), 85 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 7eeba3e4..525f7313 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -56,32 +56,35 @@ typedef ReplyTapCallback = void Function(Message); class MessageDetails { /// Constructor for creating [MessageDetails] MessageDetails( - BuildContext context, + String currentUserId, this.message, List messages, this.index, + this.defaultMessageWidget, ) { - isMyMessage = message.user?.id == StreamChat.of(context).user?.id; + isMyMessage = message.user?.id == currentUserId; isLastUser = index + 1 < messages.length && message.user?.id == messages[index + 1].user?.id; isNextUser = index - 1 >= 0 && message.user!.id == messages[index - 1].user?.id; } + late final MessageWidget defaultMessageWidget; + /// True if the message belongs to the current user - bool? isMyMessage; + late final bool isMyMessage; /// True if the user message is the same of the previous message - bool? isLastUser; + late final bool isLastUser; /// True if the user message is the same of the next message - bool? isNextUser; + late final bool isNextUser; /// The message - Message message; + late final Message message; /// The index of the message - int index; + late final int index; } /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png) @@ -576,46 +579,21 @@ class _MessageListViewState extends State { const Offstage(); } - final topMessageIndex = itemCount - - 4; // 7 -> parent // 6 -> header // 5 -> loader const bottomMessageIndex = 2; // 1 -> loader // 0 -> footer final message = messages[i - 2]; Widget messageWidget; - if (i == topMessageIndex) { - messageWidget = _buildTopMessage( - context, - message, - messages, - streamChannel, - i, - ); - } else if (i == bottomMessageIndex) { + if (i == bottomMessageIndex) { messageWidget = _buildBottomMessage( context, message, messages, streamChannel!, - i, + i - 2, ); } else { - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey('MESSAGE-${message.id}'), - builder: (context) => widget.messageBuilder!( - context, - MessageDetails( - context, - message, - messages, - i, - ), - messages), - ); - } else { - messageWidget = buildMessage(message, messages, i); - } + messageWidget = buildMessage(message, messages, i - 2); } return messageWidget; }, @@ -785,34 +763,6 @@ class _MessageListViewState extends State { isThreadConversation: _isThreadConversation, ); - Widget _buildTopMessage( - BuildContext context, - Message message, - List messages, - StreamChannelState? streamChannel, - int index, - ) { - Widget messageWidget; - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: const ValueKey('TOP-MESSAGE'), - builder: (_) => widget.messageBuilder!( - context, - MessageDetails( - context, - message, - messages, - messages.length - 1, - ), - messages, - ), - ); - } else { - messageWidget = buildMessage(message, messages, index); - } - return messageWidget; - } - Widget _buildBottomMessage( BuildContext context, Message message, @@ -820,24 +770,7 @@ class _MessageListViewState extends State { StreamChannelState streamChannel, int index, ) { - Widget messageWidget; - if (widget.messageBuilder != null) { - messageWidget = Builder( - key: ValueKey('BOTTOM-MESSAGE-${message.id}'), - builder: (_) => widget.messageBuilder!( - context, - MessageDetails( - context, - message, - messages, - 0, - ), - messages, - ), - ); - } else { - messageWidget = buildMessage(message, messages, index); - } + final messageWidget = buildMessage(message, messages, index); return VisibilityDetector( key: ValueKey('BOTTOM-MESSAGE-${message.id}'), @@ -1015,7 +948,7 @@ class _MessageListViewState extends State { final currentUserMember = members.firstWhere((e) => e.user!.id == currentUser!.id); - Widget child = MessageWidget( + Widget messageWidget = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), message: message, reverse: isMyMessage, @@ -1130,6 +1063,21 @@ class _MessageListViewState extends State { showPinButton: widget.pinPermissions.contains(currentUserMember.role), ); + if (widget.messageBuilder != null) { + messageWidget = widget.messageBuilder!( + context, + MessageDetails( + userId, + message, + messages, + index, + messageWidget as MessageWidget, + ), + messages, + ); + } + + var child = messageWidget; if (!message.isDeleted && !message.isSystem && !message.isEphemeral && diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 49788f80..de86873d 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -572,7 +572,7 @@ class _MessageWidgetState extends State super.build(context); final avatarWidth = widget.messageTheme.avatarTheme?.constraints.maxWidth ?? 40; - final leftPadding = + final bottomRowPadding = widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5; return Material( @@ -627,7 +627,8 @@ class _MessageWidgetState extends State crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ - if (widget.showUserAvatar == + if (!widget.reverse && + widget.showUserAvatar == DisplayWidget.show && widget.message.user != null) ...[ _buildUserAvatar(), @@ -753,6 +754,13 @@ class _MessageWidgetState extends State ), ), ), + if (widget.reverse && + widget.showUserAvatar == + DisplayWidget.show && + widget.message.user != null) ...[ + _buildUserAvatar(), + const SizedBox(width: 4), + ] ], ), if (showBottomRow) @@ -763,7 +771,8 @@ class _MessageWidgetState extends State if (showBottomRow) Padding( padding: EdgeInsets.only( - left: leftPadding, + left: !widget.reverse ? bottomRowPadding : 0, + right: widget.reverse ? bottomRowPadding : 0, bottom: isPinned && widget.showPinHighlight ? 6.0 : 0.0, ), From e1a9e4d8789527152577adcdf0765d095d397fb2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 25 Jun 2021 11:30:19 +0200 Subject: [PATCH 5/8] use MessageWidget.copyWith in parentMessageBuilder --- .../lib/src/message_list_view.dart | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 525f7313..f6c6d60d 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -26,9 +26,12 @@ typedef MessageBuilder = Widget Function( ); /// Widget builder for parent message +/// [defaultMessageWidget] is the default [MessageWidget] configuration +/// Use [defaultMessageWidget.copyWith] to easily customize it typedef ParentMessageBuilder = Widget Function( BuildContext, Message?, + MessageWidget defaultMessageWidget, ); /// Widget builder for system message @@ -69,6 +72,8 @@ class MessageDetails { index - 1 >= 0 && message.user!.id == messages[index - 1].user?.id; } + /// Default [MessageWidget] configuration + /// use [defaultMessageWidget.copyWith] to easily customize it late final MessageWidget defaultMessageWidget; /// True if the message belongs to the current user @@ -548,11 +553,7 @@ class _MessageListViewState extends State { itemBuilder: (context, i) { if (i == itemCount - 1) { if (widget.parentMessage == null) return const Offstage(); - return widget.parentMessageBuilder?.call( - context, - widget.parentMessage, - ) ?? - buildParentMessage(widget.parentMessage!); + return buildParentMessage(widget.parentMessage!); } if (i == itemCount - 2) { @@ -804,7 +805,7 @@ class _MessageListViewState extends State { final currentUserMember = members.firstWhereOrNull((e) => e.user!.id == currentUser!.id); - return MessageWidget( + final defaultMessageWidget = MessageWidget( showReplyMessage: false, showResendMessage: false, showThreadReplyMessage: false, @@ -858,6 +859,16 @@ class _MessageListViewState extends State { showPinButton: currentUserMember != null && widget.pinPermissions.contains(currentUserMember.role), ); + + if (widget.parentMessageBuilder != null) { + return widget.parentMessageBuilder!.call( + context, + widget.parentMessage, + defaultMessageWidget, + ); + } + + return defaultMessageWidget; } Widget buildMessage( From f3a5db159423875c5a992e8a44289b2bfa365a28 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 25 Jun 2021 12:02:33 +0200 Subject: [PATCH 6/8] fix tests --- .../test/src/message_action_modal_test.dart | 21 +++++++ .../src/message_reactions_modal_test.dart | 55 ++++--------------- 2 files changed, 31 insertions(+), 45 deletions(-) diff --git a/packages/stream_chat_flutter/test/src/message_action_modal_test.dart b/packages/stream_chat_flutter/test/src/message_action_modal_test.dart index 9b7b3e52..953434de 100644 --- a/packages/stream_chat_flutter/test/src/message_action_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/message_action_modal_test.dart @@ -38,6 +38,10 @@ void main() { id: 'user-id', ), ), + messageWidget: const Text( + 'test', + key: Key('MessageWidget'), + ), messageTheme: streamTheme.ownMessageTheme, ), ), @@ -86,6 +90,10 @@ void main() { ), ), messageTheme: streamTheme.ownMessageTheme, + messageWidget: const Text( + 'test', + key: Key('MessageWidget'), + ), ), ), ), @@ -123,6 +131,7 @@ void main() { client: client, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), message: Message( text: 'test', user: User( @@ -178,6 +187,7 @@ void main() { client: client, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), onReplyTap: (m) { tapped = true; }, @@ -223,6 +233,7 @@ void main() { client: client, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), onThreadReplyTap: (m) { tapped = true; }, @@ -272,6 +283,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), message: Message( text: 'test', user: User( @@ -320,6 +332,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), editMessageInputBuilder: (context, m) => const Text('test'), message: Message( text: 'test', @@ -371,6 +384,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), onCopyTap: (m) => tapped = true, message: Message( text: 'test', @@ -420,6 +434,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), message: Message( status: MessageSendingStatus.failed, text: 'test', @@ -469,6 +484,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), message: Message( status: MessageSendingStatus.failed_update, text: 'test', @@ -516,6 +532,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), message: Message( id: 'testid', text: 'test', @@ -571,6 +588,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), message: Message( id: 'testid', text: 'test', @@ -626,6 +644,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), message: Message( id: 'testid', text: 'test', @@ -679,6 +698,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), message: Message( id: 'testid', text: 'test', @@ -734,6 +754,7 @@ void main() { channel: channel, child: SizedBox( child: MessageActionsModal( + messageWidget: const Text('test'), message: Message( id: 'testid', text: 'test', diff --git a/packages/stream_chat_flutter/test/src/message_reactions_modal_test.dart b/packages/stream_chat_flutter/test/src/message_reactions_modal_test.dart index 6bdb72b0..9452e7e6 100644 --- a/packages/stream_chat_flutter/test/src/message_reactions_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/message_reactions_modal_test.dart @@ -34,6 +34,10 @@ void main() { client: client, streamChatThemeData: streamTheme, child: MessageReactionsModal( + messageWidget: const Text( + 'test', + key: Key('MessageWidget'), + ), message: message, messageTheme: streamTheme.ownMessageTheme, ), @@ -43,28 +47,9 @@ void main() { await tester.pump(const Duration(milliseconds: 1000)); - expect(find.byType(MessageWidget), findsOneWidget); - final messageWidget = - tester.widget(find.byType(MessageWidget)); - expect(messageWidget.message, message); - expect(messageWidget.messageTheme, streamTheme.ownMessageTheme); - expect(messageWidget.attachmentBorderRadiusGeometry, null); - expect(messageWidget.showUserAvatar, DisplayWidget.show); - expect(messageWidget.reverse, false); - expect(messageWidget.attachmentShape, null); - expect(messageWidget.shape, null); - expect(messageWidget.onUserAvatarTap, null); - expect(messageWidget.showReactions, false); - expect(messageWidget.showUsername, false); - expect(messageWidget.showThreadReplyIndicator, false); - expect(messageWidget.showTimestamp, false); - expect(messageWidget.translateUserAvatar, false); - expect(messageWidget.showSendingIndicator, false); - expect(find.byType(ReactionBubble), findsNothing); - //only one avatar (the message one) - expect(find.byType(UserAvatar), findsOneWidget); + expect(find.byType(UserAvatar), findsNothing); }, ); @@ -105,14 +90,14 @@ void main() { client: client, streamChatThemeData: streamTheme, child: MessageReactionsModal( + messageWidget: const Text( + 'test', + key: Key('MessageWidget'), + ), message: message, messageTheme: streamTheme.ownMessageTheme, - showUserAvatar: DisplayWidget.gone, reverse: true, - attachmentBorderRadiusGeometry: BorderRadius.circular(1), - attachmentShape: const RoundedRectangleBorder(), showReactions: false, - messageShape: const RoundedRectangleBorder(), onUserAvatarTap: onUserAvatarTap, ), ), @@ -121,27 +106,7 @@ void main() { await tester.pump(const Duration(milliseconds: 1000)); - expect(find.byType(MessageWidget), findsOneWidget); - final messageWidget = - tester.widget(find.byType(MessageWidget)); - expect(messageWidget.message, message); - expect(messageWidget.messageTheme, streamTheme.ownMessageTheme); - expect(messageWidget.attachmentBorderRadiusGeometry, - BorderRadius.circular(1)); - expect(messageWidget.showUserAvatar, DisplayWidget.gone); - expect(messageWidget.reverse, true); - expect(messageWidget.showReactions, false); - expect(messageWidget.attachmentShape, const RoundedRectangleBorder()); - expect(messageWidget.shape, const RoundedRectangleBorder()); - expect(messageWidget.showReactions, false); - expect(messageWidget.showUsername, false); - expect(messageWidget.showThreadReplyIndicator, false); - expect(messageWidget.showTimestamp, false); - expect(messageWidget.translateUserAvatar, false); - expect(messageWidget.showSendingIndicator, false); - - final userAvatar = tester.widget(find.byType(UserAvatar)); - expect(userAvatar.onTap, onUserAvatarTap); + expect(find.byKey(const Key('MessageWidget')), findsOneWidget); expect(find.byType(ReactionBubble), findsOneWidget); expect(find.byType(UserAvatar), findsOneWidget); From 155706c8fd8b089f9a094ebe7773cdb80c997234 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 25 Jun 2021 14:01:35 +0200 Subject: [PATCH 7/8] remove unnecessary late --- packages/stream_chat_flutter/lib/src/message_list_view.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index f6c6d60d..bdc9d069 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -74,7 +74,7 @@ class MessageDetails { /// Default [MessageWidget] configuration /// use [defaultMessageWidget.copyWith] to easily customize it - late final MessageWidget defaultMessageWidget; + final MessageWidget defaultMessageWidget; /// True if the message belongs to the current user late final bool isMyMessage; @@ -86,10 +86,10 @@ class MessageDetails { late final bool isNextUser; /// The message - late final Message message; + final Message message; /// The index of the message - late final int index; + final int index; } /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png) From 1c3dbb1595d590bb6519198815cd84f28367f006 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 25 Jun 2021 14:18:56 +0200 Subject: [PATCH 8/8] move messagewidget in the builder --- .../example/lib/tutorial-part-5.dart | 1 + .../stream_chat_flutter/lib/src/message_list_view.dart | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_flutter/example/lib/tutorial-part-5.dart b/packages/stream_chat_flutter/example/lib/tutorial-part-5.dart index 7a75c037..8f1118dc 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial-part-5.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial-part-5.dart @@ -93,6 +93,7 @@ class ChannelPage extends StatelessWidget { BuildContext context, MessageDetails details, List messages, + MessageWidget _, ) { final message = details.message; final isCurrentUser = StreamChat.of(context).user!.id == message.user!.id; diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index bdc9d069..74942259 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -19,10 +19,13 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:visibility_detector/visibility_detector.dart'; /// Widget builder for message +/// [defaultMessageWidget] is the default [MessageWidget] configuration +/// Use [defaultMessageWidget.copyWith] to easily customize it typedef MessageBuilder = Widget Function( BuildContext, MessageDetails, List, + MessageWidget defaultMessageWidget, ); /// Widget builder for parent message @@ -63,7 +66,6 @@ class MessageDetails { this.message, List messages, this.index, - this.defaultMessageWidget, ) { isMyMessage = message.user?.id == currentUserId; isLastUser = index + 1 < messages.length && @@ -72,10 +74,6 @@ class MessageDetails { index - 1 >= 0 && message.user!.id == messages[index - 1].user?.id; } - /// Default [MessageWidget] configuration - /// use [defaultMessageWidget.copyWith] to easily customize it - final MessageWidget defaultMessageWidget; - /// True if the message belongs to the current user late final bool isMyMessage; @@ -1082,9 +1080,9 @@ class _MessageListViewState extends State { message, messages, index, - messageWidget as MessageWidget, ), messages, + messageWidget as MessageWidget, ); }