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 f4a8fef8..7fb96a95 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -172,6 +172,7 @@ class StreamMessageListView extends StatefulWidget { const StreamMessageListView({ Key? key, this.showScrollToBottom = true, + this.scrollToBottomBuilder, this.messageBuilder, this.parentMessageBuilder, this.parentMessage, @@ -243,6 +244,25 @@ class StreamMessageListView extends StatefulWidget { /// messages and the scroll offset is not zero final bool showScrollToBottom; + /// Function used to build a custom scroll to bottom widget + /// + /// Provides the current unread messages count and a reference + /// to the function that is executed on tap of this widget by default + /// + /// As an example: + /// MessageListView( + /// scrollToBottomBuilder: (unreadCount, defaultTapAction) { + /// return InkWell( + /// onTap: () => defaultTapAction(unreadCount), + /// child: Text('Scroll To Bottom'), + /// ); + /// }, + /// ), + final Widget Function( + int unreadCount, + Future Function(int) scrollToBottomDefaultTapAction, + )? scrollToBottomBuilder; + /// Parent message in case of a thread final Message? parentMessage; @@ -848,6 +868,29 @@ class _StreamMessageListViewState extends State { .index; } + Future scrollToBottomDefaultTapAction(int unreadCount) async { + if (unreadCount > 0) { + streamChannel!.channel.markRead(); + } + if (!_upToDate) { + _bottomPaginationActive = false; + initialAlignment = 0; + initialIndex = 0; + await streamChannel!.reloadChannel(); + + WidgetsBinding.instance?.addPostFrameCallback((_) { + _scrollController!.jumpTo(index: 0); + }); + } else { + _showScrollToBottom.value = false; + _scrollController!.scrollTo( + index: 0, + duration: const Duration(seconds: 1), + curve: Curves.easeInOut, + ); + } + } + Widget _buildScrollToBottom() => StreamBuilder( stream: streamChannel!.channel.state!.unreadCountStream, builder: (_, snapshot) { @@ -857,6 +900,12 @@ class _StreamMessageListViewState extends State { return const Offstage(); } final unreadCount = snapshot.data!; + if (widget.scrollToBottomBuilder != null) { + return widget.scrollToBottomBuilder!( + unreadCount, + scrollToBottomDefaultTapAction, + ); + } final showUnreadCount = unreadCount > 0 && streamChannel!.channel.state!.members.any((e) => e.userId == @@ -871,28 +920,7 @@ class _StreamMessageListViewState extends State { children: [ FloatingActionButton( backgroundColor: _streamTheme.colorTheme.barsBg, - onPressed: () async { - if (unreadCount > 0) { - streamChannel!.channel.markRead(); - } - if (!_upToDate) { - _bottomPaginationActive = false; - initialAlignment = 0; - initialIndex = 0; - await streamChannel!.reloadChannel(); - - WidgetsBinding.instance?.addPostFrameCallback((_) { - _scrollController!.jumpTo(index: 0); - }); - } else { - _showScrollToBottom.value = false; - _scrollController!.scrollTo( - index: 0, - duration: const Duration(seconds: 1), - curve: Curves.easeInOut, - ); - } - }, + onPressed: () => scrollToBottomDefaultTapAction(unreadCount), child: widget.reverse ? StreamSvgIcon.down( color: _streamTheme.colorTheme.textHighEmphasis, diff --git a/packages/stream_chat_flutter/lib/src/v4/message_input/stream_message_input.dart b/packages/stream_chat_flutter/lib/src/v4/message_input/stream_message_input.dart index 17e46255..a78f9b37 100644 --- a/packages/stream_chat_flutter/lib/src/v4/message_input/stream_message_input.dart +++ b/packages/stream_chat_flutter/lib/src/v4/message_input/stream_message_input.dart @@ -210,6 +210,8 @@ class StreamMessageInput extends StatefulWidget { this.enableSafeArea, this.elevation, this.shadow, + this.autoCorrect, + this.disableEmojiSuggestionsOverlay, }) : super(key: key); /// List of options for showing overlays. @@ -329,6 +331,14 @@ class StreamMessageInput extends StatefulWidget { /// Shadow for the [StreamMessageInput] widget final BoxShadow? shadow; + /// Disable autoCorrect by passing false + /// autoCorrect is enabled by default + final bool? autoCorrect; + + /// Disable the default emoji suggestions + /// Enabled by default + final bool? disableEmojiSuggestionsOverlay; + static bool _defaultValidator(Message message) => message.text?.isNotEmpty == true || message.attachments.isNotEmpty; @@ -360,6 +370,11 @@ class StreamMessageInputState extends State bool get _isEditing => _effectiveController.value.status != MessageSendingStatus.sending; + bool get _autoCorrect => widget.autoCorrect ?? true; + + bool get _disableEmojiSuggestionsOverlay => + widget.disableEmojiSuggestionsOverlay ?? false; + RestorableMessageInputController? _controller; MessageInputController get _effectiveController => @@ -589,18 +604,19 @@ class StreamMessageInputState extends State visible: _showCommandsOverlay, widget: _buildCommandsOverlayEntry(), ), - OverlayOptions( - visible: _focusNode.hasFocus && - _effectiveController.text.isNotEmpty && - _effectiveController.baseOffset > 0 && - _effectiveController.text - .substring( - 0, - _effectiveController.baseOffset, - ) - .contains(':'), - widget: _buildEmojiOverlay(), - ), + if (!_disableEmojiSuggestionsOverlay) + OverlayOptions( + visible: _focusNode.hasFocus && + _effectiveController.text.isNotEmpty && + _effectiveController.baseOffset > 0 && + _effectiveController.text + .substring( + 0, + _effectiveController.baseOffset, + ) + .contains(':'), + widget: _buildEmojiOverlay(), + ), OverlayOptions( visible: _showMentionsOverlay, widget: _buildMentionsOverlayEntry(), @@ -802,6 +818,7 @@ class StreamMessageInputState extends State textAlignVertical: TextAlignVertical.center, decoration: _getInputDecoration(context), textCapitalization: TextCapitalization.sentences, + autocorrect: _autoCorrect, ), ), ],