LCOV - code coverage report
Current view: top level - src - channel_list_core.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 60 61 98.4 %
Date: 2021-05-27 10:59:48 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : import 'dart:convert';
       3             : 
       4             : import 'package:flutter/foundation.dart';
       5             : import 'package:flutter/material.dart';
       6             : import 'package:stream_chat/stream_chat.dart';
       7             : import 'package:stream_chat_flutter_core/src/channels_bloc.dart';
       8             : import 'package:stream_chat_flutter_core/src/stream_chat_core.dart';
       9             : import 'package:stream_chat_flutter_core/src/typedef.dart';
      10             : 
      11             : /// [ChannelListCore] is a simplified class that allows fetching a list of
      12             : /// channels while exposing UI builders.
      13             : /// A [ChannelListController] is used to reload and paginate data.
      14             : ///
      15             : ///
      16             : /// ```dart
      17             : /// class ChannelListPage extends StatelessWidget {
      18             : ///   @override
      19             : ///   Widget build(BuildContext context) {
      20             : ///     return Scaffold(
      21             : ///       body: ChannelListCore(
      22             : ///         filter: {
      23             : ///           'members': {
      24             : ///             '\$in': [StreamChat.of(context).user.id],
      25             : ///           }
      26             : ///         },
      27             : ///         sort: [SortOption('last_message_at')],
      28             : ///         pagination: PaginationParams(
      29             : ///           limit: 20,
      30             : ///         ),
      31             : ///         errorBuilder: (err) {
      32             : ///           return Center(
      33             : ///             child: Text('An error has occured'),
      34             : ///           );
      35             : ///         },
      36             : ///         emptyBuilder: (context) {
      37             : ///           return Center(
      38             : ///             child: Text('Nothing here...'),
      39             : ///           );
      40             : ///         },
      41             : ///         emptyBuilder: (context) {
      42             : ///           return Center(
      43             : ///             child: CircularProgressIndicator(),
      44             : ///           );
      45             : ///         },
      46             : ///         listBuilder: (context, list) {
      47             : ///           return ChannelPage(list);
      48             : ///         }
      49             : ///       ),
      50             : ///     );
      51             : ///   }
      52             : /// }
      53             : /// ```
      54             : ///
      55             : /// Make sure to have a [StreamChatCore] ancestor in order to provide the
      56             : /// information about the channels.
      57             : class ChannelListCore extends StatefulWidget {
      58             :   /// Instantiate a new ChannelListView
      59           1 :   const ChannelListCore({
      60             :     Key? key,
      61             :     required this.errorBuilder,
      62             :     required this.emptyBuilder,
      63             :     required this.loadingBuilder,
      64             :     required this.listBuilder,
      65             :     this.filter,
      66             :     this.options,
      67             :     this.sort,
      68             :     this.pagination = const PaginationParams(
      69             :       limit: 25,
      70             :     ),
      71             :     this.channelListController,
      72           1 :   }) : super(key: key);
      73             : 
      74             :   /// A [ChannelListController] allows reloading and pagination.
      75             :   /// Use [ChannelListController.loadData] and
      76             :   /// [ChannelListController.paginateData] respectively for reloading and
      77             :   /// pagination.
      78             :   final ChannelListController? channelListController;
      79             : 
      80             :   /// The builder that will be used in case of error
      81             :   final ErrorBuilder errorBuilder;
      82             : 
      83             :   /// The builder that will be used in case of loading
      84             :   final WidgetBuilder loadingBuilder;
      85             : 
      86             :   /// The builder which is used when list of channels loads
      87             :   final Function(BuildContext, List<Channel>) listBuilder;
      88             : 
      89             :   /// The builder used when the channel list is empty.
      90             :   final WidgetBuilder emptyBuilder;
      91             : 
      92             :   /// The query filters to use.
      93             :   /// You can query on any of the custom fields you've defined on the [Channel].
      94             :   /// You can also filter other built-in channel fields.
      95             :   final Filter? filter;
      96             : 
      97             :   /// Query channels options.
      98             :   ///
      99             :   /// state: if true returns the Channel state
     100             :   /// watch: if true listen to changes to this Channel in real time.
     101             :   final Map<String, dynamic>? options;
     102             : 
     103             :   /// The sorting used for the channels matching the filters.
     104             :   /// Sorting is based on field and direction, multiple sorting options can be
     105             :   /// provided.
     106             :   /// You can sort based on last_updated, last_message_at, updated_at, created
     107             :   /// _at or member_count. Direction can be ascending or descending.
     108             :   final List<SortOption<ChannelModel>>? sort;
     109             : 
     110             :   /// Pagination parameters
     111             :   /// limit: the number of channels to return (max is 30)
     112             :   /// offset: the offset (max is 1000)
     113             :   /// message_limit: how many messages should be included to each channel
     114             :   final PaginationParams pagination;
     115             : 
     116           1 :   @override
     117           1 :   ChannelListCoreState createState() => ChannelListCoreState();
     118             : }
     119             : 
     120             : /// The current state of the [ChannelListCore].
     121             : class ChannelListCoreState extends State<ChannelListCore> {
     122             :   late ChannelsBlocState _channelsBloc;
     123             :   StreamChatCoreState? _streamChatCoreState;
     124             : 
     125           1 :   @override
     126           2 :   Widget build(BuildContext context) => _buildListView(_channelsBloc);
     127             : 
     128           1 :   StreamBuilder<List<Channel>> _buildListView(
     129             :     ChannelsBlocState channelsBlocState,
     130             :   ) =>
     131           1 :       StreamBuilder<List<Channel>>(
     132           1 :         stream: channelsBlocState.channelsStream,
     133           1 :         builder: (context, snapshot) {
     134           1 :           if (snapshot.hasError) {
     135           4 :             return widget.errorBuilder(context, snapshot.error!);
     136             :           }
     137           1 :           if (!snapshot.hasData) {
     138           3 :             return widget.loadingBuilder(context);
     139             :           }
     140           1 :           final channels = snapshot.data!;
     141           1 :           if (channels.isEmpty) {
     142           3 :             return widget.emptyBuilder(context);
     143             :           }
     144           3 :           return widget.listBuilder(context, channels);
     145             :         },
     146             :       );
     147             : 
     148             :   /// Fetches initial channels and updates the widget
     149           3 :   Future<void> loadData() => _channelsBloc.queryChannels(
     150           2 :         filter: widget.filter,
     151           2 :         sortOptions: widget.sort,
     152           2 :         paginationParams: widget.pagination,
     153           2 :         options: widget.options,
     154             :       );
     155             : 
     156             :   /// Fetches more channels with updated pagination and updates the widget
     157           3 :   Future<void> paginateData() => _channelsBloc.queryChannels(
     158           2 :         filter: widget.filter,
     159           2 :         sortOptions: widget.sort,
     160           3 :         paginationParams: widget.pagination.copyWith(
     161           3 :           offset: _channelsBloc.channels?.length ?? 0,
     162             :         ),
     163           2 :         options: widget.options,
     164             :       );
     165             : 
     166             :   StreamSubscription<Event>? _subscription;
     167             : 
     168           1 :   @override
     169             :   void initState() {
     170           1 :     super.initState();
     171           1 :     _setupController();
     172             :   }
     173             : 
     174           1 :   @override
     175             :   void didChangeDependencies() {
     176           3 :     _channelsBloc = ChannelsBloc.of(context);
     177           2 :     final newStreamChatCoreState = StreamChatCore.of(context);
     178             : 
     179           2 :     if (newStreamChatCoreState != _streamChatCoreState) {
     180           1 :       _streamChatCoreState = newStreamChatCoreState;
     181           1 :       loadData();
     182           2 :       final client = _streamChatCoreState!.client;
     183           1 :       _subscription?.cancel();
     184           1 :       _subscription = client
     185           1 :           .on(
     186             :             EventType.connectionRecovered,
     187             :             EventType.notificationAddedToChannel,
     188             :             EventType.notificationMessageNew,
     189             :             EventType.channelVisible,
     190             :           )
     191           1 :           .listen((event) => loadData());
     192             :     }
     193             : 
     194           1 :     super.didChangeDependencies();
     195             :   }
     196             : 
     197           1 :   @override
     198             :   void didUpdateWidget(ChannelListCore oldWidget) {
     199           1 :     super.didUpdateWidget(oldWidget);
     200             : 
     201           4 :     if (widget.filter?.toString() != oldWidget.filter?.toString() ||
     202           6 :         jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) ||
     203           4 :         widget.options?.toString() != oldWidget.options?.toString() ||
     204           5 :         widget.pagination.toJson().toString() !=
     205           3 :             oldWidget.pagination.toJson().toString()) {
     206           1 :       loadData();
     207             :     }
     208             : 
     209           4 :     if (widget.channelListController != oldWidget.channelListController) {
     210           0 :       _setupController();
     211             :     }
     212             :   }
     213             : 
     214           1 :   void _setupController() {
     215           2 :     if (widget.channelListController != null) {
     216           4 :       widget.channelListController!.loadData = loadData;
     217           4 :       widget.channelListController!.paginateData = paginateData;
     218             :     }
     219             :   }
     220             : 
     221           1 :   @override
     222             :   void dispose() {
     223           2 :     _subscription?.cancel();
     224           1 :     super.dispose();
     225             :   }
     226             : }
     227             : 
     228             : /// Controller used for loading more data and controlling pagination in
     229             : /// [ChannelListCore].
     230             : class ChannelListController {
     231             :   /// This function calls Stream's servers to load a list of channels.
     232             :   /// If there is existing data, calling this function causes a reload.
     233             :   AsyncCallback? loadData;
     234             : 
     235             :   /// This function is used to load another page of data. Note, [loadData]
     236             :   /// should be used to populate the initial page of data. Calling
     237             :   /// [paginateData] performs a query to load subsequent pages.
     238             :   AsyncCallback? paginateData;
     239             : }

Generated by: LCOV version 1.14