LCOV - code coverage report
Current view: top level - graph - notifier_extension.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 31 50 62.0 %
Date: 2022-06-06 11:59:57 Functions: 0 0 -

          Line data    Source code
       1             : library notifier_extension;
       2             : 
       3             : import 'dart:async';
       4             : 
       5             : import 'package:state_notifier/state_notifier.dart';
       6             : 
       7             : class DelayedStateNotifier<T> extends StateNotifier<T?> {
       8          22 :   DelayedStateNotifier() : super(null);
       9             : 
      10          11 :   @override
      11          11 :   set state(T? value) => super.state = value;
      12             : 
      13           5 :   @override
      14             :   RemoveListener addListener(void Function(T) listener,
      15             :       {bool fireImmediately = true}) {
      16           5 :     outerListener(T? value) {
      17             :       // if `value` is `null` and `T` is actually a nullable
      18             :       // type, then the listener MUST be called with `null`
      19           5 :       if (_typesEqual<T, T?>() && value == null) {
      20           1 :         listener(null as T);
      21             :       } else if (value != null) {
      22             :         // if `value != null` and `T` is non-nullable, also
      23           5 :         listener(value);
      24             :       }
      25             :     }
      26             : 
      27           5 :     return super.addListener(outerListener, fireImmediately: false);
      28             :   }
      29             : 
      30             :   Function? onDispose;
      31             : 
      32          10 :   @override
      33             :   void dispose() {
      34          10 :     super.dispose();
      35          10 :     onDispose?.call();
      36             :   }
      37             : 
      38          10 :   bool _typesEqual<T1, T2>() => T1 == T2;
      39             : }
      40             : 
      41             : class _FunctionalStateNotifier<S, T> extends DelayedStateNotifier<T> {
      42             :   final DelayedStateNotifier<S> _source;
      43             :   final String? name;
      44             :   late RemoveListener _sourceDisposeFn;
      45             :   Timer? _timer;
      46             : 
      47           5 :   _FunctionalStateNotifier(this._source, {this.name});
      48             : 
      49           2 :   DelayedStateNotifier<T> where(bool Function(S) test) {
      50           8 :     _sourceDisposeFn = _source.addListener((newState) {
      51           2 :       if (test(newState)) {
      52           2 :         state = newState as T;
      53             :       }
      54             :     }, fireImmediately: false);
      55             :     return this;
      56             :   }
      57             : 
      58           5 :   DelayedStateNotifier<T> map(T Function(S) convert) {
      59          20 :     _sourceDisposeFn = _source.addListener((state) {
      60          10 :       super.state = convert(state);
      61             :     }, fireImmediately: false);
      62             :     return this;
      63             :   }
      64             : 
      65             :   final _bufferedState = <S>[];
      66             : 
      67           0 :   DelayedStateNotifier<T> throttle(Duration Function() durationFn) {
      68           0 :     _timer = _makeTimer(durationFn);
      69           0 :     _sourceDisposeFn = _source.addListener((model) {
      70           0 :       _bufferedState.add(model);
      71             :     }, fireImmediately: false);
      72             :     return this;
      73             :   }
      74             : 
      75           0 :   Timer _makeTimer(Duration Function() durationFn) {
      76           0 :     return Timer(durationFn(), () {
      77           0 :       if (mounted) {
      78           0 :         if (_bufferedState.isNotEmpty) {
      79             :           // Cloning the bufferedState list to force
      80             :           // calling listeners as workaround (need to figure out
      81             :           // where they are previously updated and why
      82             :           // super.state == _bufferedState -- and thus no update)
      83           0 :           super.state = [..._bufferedState] as T; // since T == List<S>;
      84           0 :           _bufferedState.clear(); // clear buffer
      85             :         }
      86           0 :         _timer = _makeTimer(durationFn); // reset timer
      87             :       }
      88             :     });
      89             :   }
      90             : 
      91           5 :   @override
      92             :   RemoveListener addListener(
      93             :     Listener<T> listener, {
      94             :     bool fireImmediately = true,
      95             :   }) {
      96             :     final dispose =
      97           5 :         super.addListener(listener, fireImmediately: fireImmediately);
      98           5 :     return () {
      99           5 :       dispose.call();
     100           5 :       _timer?.cancel();
     101          10 :       _sourceDisposeFn.call();
     102             :     };
     103             :   }
     104             : 
     105           0 :   @override
     106             :   void dispose() {
     107           0 :     if (mounted) {
     108           0 :       super.dispose();
     109             :     }
     110           0 :     _source.dispose();
     111           0 :     _timer?.cancel();
     112             :   }
     113             : }
     114             : 
     115             : /// Functional utilities for [StateNotifier]
     116             : extension StateNotifierX<T> on DelayedStateNotifier<T> {
     117             :   /// Filters incoming events by [test]
     118           2 :   DelayedStateNotifier<T> where(bool Function(T) test) {
     119           4 :     return _FunctionalStateNotifier<T, T>(this, name: 'where').where(test);
     120             :   }
     121             : 
     122             :   /// Maps events of type [T] onto events of type [R] via [convert]
     123           5 :   DelayedStateNotifier<R> map<R>(R Function(T) convert) {
     124          10 :     return _FunctionalStateNotifier<T, R>(this, name: 'map').map(convert);
     125             :   }
     126             : 
     127             :   /// Buffers all incoming [T] events for a duration obtained via
     128             :   /// [durationFn] and emits them as a [List<T>] (unless there were none)
     129           0 :   DelayedStateNotifier<List<T>> throttle(Duration Function() durationFn) {
     130           0 :     return _FunctionalStateNotifier<T, List<T>>(this, name: 'throttle')
     131           0 :         .throttle(durationFn);
     132             :   }
     133             : }

Generated by: LCOV version 1.15