LCOV - code coverage report
Current view: top level - utils - data_state.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 70 86 81.4 %
Date: 2022-05-06 22:54:19 Functions: 0 0 -

          Line data    Source code
       1             : part of flutter_data;
       2             : 
       3             : class DataState<T> with EquatableMixin {
       4             :   final T model;
       5             :   final bool isLoading;
       6             :   final DataException? exception;
       7             :   final StackTrace? stackTrace;
       8             : 
       9           1 :   const DataState(
      10             :     this.model, {
      11             :     this.isLoading = false,
      12             :     this.exception,
      13             :     this.stackTrace,
      14             :   });
      15             : 
      16           2 :   bool get hasException => exception != null;
      17             : 
      18           2 :   bool get hasModel => model != null;
      19             : 
      20           1 :   @override
      21           4 :   List<Object?> get props => [model, isLoading, exception];
      22             : 
      23           0 :   @override
      24             :   bool get stringify => true;
      25             : }
      26             : 
      27             : class DataException with EquatableMixin implements Exception {
      28             :   final Object error;
      29             :   final StackTrace? stackTrace;
      30             :   final int? statusCode;
      31             : 
      32           1 :   const DataException(this.error, {this.stackTrace, this.statusCode});
      33             : 
      34           1 :   @override
      35           4 :   List<Object?> get props => [error, stackTrace, statusCode];
      36             : 
      37           1 :   @override
      38             :   String toString() {
      39           6 :     return 'DataException: $error ${statusCode != null ? " [HTTP $statusCode]" : ""}\n${stackTrace ?? ''}';
      40             :   }
      41             : }
      42             : 
      43             : class DataStateNotifier<T> extends StateNotifier<DataState<T>> {
      44           1 :   DataStateNotifier({
      45             :     required DataState<T> data,
      46             :     Future<void> Function()? reload,
      47             :   })  : _reloadFn = reload,
      48           1 :         super(data);
      49             : 
      50             :   // ignore: prefer_final_fields
      51             :   Future<void> Function()? _reloadFn;
      52             :   void Function()? onDispose;
      53             : 
      54           2 :   DataState<T> get data => super.state;
      55             : 
      56           1 :   void updateWith({
      57             :     Object? model = stamp,
      58             :     bool? isLoading,
      59             :     Object? exception = stamp,
      60             :     Object? stackTrace = stamp,
      61             :   }) {
      62           2 :     super.state = DataState<T>(
      63           3 :       model == stamp ? state.model : model as T,
      64           2 :       isLoading: isLoading ?? state.isLoading,
      65             :       exception:
      66           3 :           exception == stamp ? state.exception : exception as DataException?,
      67             :       stackTrace:
      68           3 :           stackTrace == stamp ? state.stackTrace : stackTrace as StackTrace?,
      69             :     );
      70             :   }
      71             : 
      72           1 :   Future<void> reload() async {
      73           2 :     return _reloadFn?.call();
      74             :   }
      75             : 
      76           1 :   @override
      77             :   RemoveListener addListener(
      78             :     Listener<DataState<T>> listener, {
      79             :     bool fireImmediately = true,
      80             :   }) {
      81             :     Function? _dispose;
      82           1 :     if (mounted) {
      83           1 :       _dispose = super.addListener(listener, fireImmediately: fireImmediately);
      84             :     }
      85           1 :     return () {
      86           1 :       _dispose?.call();
      87           2 :       onDispose?.call();
      88             :     };
      89             :   }
      90             : 
      91           1 :   @override
      92             :   void dispose() {
      93           1 :     if (mounted) {
      94           1 :       super.dispose();
      95             :     }
      96             :   }
      97             : }
      98             : 
      99             : class _Stamp {
     100           1 :   const _Stamp();
     101             : }
     102             : 
     103             : const stamp = _Stamp();
     104             : 
     105             : class _FunctionalDataStateNotifier<T, W> extends DataStateNotifier<W> {
     106             :   final DataStateNotifier<W> _source;
     107             :   late RemoveListener _sourceDisposeFn;
     108             : 
     109           1 :   _FunctionalDataStateNotifier(this._source)
     110           3 :       : super(data: _source.data, reload: _source._reloadFn);
     111             : 
     112           1 :   DataStateNotifier<W> where(bool Function(T) test) {
     113           4 :     _sourceDisposeFn = _source.addListener((state) {
     114           1 :       if (state.hasModel) {
     115             :         W _model;
     116             : 
     117           1 :         if (_typesEqual<W, List<T>?>()) {
     118           3 :           _model = (state.model as List<T>?)?.where(test).toList() as W;
     119           1 :         } else if (_typesEqual<W, T?>()) {
     120           3 :           _model = test(state.model as T) ? state.model : null as W;
     121             :         } else {
     122           0 :           throw UnsupportedError('W must either be T? or List<T>?');
     123             :         }
     124             : 
     125           2 :         super.state = DataState(_model,
     126           1 :             isLoading: state.isLoading,
     127           1 :             exception: state.exception,
     128           1 :             stackTrace: state.stackTrace);
     129             :       }
     130             :     });
     131             :     return this;
     132             :   }
     133             : 
     134           1 :   DataStateNotifier<W> map(T Function(T) convert) {
     135           4 :     _sourceDisposeFn = _source.addListener((state) {
     136           1 :       if (state.hasModel) {
     137             :         W _model;
     138             : 
     139           1 :         if (_typesEqual<W, List<T>?>()) {
     140           3 :           _model = (state.model as List<T>?)?.map(convert).toList() as W;
     141           1 :         } else if (_typesEqual<W, T>()) {
     142           2 :           _model = convert(state.model as T) as W;
     143             :         } else {
     144           0 :           throw UnsupportedError('W must either be T or List<T>?');
     145             :         }
     146             : 
     147           2 :         super.state = DataState(_model,
     148           1 :             isLoading: state.isLoading,
     149           1 :             exception: state.exception,
     150           1 :             stackTrace: state.stackTrace);
     151             :       }
     152             :     });
     153             :     return this;
     154             :   }
     155             : 
     156             :   late DataState<W> _bufferedState;
     157             :   Timer? _timer;
     158             : 
     159           0 :   DataStateNotifier<W> throttle(Duration Function() durationFn) {
     160           0 :     _timer = _makeTimer(durationFn);
     161           0 :     _sourceDisposeFn = _source.addListener((model) {
     162           0 :       _bufferedState = model;
     163             :     }, fireImmediately: false);
     164             :     return this;
     165             :   }
     166             : 
     167           0 :   Timer _makeTimer(Duration Function() durationFn) {
     168           0 :     return Timer(durationFn(), () {
     169           0 :       if (mounted) {
     170           0 :         super.state = _bufferedState;
     171           0 :         _timer = _makeTimer(durationFn); // reset timer
     172             :       }
     173             :     });
     174             :   }
     175             : 
     176           2 :   bool _typesEqual<T1, T2>() => T1 == T2;
     177             : 
     178           1 :   @override
     179             :   RemoveListener addListener(
     180             :     Listener<DataState<W>> listener, {
     181             :     bool fireImmediately = true,
     182             :   }) {
     183             :     final dispose =
     184           1 :         super.addListener(listener, fireImmediately: fireImmediately);
     185           1 :     return () {
     186           1 :       dispose.call();
     187           1 :       _timer?.cancel();
     188           2 :       _sourceDisposeFn.call();
     189             :     };
     190             :   }
     191             : 
     192           0 :   @override
     193             :   void dispose() {
     194           0 :     if (mounted) {
     195           0 :       super.dispose();
     196             :     }
     197           0 :     _source.dispose();
     198             :   }
     199             : }
     200             : 
     201             : /// Functional utilities for [DataStateNotifier]
     202             : extension DataStateNotifierListX<T> on DataStateNotifier<List<T>?> {
     203             :   /// Filters all models of the list (if present) through [test]
     204           1 :   DataStateNotifier<List<T>?> where(bool Function(T) test) {
     205           2 :     return _FunctionalDataStateNotifier<T, List<T>?>(this).where(test);
     206             :   }
     207             : 
     208             :   /// Maps all models of the list (if present) through [convert]
     209           1 :   DataStateNotifier<List<T>?> map(T Function(T) convert) {
     210           2 :     return _FunctionalDataStateNotifier<T, List<T>?>(this).map(convert);
     211             :   }
     212             : }
     213             : 
     214             : /// Functional utilities for [DataStateNotifier]
     215             : extension DataStateNotifierX<T> on DataStateNotifier<T> {
     216             :   /// Filters all models of the list (if present) through [test]
     217           1 :   DataStateNotifier<T> where(bool Function(T) test) {
     218           2 :     return _FunctionalDataStateNotifier<T, T>(this).where(test);
     219             :   }
     220             : 
     221             :   /// Maps all models of the list (if present) through [convert]
     222           1 :   DataStateNotifier<T> map(T Function(T) convert) {
     223           2 :     return _FunctionalDataStateNotifier<T, T>(this).map(convert);
     224             :   }
     225             : }

Generated by: LCOV version 1.15