LCOV - code coverage report
Current view: top level - list/filter - filter_list_bloc.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 29 31 93.5 %
Date: 2020-03-25 12:10:52 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:collection';
       2             : 
       3             : import 'package:bloc/bloc.dart';
       4             : import 'package:flutter_bloc_patterns/src/list/base/list_events.dart';
       5             : import 'package:flutter_bloc_patterns/src/list/filter/filter_list_repository.dart';
       6             : import 'package:flutter_bloc_patterns/src/view/view_state.dart';
       7             : 
       8             : /// A list BLoC with allowing filtering capabilities but without pagination.
       9             : /// Thus it should be used with a reasonable small amount of data.
      10             : ///
      11             : /// Designed to collaborate with [ViewStateBuilder] for displaying data.
      12             : ///
      13             : /// Call [loadElements] to perform initial data fetch.
      14             : /// Call [refreshElements] to perform a refresh.
      15             : ///
      16             : /// [T] - the type of list elements.
      17             : /// [F] - the type of filter.
      18             : class FilterListBloc<T, F> extends Bloc<ListEvent, ViewState> {
      19             :   final FilterListRepository<T, F> _repository;
      20             :   F _filter;
      21             : 
      22           2 :   FilterListBloc(FilterListRepository<T, F> filterListRepository)
      23           0 :       : assert(filterListRepository != null),
      24             :         _repository = filterListRepository;
      25             : 
      26           2 :   @override
      27             :   ViewState get initialState => const Initial();
      28             : 
      29           0 :   F get filter => _filter;
      30             : 
      31             :   /// Loads elements using the given [filter].
      32             :   ///
      33             :   /// It's most suitable for initial data fetch or for retry action when
      34             :   /// the first fetch fails. It can also be used when [filter] changes when a
      35             :   /// full reload is required.
      36           6 :   void loadElements({F filter}) => add(LoadList(filter));
      37             : 
      38             :   /// Refreshes elements using the given [filter].
      39             :   ///
      40             :   /// The refresh is designed for being called after the initial fetch
      41             :   /// succeeds. It can be performed when the list has already been loaded.
      42             :   ///
      43             :   /// It can be used when [filter] changes and there's no need for displaying a
      44             :   /// loading indicator.
      45           6 :   void refreshElements({F filter}) => add(RefreshList(filter));
      46             : 
      47             :   @override
      48           2 :   Stream<ViewState> mapEventToState(ListEvent event) async* {
      49           2 :     if (event is LoadList<F>) {
      50           6 :       yield* _mapLoadList(event.filter);
      51           4 :     } else if (event is RefreshList<F> && _isRefreshPossible(event)) {
      52           6 :       yield* _mapRefreshList(event.filter);
      53             :     }
      54             :   }
      55             : 
      56           2 :   bool _isRefreshPossible(ListEvent event) =>
      57           6 :       state is Success || state is Empty;
      58             : 
      59           2 :   Stream<ViewState> _mapLoadList(F filter) async* {
      60           2 :     yield const Loading();
      61           4 :     yield* _getListState(filter);
      62             :   }
      63             : 
      64           2 :   Stream<ViewState> _mapRefreshList(F filter) async* {
      65           2 :     final elements = _getCurrentStateElements();
      66           4 :     yield Refreshing(elements);
      67           4 :     yield* _getListState(filter);
      68             :   }
      69             : 
      70           2 :   List<T> _getCurrentStateElements() =>
      71           9 :       (state is Success<List<T>>) ? (state as Success<List<T>>).data : [];
      72             : 
      73           2 :   Stream<ViewState> _getListState(F filter) async* {
      74             :     try {
      75           4 :       final List<T> elements = await _getElementsFromRepository(filter);
      76           4 :       yield elements.isNotEmpty
      77           4 :           ? Success<List<T>>(UnmodifiableListView(elements))
      78             :           : const Empty();
      79             :     } catch (e) {
      80           4 :       yield Failure(e);
      81             :       rethrow;
      82             :     } finally {
      83           2 :       _filter = filter;
      84             :     }
      85             :   }
      86             : 
      87           2 :   Future<List<T>> _getElementsFromRepository(F filter) {
      88             :     if (filter != null) {
      89           2 :       return _repository.getBy(filter);
      90             :     } else {
      91           4 :       return _repository.getAll();
      92             :     }
      93             :   }
      94             : }

Generated by: LCOV version 1.14