Merge branch 'master' into feat/custom-attachment-upload

This commit is contained in:
Sahil Kumar
2021-02-17 20:40:15 +05:30
committed by GitHub
5 changed files with 234 additions and 194 deletions
+1
View File
@@ -11,6 +11,7 @@
- [Register](https://getstream.io/chat/trial/) to get an API key for Stream Chat
- [Flutter Chat Tutorial](https://getstream.io/chat/flutter/tutorial/)
- [Chat UI Kit](https://getstream.io/chat/ui-kit/)
- [Sample apps](https://github.com/GetStream/flutter-samples)
This repository contains code for our [Dart](https://dart.dev/) and [Flutter](https://flutter.dev/) chat clients.
@@ -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<Channel>) listBuilder;
/// The builder used when the channel list is empty.
final WidgetBuilder emptyBuilder;
@override
_ChannelListViewState createState() => _ChannelListViewState();
}
@@ -161,18 +169,22 @@ class _ChannelListViewState extends State<ChannelListView>
Widget build(BuildContext context) {
var child = ChannelListCore(
channelListController: _channelListController,
listBuilder: (context, list) {
return _buildListView(list);
},
emptyBuilder: (BuildContext context) {
return _buildEmptyWidget();
},
errorBuilder: (BuildContext context, dynamic error) {
return _buildErrorWidget(context);
},
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,
@@ -236,10 +248,6 @@ class _ChannelListViewState extends State<ChannelListView>
}
Widget _buildEmptyWidget() {
if (widget.emptyBuilder != null) {
return widget.emptyBuilder(context);
}
return LayoutBuilder(
builder: (context, viewportConstraints) {
return SingleChildScrollView(
@@ -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<Message>) 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();
}
@@ -242,41 +260,45 @@ class _MessageListViewState extends State<MessageListView> {
@override
Widget build(BuildContext context) {
return MessageListCore(
loadingBuilder: (context) {
return Center(
child: const CircularProgressIndicator(),
);
},
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: (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: (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)),
),
);
},
);
}
@@ -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<GetMessageResponse>) 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,101 +136,98 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
paginationParams: widget.paginationParams,
messageFilters: widget.messageFilters,
messageSearchListController: _messageSearchListController,
emptyBuilder: (context) {
if (widget.emptyBuilder != null) {
return widget.emptyBuilder(context, widget.messageQuery);
}
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: (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) {
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: <Widget>[
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: (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: <Widget>[
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: (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);
},
);
}
@@ -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<ListItem> 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,32 +151,36 @@ class _UserListViewState extends State<UserListView>
@override
Widget build(BuildContext context) {
var child = UserListCore(
errorBuilder: (err) {
return _buildError(err);
},
emptyBuilder: (context) {
return _buildEmpty();
},
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: (context, list) {
return _buildListView(list);
},
listBuilder: widget.listBuilder ??
(context, list) {
return _buildListView(list);
},
pagination: widget.pagination,
options: widget.options,
sort: widget.sort,
@@ -195,10 +207,6 @@ class _UserListViewState extends State<UserListView>
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 +254,6 @@ class _UserListViewState extends State<UserListView>
}
Widget _buildEmpty() {
if (widget.emptyBuilder != null) {
return widget.emptyBuilder(context);
}
return LayoutBuilder(
builder: (context, viewportConstraints) {
return SingleChildScrollView(