Add custom sort support for offline channels

Signed-off-by: Sahil Kumar <[email protected]>
This commit is contained in:
Sahil Kumar
2021-02-26 18:30:22 +05:30
parent aeecc71154
commit 623d48e32b
13 changed files with 394 additions and 442 deletions
@@ -49,8 +49,11 @@ class ChannelInfo extends StatelessWidget {
var alternativeWidget;
if (channel.memberCount != null && channel.memberCount > 2) {
var text = '${channel.memberCount} Members';
final watcherCount = channel.state.watcherCount ?? 0;
if (watcherCount > 0) text += ' $watcherCount Online';
alternativeWidget = Text(
'${channel.memberCount} Members, ${channel.state.watcherCount} Online',
text,
style: StreamChatTheme.of(context)
.channelTheme
.channelHeaderTheme
@@ -99,7 +99,7 @@ class ChannelListView extends StatefulWidget {
/// Sorting is based on field and direction, multiple sorting options can be provided.
/// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count.
/// Direction can be ascending or descending.
final List<SortOption> sort;
final List<SortOption<ChannelModel>> sort;
/// Pagination parameters
/// limit: the number of channels to return (max is 30)
@@ -159,54 +159,42 @@ class ChannelListView extends StatefulWidget {
_ChannelListViewState createState() => _ChannelListViewState();
}
class _ChannelListViewState extends State<ChannelListView>
with WidgetsBindingObserver {
final ScrollController _scrollController = ScrollController();
final SlidableController _slideController = SlidableController();
final ChannelListController _channelListController = ChannelListController();
class _ChannelListViewState extends State<ChannelListView> {
final _slideController = SlidableController();
final _channelListController = ChannelListController();
@override
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();
},
Widget child = ChannelListCore(
pagination: widget.pagination,
options: widget.options,
sort: widget.sort,
filter: widget.filter,
channelListController: _channelListController,
listBuilder: widget.listBuilder ?? _buildListView,
emptyBuilder: widget.emptyBuilder ?? _buildEmptyWidget,
errorBuilder: widget.errorBuilder ?? _buildErrorWidget,
loadingBuilder: widget.loadingBuilder ?? _buildLoadingWidget,
);
if (!widget.pullToRefresh) {
return child;
} else {
return RefreshIndicator(
onRefresh: () async {
_channelListController.loadData();
},
if (widget.pullToRefresh) {
child = RefreshIndicator(
onRefresh: () async => _channelListController.loadData(),
child: child,
);
}
return LazyLoadScrollView(
onEndOfPage: () async {
_channelListController.paginateData();
},
child: child,
);
}
Widget _buildListView(
List<Channel> channels,
) {
var child;
Widget _buildListView(BuildContext context, List<Channel> channels) {
Widget child;
if (channels.isNotEmpty) {
if (widget.crossAxisCount > 1) {
@@ -216,7 +204,6 @@ class _ChannelListViewState extends State<ChannelListView>
crossAxisCount: widget.crossAxisCount),
itemCount: channels.length,
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
itemBuilder: (context, index) {
return _gridItemBuilder(context, index, channels);
},
@@ -236,18 +223,17 @@ class _ChannelListViewState extends State<ChannelListView>
itemBuilder: (context, index) {
return _listItemBuilder(context, index, channels);
},
controller: _scrollController,
);
}
}
return AnimatedSwitcher(
child: child,
duration: Duration(milliseconds: 500),
duration: const Duration(milliseconds: 500),
);
}
Widget _buildEmptyWidget() {
Widget _buildEmptyWidget(BuildContext context) {
return LayoutBuilder(
builder: (context, viewportConstraints) {
return SingleChildScrollView(
@@ -326,7 +312,7 @@ class _ChannelListViewState extends State<ChannelListView>
);
}
Widget _buildLoadingWidget() {
Widget _buildLoadingWidget(BuildContext context) {
return ListView(
padding: widget.padding,
physics: AlwaysScrollableScrollPhysics(),
@@ -341,13 +327,13 @@ class _ChannelListViewState extends State<ChannelListView>
return _separatorBuilder(context, i);
}
}
return _buildLoadingItem();
return _buildLoadingItem(context);
},
),
);
}
Shimmer _buildLoadingItem() {
Shimmer _buildLoadingItem(BuildContext context) {
if (widget.crossAxisCount > 1) {
return Shimmer.fromColors(
baseColor: StreamChatTheme.of(context).colorTheme.greyGainsboro,
@@ -443,9 +429,7 @@ class _ChannelListViewState extends State<ChannelListView>
}
}
Widget _buildErrorWidget(
BuildContext context,
) {
Widget _buildErrorWidget(BuildContext context, Object error) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
@@ -572,23 +556,13 @@ class _ChannelListViewState extends State<ChannelListView>
],
child: Container(
color: StreamChatTheme.of(context).colorTheme.whiteSnow,
child: widget.channelPreviewBuilder != null
? widget.channelPreviewBuilder(
context,
channel,
)
: ChannelPreview(
onLongPress: widget.onChannelLongPress,
channel: channel,
onImageTap: widget.onImageTap != null
? () {
widget.onImageTap(channel);
}
: null,
onTap: (channel) {
onTap(channel, widget.channelWidget);
},
),
child: widget.channelPreviewBuilder?.call(context, channel) ??
ChannelPreview(
onLongPress: widget.onChannelLongPress,
channel: channel,
onImageTap: widget.onImageTap?.call(channel),
onTap: (channel) => onTap(channel, widget.channelWidget),
),
),
);
},
@@ -618,9 +592,7 @@ class _ChannelListViewState extends State<ChannelListView>
width: 64,
height: 64,
),
onTap: () {
widget.onChannelTap(channel, null);
},
onTap: () => widget.onChannelTap(channel, null),
),
SizedBox(height: 7),
Padding(
@@ -680,70 +652,4 @@ class _ChannelListViewState extends State<ChannelListView>
color: effect.color.withOpacity(effect.alpha ?? 1.0),
);
}
void _listenChannelPagination(ChannelsBlocState channelsProvider) {
if (_scrollController.position.maxScrollExtent ==
_scrollController.offset &&
_scrollController.offset != 0) {
_channelListController.paginateData();
}
}
StreamSubscription _subscription;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
final channelsBloc = ChannelsBloc.of(context);
channelsBloc.queryChannels(
filter: widget.filter,
sortOptions: widget.sort,
paginationParams: widget.pagination,
options: widget.options,
);
_scrollController.addListener(() {
channelsBloc.queryChannelsLoading.first.then((loading) {
if (!loading) {
_listenChannelPagination(channelsBloc);
}
});
});
final client = StreamChat.of(context).client;
_subscription = client
.on(
EventType.connectionRecovered,
EventType.notificationAddedToChannel,
EventType.notificationMessageNew,
EventType.channelVisible,
)
.listen((event) {
_channelListController.loadData();
});
}
@override
void didUpdateWidget(ChannelListView oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.filter?.toString() != oldWidget.filter?.toString() ||
jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) ||
widget.pagination?.toJson()?.toString() !=
oldWidget.pagination?.toJson()?.toString() ||
widget.options?.toString() != oldWidget.options?.toString()) {
_channelListController.loadData();
}
}
@override
void dispose() {
_subscription.cancel();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}