From 190f2674969e3ca5b1ab88054906dc241ebf4932 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 16 Jun 2023 02:13:56 +0530 Subject: [PATCH 1/4] refactor(ui): refactor stream quouted message. Signed-off-by: xsahil03x --- .../message_input/quoted_message_widget.dart | 69 +++++++++++-------- .../message_input/stream_message_input.dart | 1 + .../lib/src/message_widget/message_card.dart | 23 +++++-- .../src/message_widget/quoted_message.dart | 38 +++------- 4 files changed, 65 insertions(+), 66 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input/quoted_message_widget.dart b/packages/stream_chat_flutter/lib/src/message_input/quoted_message_widget.dart index 554e8d12..a61ced63 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/quoted_message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/quoted_message_widget.dart @@ -20,7 +20,6 @@ class StreamQuotedMessageWidget extends StatelessWidget { this.textLimit = 170, this.attachmentThumbnailBuilders, this.padding = const EdgeInsets.all(8), - this.onTap, this.onQuotedMessageClear, }); @@ -46,9 +45,6 @@ class StreamQuotedMessageWidget extends StatelessWidget { /// Padding around the widget final EdgeInsetsGeometry padding; - /// Callback for tap on widget - final GestureTapCallback? onTap; - /// Callback for clearing quoted messages. final VoidCallback? onQuotedMessageClear; @@ -77,19 +73,12 @@ class StreamQuotedMessageWidget extends StatelessWidget { showOnlineStatus: false, ), ]; - return MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: onTap, - child: Padding( - padding: padding, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: reverse ? children.reversed.toList() : children, - ), - ), + return Padding( + padding: padding, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: reverse ? children.reversed.toList() : children, ), ); } @@ -258,23 +247,26 @@ class _ParseAttachments extends StatelessWidget { child = attachmentBuilder(context, attachment); } } - child = AbsorbPointer(child: child); + + final isImageFile = attachment.title?.mimeType?.type == 'image'; + final isVideoFile = attachment.title?.mimeType?.type == 'video'; + return Material( clipBehavior: Clip.hardEdge, type: MaterialType.transparency, - shape: attachment.type == 'file' + shape: attachment.type == 'file' && (!isImageFile && !isVideoFile) ? null : RoundedRectangleBorder( side: const BorderSide(width: 0, color: Colors.transparent), borderRadius: BorderRadius.circular(8), ), - child: child, + child: AbsorbPointer(child: child), ); } Map get _defaultAttachmentBuilder { - return { + final builders = { 'image': (_, attachment) { return StreamImageAttachment( attachment: attachment, @@ -315,16 +307,33 @@ class _ParseAttachments extends StatelessWidget { fit: BoxFit.cover, ); }, - 'file': (_, attachment) { - return SizedBox( - height: 32, - width: 32, - child: getFileTypeImage( - attachment.extraData['mime_type'] as String?, - ), - ); - }, }; + + builders['file'] = (_, attachment) { + return SizedBox( + height: 32, + width: 32, + child: Builder( + builder: (context) { + final isImageFile = attachment.title?.mimeType?.type == 'image'; + if (isImageFile) { + return builders['image']!(context, attachment); + } + + final isVideoFile = attachment.title?.mimeType?.type == 'video'; + if (isVideoFile) { + return builders['video']!(context, attachment); + } + + return getFileTypeImage( + attachment.extraData['mime_type'] as String?, + ); + }, + ), + ); + }; + + return builders; } } diff --git a/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart b/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart index cca0ab19..1de6c914 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart @@ -1133,6 +1133,7 @@ class StreamMessageInputState extends State messageTheme: _streamChatTheme.otherMessageTheme, padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), onQuotedMessageClear: widget.onQuotedMessageCleared, + attachmentThumbnailBuilders: widget.attachmentThumbnailBuilders, ); } diff --git a/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart b/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart index e7f1d506..ca3346d9 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart @@ -129,8 +129,11 @@ class _MessageCardState extends State { @override Widget build(BuildContext context) { + final onQuotedMessageTap = widget.onQuotedMessageTap; + return Card( elevation: 0, + clipBehavior: Clip.hardEdge, margin: EdgeInsets.symmetric( horizontal: (widget.isFailedState ? 15.0 : 0.0) + (widget.showUserAvatar == DisplayWidget.gone ? 0 : 4.0), @@ -150,15 +153,23 @@ class _MessageCardState extends State { maxWidth: widthLimit ?? double.infinity, ), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.hasQuotedMessage) - QuotedMessage( - reverse: widget.reverse, - message: widget.message, - hasNonUrlAttachments: widget.hasNonUrlAttachments, - onQuotedMessageTap: widget.onQuotedMessageTap, + MouseRegion( + cursor: SystemMouseCursors.click, + child: InkWell( + onTap: !widget.message.quotedMessage!.isDeleted && + onQuotedMessageTap != null + ? () => onQuotedMessageTap(widget.message.quotedMessageId) + : null, + child: QuotedMessage( + reverse: widget.reverse, + message: widget.message, + hasNonUrlAttachments: widget.hasNonUrlAttachments, + ), + ), ), if (widget.hasNonUrlAttachments) ParseAttachments( diff --git a/packages/stream_chat_flutter/lib/src/message_widget/quoted_message.dart b/packages/stream_chat_flutter/lib/src/message_widget/quoted_message.dart index f75bdbe7..673853af 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/quoted_message.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/quoted_message.dart @@ -7,63 +7,41 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart'; /// /// Used in [QuotedMessageCard]. Should not be used elsewhere. /// {@endtemplate} -class QuotedMessage extends StatefulWidget { +class QuotedMessage extends StatelessWidget { /// {@macro quotedMessage} const QuotedMessage({ super.key, required this.message, required this.reverse, required this.hasNonUrlAttachments, - this.onQuotedMessageTap, }); /// {@macro message} final Message message; - /// {@macro onQuotedMessageTap} - final OnQuotedMessageTap? onQuotedMessageTap; - /// {@macro reverse} final bool reverse; /// {@macro hasNonUrlAttachments} final bool hasNonUrlAttachments; - @override - State createState() => _QuotedMessageState(); -} - -class _QuotedMessageState extends State { - late StreamChatState _streamChat; - late StreamChatThemeData _streamChatTheme; - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _streamChatTheme = StreamChatTheme.of(context); - _streamChat = StreamChat.of(context); - } - @override Widget build(BuildContext context) { - final isMyMessage = widget.message.user?.id == _streamChat.currentUser?.id; - final onTap = widget.message.quotedMessage?.isDeleted != true && - widget.onQuotedMessageTap != null - ? () => widget.onQuotedMessageTap!(widget.message.quotedMessageId) - : null; - final chatThemeData = _streamChatTheme; + final streamChat = StreamChat.of(context); + final chatThemeData = StreamChatTheme.of(context); + + final isMyMessage = message.user?.id == streamChat.currentUser?.id; return StreamQuotedMessageWidget( - onTap: onTap, - message: widget.message.quotedMessage!, + message: message.quotedMessage!, messageTheme: isMyMessage ? chatThemeData.otherMessageTheme : chatThemeData.ownMessageTheme, - reverse: widget.reverse, + reverse: reverse, padding: EdgeInsets.only( right: 8, left: 8, top: 8, - bottom: widget.hasNonUrlAttachments ? 8 : 0, + bottom: hasNonUrlAttachments ? 8 : 0, ), ); } From 09d9ec3ed59e88953e32c8581de4d80e93d450ed Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 16 Jun 2023 02:37:56 +0530 Subject: [PATCH 2/4] feat(ui): add support for `quotedMessageBuilder`. Signed-off-by: xsahil03x --- .../message_input/stream_message_input.dart | 27 ++++++++++++------- .../lib/src/message_widget/message_card.dart | 19 +++++++++---- .../src/message_widget/message_widget.dart | 9 +++++++ .../message_widget_content.dart | 6 +++++ 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart b/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart index 1de6c914..3d80c14f 100644 --- a/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart @@ -129,6 +129,7 @@ class StreamMessageInput extends StatefulWidget { this.customAutocompleteTriggers = const [], this.mentionAllAppUsers = false, this.sendButtonBuilder, + this.quotedMessageBuilder, this.shouldKeepFocusAfterMessage, this.validator = _defaultValidator, this.restorationId, @@ -265,6 +266,9 @@ class StreamMessageInput extends StatefulWidget { /// Builder for creating send button final MessageRelatedBuilder? sendButtonBuilder; + /// Builder for building quoted message + final Widget Function(BuildContext, Message)? quotedMessageBuilder; + /// Defines if the [StreamMessageInput] loses focuses after a message is sent. /// The default behaviour keeps focus until a command is enabled. final bool? shouldKeepFocusAfterMessage; @@ -1126,15 +1130,20 @@ class StreamMessageInputState extends State if (!_hasQuotedMessage) return const Offstage(); final containsUrl = _effectiveController.message.quotedMessage!.attachments .any((element) => element.titleLink != null); - return StreamQuotedMessageWidget( - reverse: true, - showBorder: !containsUrl, - message: _effectiveController.message.quotedMessage!, - messageTheme: _streamChatTheme.otherMessageTheme, - padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), - onQuotedMessageClear: widget.onQuotedMessageCleared, - attachmentThumbnailBuilders: widget.attachmentThumbnailBuilders, - ); + + return widget.quotedMessageBuilder?.call( + context, + _effectiveController.message.quotedMessage!, + ) ?? + StreamQuotedMessageWidget( + reverse: true, + showBorder: !containsUrl, + message: _effectiveController.message.quotedMessage!, + messageTheme: _streamChatTheme.otherMessageTheme, + padding: const EdgeInsets.fromLTRB(8, 8, 8, 0), + onQuotedMessageClear: widget.onQuotedMessageCleared, + attachmentThumbnailBuilders: widget.attachmentThumbnailBuilders, + ); } Widget _buildAttachments() { diff --git a/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart b/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart index ca3346d9..5cd93efc 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart @@ -29,6 +29,7 @@ class MessageCard extends StatefulWidget { this.borderSide, this.borderRadiusGeometry, this.textBuilder, + this.quotedMessageBuilder, this.onLinkTap, this.onMentionTap, this.onQuotedMessageTap, @@ -82,6 +83,9 @@ class MessageCard extends StatefulWidget { /// {@macro textBuilder} final Widget Function(BuildContext, Message)? textBuilder; + /// {@macro quotedMessageBuilder} + final Widget Function(BuildContext, Message)? quotedMessageBuilder; + /// {@macro onLinkTap} final void Function(String)? onLinkTap; @@ -130,6 +134,7 @@ class _MessageCardState extends State { @override Widget build(BuildContext context) { final onQuotedMessageTap = widget.onQuotedMessageTap; + final quotedMessageBuilder = widget.quotedMessageBuilder; return Card( elevation: 0, @@ -164,11 +169,15 @@ class _MessageCardState extends State { onQuotedMessageTap != null ? () => onQuotedMessageTap(widget.message.quotedMessageId) : null, - child: QuotedMessage( - reverse: widget.reverse, - message: widget.message, - hasNonUrlAttachments: widget.hasNonUrlAttachments, - ), + child: quotedMessageBuilder?.call( + context, + widget.message.quotedMessage!, + ) ?? + QuotedMessage( + reverse: widget.reverse, + message: widget.message, + hasNonUrlAttachments: widget.hasNonUrlAttachments, + ), ), ), if (widget.hasNonUrlAttachments) diff --git a/packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart index fe7ccc19..61332a3c 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/message_widget.dart @@ -79,6 +79,7 @@ class StreamMessageWidget extends StatefulWidget { this.onMessageActions, this.onShowMessage, this.userAvatarBuilder, + this.quotedMessageBuilder, this.editMessageInputBuilder, this.textBuilder, @Deprecated(''' @@ -354,6 +355,11 @@ class StreamMessageWidget extends StatefulWidget { /// {@endtemplate} final Widget Function(BuildContext, User)? userAvatarBuilder; + /// {@template quotedMessageBuilder} + /// Widget builder for building quoted message + /// {@endtemplate} + final Widget Function(BuildContext, Message)? quotedMessageBuilder; + /// {@template message} /// The message to display. /// {@endtemplate} @@ -577,6 +583,7 @@ class StreamMessageWidget extends StatefulWidget { Future Function(Message)? onConfirmDeleteTap, Widget Function(BuildContext, Message)? editMessageInputBuilder, Widget Function(BuildContext, Message)? textBuilder, + Widget Function(BuildContext, Message)? quotedMessageBuilder, @Deprecated(''' Use [bottomRowBuilderWithDefaultWidget] instead. Will be removed in the next major version. @@ -670,6 +677,7 @@ class StreamMessageWidget extends StatefulWidget { editMessageInputBuilder: editMessageInputBuilder ?? this.editMessageInputBuilder, textBuilder: textBuilder ?? this.textBuilder, + quotedMessageBuilder: quotedMessageBuilder ?? this.quotedMessageBuilder, bottomRowBuilderWithDefaultWidget: _bottomRowBuilderWithDefaultWidget, onMessageActions: onMessageActions ?? this.onMessageActions, message: message ?? this.message, @@ -965,6 +973,7 @@ class _StreamMessageWidgetState extends State borderSide: widget.borderSide, borderRadiusGeometry: widget.borderRadiusGeometry, textBuilder: widget.textBuilder, + quotedMessageBuilder: widget.quotedMessageBuilder, onLinkTap: widget.onLinkTap, onMentionTap: widget.onMentionTap, onQuotedMessageTap: widget.onQuotedMessageTap, diff --git a/packages/stream_chat_flutter/lib/src/message_widget/message_widget_content.dart b/packages/stream_chat_flutter/lib/src/message_widget/message_widget_content.dart index c9e403ad..f8543013 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/message_widget_content.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/message_widget_content.dart @@ -63,6 +63,7 @@ class MessageWidgetContent extends StatelessWidget { this.onMentionTap, this.onLinkTap, this.textBuilder, + this.quotedMessageBuilder, @Deprecated(''' Use [bottomRowBuilderWithDefaultWidget] instead. Will be removed in the next major version. @@ -170,6 +171,9 @@ class MessageWidgetContent extends StatelessWidget { /// {@macro textBuilder} final Widget Function(BuildContext, Message)? textBuilder; + /// {@macro quotedMessageBuilder} + final Widget Function(BuildContext, Message)? quotedMessageBuilder; + /// {@macro showReactionPickerIndicator} final bool showReactionPickerIndicator; @@ -351,6 +355,8 @@ class MessageWidgetContent extends StatelessWidget { onMentionTap: onMentionTap, onLinkTap: onLinkTap, textBuilder: textBuilder, + quotedMessageBuilder: + quotedMessageBuilder, borderRadiusGeometry: borderRadiusGeometry, borderSide: borderSide, From 3f61cdaea2bba5fea4bb90d6fa1e1e2dd4fd1f0b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 16 Jun 2023 02:40:28 +0530 Subject: [PATCH 3/4] chore: update CHANGELOG.md Signed-off-by: xsahil03x --- packages/stream_chat_flutter/CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 4b77dfa0..a5e2c46f 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -35,6 +35,22 @@ ) ``` +- Added support for `StreamMessageWidget.quotedMessageBuilder` and `StreamMessageInput.quotedMessageBuilder` to override + the default quoted message widget. [#1606]() + + ```dart + StreamMessageWidget( + ..., + quotedMessageBuilder: (context, message) { + return Container( + color: Colors.red, + child: Text('Quoted Message'), + ); + }, + ) + ``` + + ## 6.3.0 🐞 Fixed From 95f21e66b9a8e327188be78aa80d55b078b479d1 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 16 Jun 2023 02:41:24 +0530 Subject: [PATCH 4/4] chore: update CHANGELOG.md Signed-off-by: xsahil03x --- packages/stream_chat_flutter/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index a5e2c46f..d1fdf4cb 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -36,7 +36,7 @@ ``` - Added support for `StreamMessageWidget.quotedMessageBuilder` and `StreamMessageInput.quotedMessageBuilder` to override - the default quoted message widget. [#1606]() + the default quoted message widget. [#1547](https://github.com/GetStream/stream-chat-flutter/issues/1547) ```dart StreamMessageWidget(