Merge pull request #108 from GetStream/feature/messageListView

add scroll to bottom fab
This commit is contained in:
Salvatore Giordano
2020-10-20 11:16:04 +02:00
committed by GitHub
3 changed files with 176 additions and 109 deletions
+72 -4
View File
@@ -97,6 +97,7 @@ class MessageListView extends StatefulWidget {
/// Instantiate a new MessageListView /// Instantiate a new MessageListView
MessageListView({ MessageListView({
Key key, Key key,
this.showScrollToBottom = true,
this.messageBuilder, this.messageBuilder,
this.parentMessageBuilder, this.parentMessageBuilder,
this.parentMessage, this.parentMessage,
@@ -120,6 +121,9 @@ class MessageListView extends StatefulWidget {
/// By default it calls [Navigator.push] using the widget built using [threadBuilder] /// By default it calls [Navigator.push] using the widget built using [threadBuilder]
final ThreadTapCallback onThreadTap; final ThreadTapCallback onThreadTap;
/// If true will show a scroll to bottom message when there are new messages and the scroll offset is not zero
final bool showScrollToBottom;
/// Parent message in case of a thread /// Parent message in case of a thread
final Message parentMessage; final Message parentMessage;
@@ -144,13 +148,16 @@ class _MessageListViewState extends State<MessageListView> {
List<Message> _messages = []; List<Message> _messages = [];
List<Message> _newMessageList = []; List<Message> _newMessageList = [];
Function _onThreadTap; Function _onThreadTap;
bool _showScrollToBottom = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final streamChannel = StreamChannel.of(context); final streamChannel = StreamChannel.of(context);
/// TODO: find a better solution when (https://github.com/flutter/flutter/issues/21023) is fixed /// TODO: find a better solution when (https://github.com/flutter/flutter/issues/21023) is fixed
return NotificationListener<ScrollNotification>( return Stack(
children: [
NotificationListener<ScrollNotification>(
onNotification: (_) { onNotification: (_) {
if (_scrollController.offset < 150 && _newMessageList.isNotEmpty) { if (_scrollController.offset < 150 && _newMessageList.isNotEmpty) {
setState(() { setState(() {
@@ -188,7 +195,8 @@ class _MessageListViewState extends State<MessageListView> {
'Start of thread', 'Start of thread',
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
color: Theme.of(context).accentColor.withAlpha(50), color:
Theme.of(context).accentColor.withAlpha(50),
), ),
), ),
], ],
@@ -250,8 +258,8 @@ class _MessageListViewState extends State<MessageListView> {
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0), padding: const EdgeInsets.symmetric(vertical: 12.0),
child: widget.dateDividerBuilder != null child: widget.dateDividerBuilder != null
? widget ? widget.dateDividerBuilder(
.dateDividerBuilder(nextMessage.createdAt.toLocal()) nextMessage.createdAt.toLocal())
: DateDivider( : DateDivider(
dateTime: nextMessage.createdAt.toLocal(), dateTime: nextMessage.createdAt.toLocal(),
), ),
@@ -271,6 +279,63 @@ class _MessageListViewState extends State<MessageListView> {
}, },
), ),
), ),
),
if (widget.showScrollToBottom)
StreamBuilder<Event>(
stream: streamChannel.channel.on(
EventType.messageNew,
),
builder: (context, _) {
if (!_showScrollToBottom ||
streamChannel.channel.state.unreadCount == 0) {
return SizedBox();
}
return _buildScrollToBottom(streamChannel);
}),
],
);
}
Widget _buildScrollToBottom(StreamChannelState streamChannel) {
return Positioned(
bottom: 8,
right: 8,
width: 40,
height: 40,
child: Stack(
clipBehavior: Clip.none,
children: [
FloatingActionButton(
backgroundColor: Colors.white,
child: Icon(
StreamIcons.down,
color: Colors.black,
),
onPressed: () {
Future.delayed(Duration(milliseconds: 500), () {
setState(() {
_showScrollToBottom = false;
});
});
_scrollController.animateTo(
0,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
);
},
),
Positioned(
width: 20,
height: 20,
left: 10,
top: -10,
child: CircleAvatar(
radius: 20,
child: Text(streamChannel.channel.state.unreadCount.toString()),
),
),
],
),
); );
} }
@@ -381,6 +446,9 @@ class _MessageListViewState extends State<MessageListView> {
} }
} }
_bottomWasVisible = isVisible; _bottomWasVisible = isVisible;
setState(() {
_showScrollToBottom = !isVisible;
});
}, },
child: messageWidget, child: messageWidget,
); );
+1 -2
View File
@@ -3,10 +3,9 @@ import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_flutter/src/channel_header.dart'; import 'package:stream_chat_flutter/src/channel_header.dart';
import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/channel_preview.dart';
import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/message_input.dart';
import 'package:stream_chat_flutter/src/reaction_icon.dart';
import 'package:stream_chat_flutter/src/stream_icons.dart'; import 'package:stream_chat_flutter/src/stream_icons.dart';
import 'reaction_asset.dart';
/// Inherited widget providing the [StreamChatThemeData] to the widget tree /// Inherited widget providing the [StreamChatThemeData] to the widget tree
class StreamChatTheme extends InheritedWidget { class StreamChatTheme extends InheritedWidget {
final StreamChatThemeData data; final StreamChatThemeData data;