LCOV - code coverage report
Current view: top level - utils - data_state.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 65 72 90.3 %
Date: 2021-12-09 18:46:36 Functions: 0 0 -

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

Generated by: LCOV version 1.15