diff --git a/lib/src/widgets/chat.dart b/lib/src/widgets/chat.dart index 73ce9982..e835aadd 100644 --- a/lib/src/widgets/chat.dart +++ b/lib/src/widgets/chat.dart @@ -28,6 +28,9 @@ import 'state/inherited_user.dart'; import 'typing_indicator.dart'; import 'unread_header.dart'; +/// Keep track of all the auto scroll indices by their respective message's id to allow animating to them. +final Map chatMessageAutoScrollIndexById = {}; + /// Entry widget, represents the complete chat. If you wrap it in [SafeArea] and /// it should be full screen, set [SafeArea]'s `bottom` to `false`. class Chat extends StatefulWidget { @@ -97,6 +100,7 @@ class Chat extends StatefulWidget { this.userAgent, this.useTopSafeAreaInset, this.videoMessageBuilder, + this.slidableMessageBuilder, }); /// See [Message.audioMessageBuilder]. @@ -318,13 +322,17 @@ class Chat extends StatefulWidget { final Widget Function(types.VideoMessage, {required int messageWidth})? videoMessageBuilder; + /// See [Message.slidableMessageBuilder]. + final Widget Function(types.Message, Widget msgWidget)? + slidableMessageBuilder; + @override State createState() => ChatState(); } /// [Chat] widget state. class ChatState extends State { - /// Used to get the correct auto scroll index from [_autoScrollIndexById]. + /// Used to get the correct auto scroll index from [chatMessageAutoScrollIndexById]. static const String _unreadHeaderId = 'unread_header_id'; List _chatMessages = []; @@ -333,8 +341,6 @@ class ChatState extends State { bool _hadScrolledToUnreadOnOpen = false; bool _isImageViewVisible = false; - /// Keep track of all the auto scroll indices by their respective message's id to allow animating to them. - final Map _autoScrollIndexById = {}; late final AutoScrollController _scrollController; @override @@ -348,7 +354,7 @@ class ChatState extends State { /// Scroll to the unread header. void scrollToUnreadHeader() { - final unreadHeaderIndex = _autoScrollIndexById[_unreadHeaderId]; + final unreadHeaderIndex = chatMessageAutoScrollIndexById[_unreadHeaderId]; if (unreadHeaderIndex != null) { _scrollController.scrollToIndex( unreadHeaderIndex, @@ -365,13 +371,13 @@ class ChatState extends State { Duration? highlightDuration, }) async { await _scrollController.scrollToIndex( - _autoScrollIndexById[id]!, + chatMessageAutoScrollIndexById[id]!, duration: scrollDuration ?? scrollAnimationDuration, preferPosition: AutoScrollPosition.middle, ); if (withHighlight) { await _scrollController.highlight( - _autoScrollIndexById[id]!, + chatMessageAutoScrollIndexById[id]!, highlightDuration: highlightDuration ?? const Duration(seconds: 3), ); } @@ -380,7 +386,7 @@ class ChatState extends State { /// Highlight the message with the specified [id]. void highlightMessage(String id, {Duration? duration}) => _scrollController.highlight( - _autoScrollIndexById[id]!, + chatMessageAutoScrollIndexById[id]!, highlightDuration: duration ?? const Duration(seconds: 3), ); @@ -456,8 +462,7 @@ class ChatState extends State { widget.showUserAvatars && message.author.id != widget.user.id ? min(constraints.maxWidth * 0.72, 440).floor() : min(constraints.maxWidth * 0.78, 440).floor(); - - messageWidget = Message( + final Widget msgWidget = Message( audioMessageBuilder: widget.audioMessageBuilder, avatarBuilder: widget.avatarBuilder, bubbleBuilder: widget.bubbleBuilder, @@ -499,6 +504,9 @@ class ChatState extends State { userAgent: widget.userAgent, videoMessageBuilder: widget.videoMessageBuilder, ); + messageWidget = widget.slidableMessageBuilder == null + ? msgWidget + : widget.slidableMessageBuilder!(message, msgWidget); } return AutoScrollTag( @@ -536,16 +544,16 @@ class ChatState extends State { widget.onPreviewDataFetched?.call(message, previewData); } - /// Updates the [_autoScrollIndexById] mapping with the latest messages. + /// Updates the [chatMessageAutoScrollIndexById] mapping with the latest messages. void _refreshAutoScrollMapping() { - _autoScrollIndexById.clear(); + chatMessageAutoScrollIndexById.clear(); var i = 0; for (final object in _chatMessages) { if (object is UnreadHeaderData) { - _autoScrollIndexById[_unreadHeaderId] = i; + chatMessageAutoScrollIndexById[_unreadHeaderId] = i; } else if (object is Map) { final message = object['message']! as types.Message; - _autoScrollIndexById[message.id] = i; + chatMessageAutoScrollIndexById[message.id] = i; } i++; }