From 795ecb2b9d7fb6e8cfee4a513501b696a8e922cb Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 5 Feb 2021 14:10:04 +0530 Subject: [PATCH 1/3] fix: granular scrolling --- packages/stream_chat/lib/src/api/channel.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 7359c343..bdf74dd6 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -1450,7 +1450,6 @@ class ChannelClientState { ); } }); - _typingEventsController.add(_typings.keys.toList()); } /// Call this method to dispose this object From f4882900579bcf3ec2f278fd51ce0fafb6bbea3e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 17 Feb 2021 15:59:48 +0530 Subject: [PATCH 2/3] feat: Exposed builders --- .../lib/src/channel_list_view.dart | 36 +++++++++-------- .../lib/src/message_list_view.dart | 26 ++++++++++-- .../lib/src/message_search_list_view.dart | 39 +++++++++--------- .../lib/src/user_list_view.dart | 40 +++++++++---------- 4 files changed, 82 insertions(+), 59 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart index 2da9b434..abcc665f 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -67,8 +67,6 @@ class ChannelListView extends StatefulWidget { this.channelWidget, this.channelPreviewBuilder, this.separatorBuilder, - this.errorBuilder, - this.emptyBuilder, this.onImageTap, this.onStartChatPressed, this.swipeToAction = false, @@ -77,17 +75,15 @@ class ChannelListView extends StatefulWidget { this.padding, this.selectedChannels = const [], this.onViewInfoTap, + this.errorBuilder, + this.emptyBuilder, + this.loadingBuilder, + this.listBuilder, }) : super(key: key); - /// The builder that will be used in case of error - final Widget Function(Error error) errorBuilder; - /// If true a default swipe to action behaviour will be added to this widget final bool swipeToAction; - /// The builder used when the channel list is empty. - final WidgetBuilder emptyBuilder; - /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. @@ -147,6 +143,18 @@ class ChannelListView extends StatefulWidget { final ViewInfoCallback onViewInfoTap; + /// The builder that will be used in case of error + final ErrorBuilder errorBuilder; + + /// The builder that will be used in case of loading + final WidgetBuilder loadingBuilder; + + /// The builder which is used when list of channels loads + final Function(BuildContext, List) listBuilder; + + /// The builder used when the channel list is empty. + final WidgetBuilder emptyBuilder; + @override _ChannelListViewState createState() => _ChannelListViewState(); } @@ -161,16 +169,16 @@ class _ChannelListViewState extends State Widget build(BuildContext context) { var child = ChannelListCore( channelListController: _channelListController, - listBuilder: (context, list) { + listBuilder: widget.listBuilder ?? (context, list) { return _buildListView(list); }, - emptyBuilder: (BuildContext context) { + emptyBuilder: widget.emptyBuilder ?? (BuildContext context) { return _buildEmptyWidget(); }, - errorBuilder: (BuildContext context, dynamic error) { + errorBuilder: widget.errorBuilder ?? (BuildContext context, dynamic error) { return _buildErrorWidget(context); }, - loadingBuilder: (BuildContext context) { + loadingBuilder: widget.loadingBuilder ?? (BuildContext context) { return _buildLoadingWidget(); }, pagination: widget.pagination, @@ -236,10 +244,6 @@ class _ChannelListViewState extends State } Widget _buildEmptyWidget() { - if (widget.emptyBuilder != null) { - return widget.emptyBuilder(context); - } - return LayoutBuilder( builder: (context, viewportConstraints) { return SingleChildScrollView( 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 2929c2d7..5a862bce 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -126,6 +126,10 @@ class MessageListView extends StatefulWidget { this.messageHighlightColor, this.onShowMessage, this.showConnectionStateTile = false, + this.loadingBuilder, + this.emptyBuilder, + this.messageListBuilder, + this.errorWidgetBuilder, }) : super(key: key); /// Function used to build a custom message widget @@ -185,6 +189,20 @@ class MessageListView extends StatefulWidget { final bool showConnectionStateTile; + /// Function called when messages are fetched + final Widget Function(BuildContext, List) messageListBuilder; + + /// Function used to build a loading widget + final WidgetBuilder loadingBuilder; + + /// Function used to build an empty widget + final WidgetBuilder emptyBuilder; + + /// Callback triggered when an error occurs while performing the given request. + /// This parameter can be used to display an error message to users in the event + /// of a connection failure. + final ErrorBuilder errorWidgetBuilder; + @override _MessageListViewState createState() => _MessageListViewState(); } @@ -244,12 +262,12 @@ class _MessageListViewState extends State { @override Widget build(BuildContext context) { return MessageListCore( - loadingBuilder: (context) { + loadingBuilder: widget.loadingBuilder ?? (context) { return Center( child: const CircularProgressIndicator(), ); }, - emptyBuilder: (context) { + emptyBuilder: widget.emptyBuilder ?? (context) { return Center( child: Text( 'No chats here yet...', @@ -261,13 +279,13 @@ class _MessageListViewState extends State { ), ); }, - messageListBuilder: (context, list) { + messageListBuilder: widget.messageListBuilder ?? (context, list) { return _buildListView(list); }, messageListController: _messageListController, parentMessage: widget.parentMessage, showScrollToBottom: widget.showScrollToBottom, - errorWidgetBuilder: (BuildContext context, Object error) { + errorWidgetBuilder: widget.errorWidgetBuilder ?? (BuildContext context, Object error) { return Center( child: Text( 'Something went wrong', diff --git a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart index 490b3581..9a3b6aa5 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart @@ -53,14 +53,16 @@ class MessageSearchListView extends StatefulWidget { this.sortOptions, this.paginationParams, this.messageFilters, - this.emptyBuilder, - this.errorBuilder, this.separatorBuilder, this.itemBuilder, this.onItemTap, this.showResultCount = true, this.pullToRefresh = true, this.showErrorTile = false, + this.emptyBuilder, + this.errorBuilder, + this.loadingBuilder, + this.childBuilder, }) : super(key: key); /// Message String to search on @@ -94,12 +96,6 @@ class MessageSearchListView extends StatefulWidget { /// Function called when tapping on a [MessageSearchItem] final MessageSearchItemTapCallback onItemTap; - /// The builder used when the channel list is empty. - final EmptyMessageSearchBuilder emptyBuilder; - - /// The builder that will be used in case of error - final Widget Function(Error error) errorBuilder; - /// Builder used to create a custom item separator final IndexedWidgetBuilder separatorBuilder; @@ -111,6 +107,18 @@ class MessageSearchListView extends StatefulWidget { final bool showErrorTile; + /// The builder that is used when the search messages are fetched + final Widget Function(List) childBuilder; + + /// The builder used when the channel list is empty. + final WidgetBuilder emptyBuilder; + + /// The builder that will be used in case of error + final ErrorBuilder errorBuilder; + + /// The builder that will be used in case of loading + final WidgetBuilder loadingBuilder; + @override _MessageSearchListViewState createState() => _MessageSearchListViewState(); } @@ -128,10 +136,7 @@ class _MessageSearchListViewState extends State { paginationParams: widget.paginationParams, messageFilters: widget.messageFilters, messageSearchListController: _messageSearchListController, - emptyBuilder: (context) { - if (widget.emptyBuilder != null) { - return widget.emptyBuilder(context, widget.messageQuery); - } + emptyBuilder: widget.emptyBuilder ?? (context) { return LayoutBuilder( builder: (context, viewportConstraints) { return SingleChildScrollView( @@ -148,15 +153,11 @@ class _MessageSearchListViewState extends State { }, ); }, - errorBuilder: (BuildContext context, dynamic error) { + errorBuilder: widget.emptyBuilder ?? (BuildContext context, dynamic error) { if (error is Error) { print((error).stackTrace); } - if (widget.errorBuilder != null) { - return widget.errorBuilder(error); - } - var message = error.toString(); if (error is DioError) { if (error.type == DioErrorType.RESPONSE) { @@ -203,7 +204,7 @@ class _MessageSearchListViewState extends State { ), ); }, - loadingBuilder: (context) { + loadingBuilder: widget.loadingBuilder ?? (context) { return LayoutBuilder( builder: (context, viewportConstraints) { return SingleChildScrollView( @@ -220,7 +221,7 @@ class _MessageSearchListViewState extends State { }, ); }, - childBuilder: (list) { + childBuilder: widget.childBuilder ?? (list) { return _buildListView(list); }, ); diff --git a/packages/stream_chat_flutter/lib/src/user_list_view.dart b/packages/stream_chat_flutter/lib/src/user_list_view.dart index a1819592..d472feca 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -45,8 +45,6 @@ class UserListView extends StatefulWidget { /// Instantiate a new UserListView const UserListView({ Key key, - this.errorBuilder, - this.emptyBuilder, this.filter, this.options, this.sort, @@ -61,18 +59,16 @@ class UserListView extends StatefulWidget { this.pullToRefresh = true, this.groupAlphabetically = false, this.crossAxisCount = 1, + this.errorBuilder, + this.emptyBuilder, + this.loadingBuilder, + this.listBuilder, }) : assert( crossAxisCount == 1 || groupAlphabetically == false, 'Cannot group alphabetically when crossAxisCount > 1', ), super(key: key); - /// The builder that will be used in case of error - final Widget Function(Error error) errorBuilder; - - /// The builder used when the channel list is empty. - final WidgetBuilder emptyBuilder; - /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. @@ -130,6 +126,18 @@ class UserListView extends StatefulWidget { /// The number of children in the cross axis. final int crossAxisCount; + /// The builder that will be used in case of error + final Widget Function(Error error) errorBuilder; + + /// The builder that will be used to build the list + final Widget Function(BuildContext context, List users) listBuilder; + + /// The builder that will be used for loading + final WidgetBuilder loadingBuilder; + + /// The builder used when the channel list is empty. + final WidgetBuilder emptyBuilder; + @override _UserListViewState createState() => _UserListViewState(); } @@ -143,13 +151,13 @@ class _UserListViewState extends State @override Widget build(BuildContext context) { var child = UserListCore( - errorBuilder: (err) { + errorBuilder: widget.errorBuilder ?? (err) { return _buildError(err); }, - emptyBuilder: (context) { + emptyBuilder: widget.emptyBuilder ?? (context) { return _buildEmpty(); }, - loadingBuilder: (context) { + loadingBuilder: widget.loadingBuilder ?? (context) { return LayoutBuilder( builder: (context, viewportConstraints) { return SingleChildScrollView( @@ -166,7 +174,7 @@ class _UserListViewState extends State }, ); }, - listBuilder: (context, list) { + listBuilder: widget.listBuilder ?? (context, list) { return _buildListView(list); }, pagination: widget.pagination, @@ -195,10 +203,6 @@ class _UserListViewState extends State Widget _buildError(Error error) { print((error).stackTrace); - if (widget.errorBuilder != null) { - return widget.errorBuilder(error); - } - var message = error.toString(); if (error is DioError) { final dioError = error as DioError; @@ -246,10 +250,6 @@ class _UserListViewState extends State } Widget _buildEmpty() { - if (widget.emptyBuilder != null) { - return widget.emptyBuilder(context); - } - return LayoutBuilder( builder: (context, viewportConstraints) { return SingleChildScrollView( From 779c6f46f329a92e4a45e343f09c62cb51303505 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 17 Feb 2021 16:57:19 +0530 Subject: [PATCH 3/3] fmt: dartfmt --- .../lib/src/channel_list_view.dart | 28 +-- .../lib/src/message_list_view.dart | 68 +++---- .../lib/src/message_search_list_view.dart | 170 +++++++++--------- .../lib/src/user_list_view.dart | 52 +++--- 4 files changed, 167 insertions(+), 151 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart index abcc665f..90b40be9 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -169,18 +169,22 @@ class _ChannelListViewState extends State Widget build(BuildContext context) { var child = ChannelListCore( channelListController: _channelListController, - listBuilder: widget.listBuilder ?? (context, list) { - return _buildListView(list); - }, - emptyBuilder: widget.emptyBuilder ?? (BuildContext context) { - return _buildEmptyWidget(); - }, - errorBuilder: widget.errorBuilder ?? (BuildContext context, dynamic error) { - return _buildErrorWidget(context); - }, - loadingBuilder: widget.loadingBuilder ?? (BuildContext context) { - return _buildLoadingWidget(); - }, + listBuilder: widget.listBuilder ?? + (context, list) { + return _buildListView(list); + }, + emptyBuilder: widget.emptyBuilder ?? + (BuildContext context) { + return _buildEmptyWidget(); + }, + errorBuilder: widget.errorBuilder ?? + (BuildContext context, dynamic error) { + return _buildErrorWidget(context); + }, + loadingBuilder: widget.loadingBuilder ?? + (BuildContext context) { + return _buildLoadingWidget(); + }, pagination: widget.pagination, options: widget.options, sort: widget.sort, 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 5a862bce..eedf9689 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -262,41 +262,45 @@ class _MessageListViewState extends State { @override Widget build(BuildContext context) { return MessageListCore( - loadingBuilder: widget.loadingBuilder ?? (context) { - return Center( - child: const CircularProgressIndicator(), - ); - }, - emptyBuilder: widget.emptyBuilder ?? (context) { - return Center( - child: Text( - 'No chats here yet...', - style: StreamChatTheme.of(context).textTheme.footnote.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), - ), - ); - }, - messageListBuilder: widget.messageListBuilder ?? (context, list) { - return _buildListView(list); - }, + loadingBuilder: widget.loadingBuilder ?? + (context) { + return Center( + child: const CircularProgressIndicator(), + ); + }, + emptyBuilder: widget.emptyBuilder ?? + (context) { + return Center( + child: Text( + 'No chats here yet...', + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), + ), + ); + }, + messageListBuilder: widget.messageListBuilder ?? + (context, list) { + return _buildListView(list); + }, messageListController: _messageListController, parentMessage: widget.parentMessage, showScrollToBottom: widget.showScrollToBottom, - errorWidgetBuilder: widget.errorWidgetBuilder ?? (BuildContext context, Object error) { - return Center( - child: Text( - 'Something went wrong', - style: StreamChatTheme.of(context).textTheme.footnote.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5)), - ), - ); - }, + errorWidgetBuilder: widget.errorWidgetBuilder ?? + (BuildContext context, Object error) { + return Center( + child: Text( + 'Something went wrong', + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5)), + ), + ); + }, ); } diff --git a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart index 9a3b6aa5..94a79eaf 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart @@ -136,94 +136,98 @@ class _MessageSearchListViewState extends State { paginationParams: widget.paginationParams, messageFilters: widget.messageFilters, messageSearchListController: _messageSearchListController, - emptyBuilder: widget.emptyBuilder ?? (context) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: Text('There are no messages currently'), - ), - ), - ); - }, - ); - }, - errorBuilder: widget.emptyBuilder ?? (BuildContext context, dynamic error) { - if (error is Error) { - print((error).stackTrace); - } - - var message = error.toString(); - if (error is DioError) { - if (error.type == DioErrorType.RESPONSE) { - message = error.message; - } else { - message = 'Check your connection and retry'; - } - } - return InfoTile( - showMessage: widget.showErrorTile, - tileAnchor: Alignment.topCenter, - childAnchor: Alignment.topCenter, - message: 'An error occurred.', - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text.rich( - TextSpan( - children: [ - WidgetSpan( - child: Padding( - padding: const EdgeInsets.only(right: 2.0), - child: Icon(Icons.error_outline), - ), - ), - TextSpan(text: 'Error loading messages'), - ], + emptyBuilder: widget.emptyBuilder ?? + (context) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: Text('There are no messages currently'), + ), ), - style: Theme.of(context).textTheme.headline6, - ), - Padding( - padding: const EdgeInsets.only(top: 16.0), - child: Text(message), - ), - RaisedButton( - onPressed: () { - _messageSearchListController.loadData(); - }, - child: Text('Retry'), - ), - ], - ), - ), - ); - }, - loadingBuilder: widget.loadingBuilder ?? (context) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: CircularProgressIndicator(), + ); + }, + ); + }, + errorBuilder: widget.emptyBuilder ?? + (BuildContext context, dynamic error) { + if (error is Error) { + print((error).stackTrace); + } + + var message = error.toString(); + if (error is DioError) { + if (error.type == DioErrorType.RESPONSE) { + message = error.message; + } else { + message = 'Check your connection and retry'; + } + } + return InfoTile( + showMessage: widget.showErrorTile, + tileAnchor: Alignment.topCenter, + childAnchor: Alignment.topCenter, + message: 'An error occurred.', + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text.rich( + TextSpan( + children: [ + WidgetSpan( + child: Padding( + padding: const EdgeInsets.only(right: 2.0), + child: Icon(Icons.error_outline), + ), + ), + TextSpan(text: 'Error loading messages'), + ], + ), + style: Theme.of(context).textTheme.headline6, + ), + Padding( + padding: const EdgeInsets.only(top: 16.0), + child: Text(message), + ), + RaisedButton( + onPressed: () { + _messageSearchListController.loadData(); + }, + child: Text('Retry'), + ), + ], ), ), ); }, - ); - }, - childBuilder: widget.childBuilder ?? (list) { - return _buildListView(list); - }, + loadingBuilder: widget.loadingBuilder ?? + (context) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); + }, + ); + }, + childBuilder: widget.childBuilder ?? + (list) { + return _buildListView(list); + }, ); } diff --git a/packages/stream_chat_flutter/lib/src/user_list_view.dart b/packages/stream_chat_flutter/lib/src/user_list_view.dart index d472feca..4b50559b 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -151,32 +151,36 @@ class _UserListViewState extends State @override Widget build(BuildContext context) { var child = UserListCore( - errorBuilder: widget.errorBuilder ?? (err) { - return _buildError(err); - }, - emptyBuilder: widget.emptyBuilder ?? (context) { - return _buildEmpty(); - }, - loadingBuilder: widget.loadingBuilder ?? (context) { - return LayoutBuilder( - builder: (context, viewportConstraints) { - return SingleChildScrollView( - physics: AlwaysScrollableScrollPhysics(), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: viewportConstraints.maxHeight, - ), - child: Center( - child: CircularProgressIndicator(), - ), - ), + errorBuilder: widget.errorBuilder ?? + (err) { + return _buildError(err); + }, + emptyBuilder: widget.emptyBuilder ?? + (context) { + return _buildEmpty(); + }, + loadingBuilder: widget.loadingBuilder ?? + (context) { + return LayoutBuilder( + builder: (context, viewportConstraints) { + return SingleChildScrollView( + physics: AlwaysScrollableScrollPhysics(), + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: viewportConstraints.maxHeight, + ), + child: Center( + child: CircularProgressIndicator(), + ), + ), + ); + }, ); }, - ); - }, - listBuilder: widget.listBuilder ?? (context, list) { - return _buildListView(list); - }, + listBuilder: widget.listBuilder ?? + (context, list) { + return _buildListView(list); + }, pagination: widget.pagination, options: widget.options, sort: widget.sort,