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

Generated by: LCOV version 1.15