LCOV - code coverage report
Current view: top level - list/filter - filter_list_bloc.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 31 33 93.9 %
Date: 2019-11-04 17:53:55 Functions: 0 0 -

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