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,30 +868,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
.index; .index;
} }
Widget _buildScrollToBottom() => StreamBuilder<int>( Future<void> scrollToBottomDefaultTapAction(int unreadCount) async {
stream: streamChannel!.channel.state!.unreadCountStream,
builder: (_, snapshot) {
if (snapshot.hasError) {
return const Offstage();
} else if (!snapshot.hasData) {
return const Offstage();
}
final unreadCount = snapshot.data!;
final showUnreadCount = unreadCount > 0 &&
streamChannel!.channel.state!.members.any((e) =>
e.userId ==
streamChannel!.channel.client.state.currentUser!.id);
return Positioned(
bottom: 8,
right: 8,
width: 40,
height: 40,
child: Stack(
clipBehavior: Clip.none,
children: [
FloatingActionButton(
backgroundColor: _streamTheme.colorTheme.barsBg,
onPressed: () async {
if (unreadCount > 0) { if (unreadCount > 0) {
streamChannel!.channel.markRead(); streamChannel!.channel.markRead();
} }
@@ -892,7 +889,38 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
curve: Curves.easeInOut, curve: Curves.easeInOut,
); );
} }
}, }
Widget _buildScrollToBottom() => StreamBuilder<int>(
stream: streamChannel!.channel.state!.unreadCountStream,
builder: (_, snapshot) {
if (snapshot.hasError) {
return const Offstage();
} else if (!snapshot.hasData) {
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 ==
streamChannel!.channel.client.state.currentUser!.id);
return Positioned(
bottom: 8,
right: 8,
width: 40,
height: 40,
child: Stack(
clipBehavior: Clip.none,
children: [
FloatingActionButton(
backgroundColor: _streamTheme.colorTheme.barsBg,
onPressed: () => scrollToBottomDefaultTapAction(unreadCount),
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,6 +604,7 @@ class StreamMessageInputState extends State<StreamMessageInput>
visible: _showCommandsOverlay, visible: _showCommandsOverlay,
widget: _buildCommandsOverlayEntry(), widget: _buildCommandsOverlayEntry(),
), ),
if (!_disableEmojiSuggestionsOverlay)
OverlayOptions( OverlayOptions(
visible: _focusNode.hasFocus && visible: _focusNode.hasFocus &&
_effectiveController.text.isNotEmpty && _effectiveController.text.isNotEmpty &&
@@ -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,
), ),
), ),
], ],