Merge pull request #1030 from GetStream/live-event-improvements

feat(flutter): Live event integration improvements
This commit is contained in:
Salvatore Giordano
2022-04-07 10:53:23 +02:00
committed by GitHub
2 changed files with 79 additions and 34 deletions
@@ -172,6 +172,7 @@ class StreamMessageListView extends StatefulWidget {
const StreamMessageListView({ const StreamMessageListView({
Key? key, Key? key,
this.showScrollToBottom = true, this.showScrollToBottom = true,
this.scrollToBottomBuilder,
this.messageBuilder, this.messageBuilder,
this.parentMessageBuilder, this.parentMessageBuilder,
this.parentMessage, this.parentMessage,
@@ -243,6 +244,25 @@ class StreamMessageListView extends StatefulWidget {
/// messages and the scroll offset is not zero /// messages and the scroll offset is not zero
final bool showScrollToBottom; 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<void> Function(int) scrollToBottomDefaultTapAction,
)? scrollToBottomBuilder;
/// Parent message in case of a thread /// Parent message in case of a thread
final Message? parentMessage; final Message? parentMessage;
@@ -848,6 +868,29 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
.index; .index;
} }
Future<void> 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<int>( Widget _buildScrollToBottom() => StreamBuilder<int>(
stream: streamChannel!.channel.state!.unreadCountStream, stream: streamChannel!.channel.state!.unreadCountStream,
builder: (_, snapshot) { builder: (_, snapshot) {
@@ -857,6 +900,12 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
return const Offstage(); return const Offstage();
} }
final unreadCount = snapshot.data!; final unreadCount = snapshot.data!;
if (widget.scrollToBottomBuilder != null) {
return widget.scrollToBottomBuilder!(
unreadCount,
scrollToBottomDefaultTapAction,
);
}
final showUnreadCount = unreadCount > 0 && final showUnreadCount = unreadCount > 0 &&
streamChannel!.channel.state!.members.any((e) => streamChannel!.channel.state!.members.any((e) =>
e.userId == e.userId ==
@@ -871,28 +920,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
children: [ children: [
FloatingActionButton( FloatingActionButton(
backgroundColor: _streamTheme.colorTheme.barsBg, backgroundColor: _streamTheme.colorTheme.barsBg,
onPressed: () async { onPressed: () => scrollToBottomDefaultTapAction(unreadCount),
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,
);
}
},
child: widget.reverse child: widget.reverse
? StreamSvgIcon.down( ? StreamSvgIcon.down(
color: _streamTheme.colorTheme.textHighEmphasis, color: _streamTheme.colorTheme.textHighEmphasis,
@@ -210,6 +210,8 @@ class StreamMessageInput extends StatefulWidget {
this.enableSafeArea, this.enableSafeArea,
this.elevation, this.elevation,
this.shadow, this.shadow,
this.autoCorrect,
this.disableEmojiSuggestionsOverlay,
}) : super(key: key); }) : super(key: key);
/// List of options for showing overlays. /// List of options for showing overlays.
@@ -329,6 +331,14 @@ class StreamMessageInput extends StatefulWidget {
/// Shadow for the [StreamMessageInput] widget /// Shadow for the [StreamMessageInput] widget
final BoxShadow? shadow; 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) => static bool _defaultValidator(Message message) =>
message.text?.isNotEmpty == true || message.attachments.isNotEmpty; message.text?.isNotEmpty == true || message.attachments.isNotEmpty;
@@ -360,6 +370,11 @@ class StreamMessageInputState extends State<StreamMessageInput>
bool get _isEditing => bool get _isEditing =>
_effectiveController.value.status != MessageSendingStatus.sending; _effectiveController.value.status != MessageSendingStatus.sending;
bool get _autoCorrect => widget.autoCorrect ?? true;
bool get _disableEmojiSuggestionsOverlay =>
widget.disableEmojiSuggestionsOverlay ?? false;
RestorableMessageInputController? _controller; RestorableMessageInputController? _controller;
MessageInputController get _effectiveController => MessageInputController get _effectiveController =>
@@ -589,18 +604,19 @@ class StreamMessageInputState extends State<StreamMessageInput>
visible: _showCommandsOverlay, visible: _showCommandsOverlay,
widget: _buildCommandsOverlayEntry(), widget: _buildCommandsOverlayEntry(),
), ),
OverlayOptions( if (!_disableEmojiSuggestionsOverlay)
visible: _focusNode.hasFocus && OverlayOptions(
_effectiveController.text.isNotEmpty && visible: _focusNode.hasFocus &&
_effectiveController.baseOffset > 0 && _effectiveController.text.isNotEmpty &&
_effectiveController.text _effectiveController.baseOffset > 0 &&
.substring( _effectiveController.text
0, .substring(
_effectiveController.baseOffset, 0,
) _effectiveController.baseOffset,
.contains(':'), )
widget: _buildEmojiOverlay(), .contains(':'),
), widget: _buildEmojiOverlay(),
),
OverlayOptions( OverlayOptions(
visible: _showMentionsOverlay, visible: _showMentionsOverlay,
widget: _buildMentionsOverlayEntry(), widget: _buildMentionsOverlayEntry(),
@@ -802,6 +818,7 @@ class StreamMessageInputState extends State<StreamMessageInput>
textAlignVertical: TextAlignVertical.center, textAlignVertical: TextAlignVertical.center,
decoration: _getInputDecoration(context), decoration: _getInputDecoration(context),
textCapitalization: TextCapitalization.sentences, textCapitalization: TextCapitalization.sentences,
autocorrect: _autoCorrect,
), ),
), ),
], ],