LCOV - code coverage report
Current view: top level - src/state/listeners - provider_listener.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 55 55 100.0 %
Date: 2022-11-04 14:47:16 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/widgets.dart'
       2             :     show Widget, BuildContext, StatefulWidget, State, WidgetsBinding, Key;
       3             : 
       4             : import 'package:meedu/meedu.dart';
       5             : 
       6             : import '../../utils/ambiguate.dart';
       7             : import '../widgets/watch_filter.dart';
       8             : 
       9             : /// a typedef for a common callback
      10             : typedef _ProviderListenerCallback<T> = void Function(
      11             :   BuildContext _,
      12             :   T notifier,
      13             : );
      14             : 
      15             : typedef _Builder<T> = Widget Function(BuildContext, T);
      16             : 
      17             : /// A widget to listen events in a SimpleProvider or a StateProvider
      18             : ///
      19             : /// THis widget only listen the events, does not update the widget when a SimpleNotifier or a StateNotifier emit a new event
      20             : class ProviderListener<T extends BaseNotifier> extends StatefulWidget {
      21             :   // ignore: public_member_api_docs
      22           3 :   const ProviderListener({
      23             :     Key? key,
      24             :     this.onChange,
      25             :     required this.provider,
      26             :     required this.builder,
      27             :     this.onInitState,
      28             :     this.onDispose,
      29             :     this.onAfterFirstLayout,
      30           3 :   }) : super(key: key);
      31             : 
      32             :   /// callback that must return the widget child of the ProviderListener
      33             :   final _Builder<T> builder;
      34             : 
      35             :   /// provider to listen the changes
      36             :   final ListeneableProvider<T> provider;
      37             : 
      38             :   /// callback to listen the new events
      39             :   final _ProviderListenerCallback<T>? onChange;
      40             : 
      41             :   /// callback when initState is called
      42             :   final _ProviderListenerCallback<T>? onInitState;
      43             : 
      44             :   /// this callback will be called when the first frame was rendered
      45             :   /// use this callback if you want to show a dialog, snackbar or navigate
      46             :   /// after the first frame
      47             :   final _ProviderListenerCallback<T>? onAfterFirstLayout;
      48             : 
      49             :   /// callback when dispose is called
      50             :   final _ProviderListenerCallback<T>? onDispose;
      51             : 
      52           3 :   @override
      53           3 :   _ProviderListenerState createState() => _ProviderListenerState<T>();
      54             : }
      55             : 
      56             : class _ProviderListenerState<T extends BaseNotifier>
      57             :     extends State<ProviderListener<T>> {
      58             :   /// the notifier attached to widget.provider
      59             :   late T _notifier;
      60             :   Target? _target;
      61             :   void Function(dynamic)? _listener;
      62             : 
      63           3 :   ListeneableNotifier get _listeneableNotifier =>
      64           3 :       _notifier as ListeneableNotifier;
      65             : 
      66           3 :   @override
      67             :   void initState() {
      68           3 :     super.initState();
      69             : 
      70          16 :     _target = widget.provider is Target ? widget.provider as Target : null;
      71             : 
      72           3 :     if (_target != null) {
      73             :       /// read and save the provider
      74           6 :       _notifier = _target!.notifier;
      75             :     } else {
      76           4 :       _notifier = (widget.provider as BaseProvider).read;
      77             :     }
      78             : 
      79             :     /// check if the onChange callback is defined
      80           9 :     if (widget.onChange != null && _target == null) {
      81             :       // add a listener for the current notifier
      82           2 :       _listener = _defaultListener;
      83           3 :       (_notifier as ListeneableNotifier).addListener(_listener!);
      84           6 :     } else if (widget.onChange != null && _target != null) {
      85           2 :       _buildTargetListener();
      86             :     }
      87             : 
      88             :     // check if the onInitState callback needs to be called
      89           6 :     if (widget.onInitState != null) {
      90           5 :       widget.onInitState!(context, _notifier);
      91             :     }
      92             : 
      93             :     // check if the onAfterFirstLayout callback needs to be called
      94           6 :     if (widget.onAfterFirstLayout != null) {
      95             :       // wait after first frame
      96           5 :       ambiguate(WidgetsBinding.instance)?.endOfFrame.then((_) {
      97           1 :         if (mounted) {
      98           5 :           widget.onAfterFirstLayout!(context, _notifier);
      99             :         }
     100             :       });
     101             :     }
     102             :   }
     103             : 
     104             :   /// listen when the widget is disposed
     105             :   /// and remove the listeners
     106           3 :   @override
     107             :   void dispose() {
     108           9 :     if (widget.onChange != null && _listener != null) {
     109           9 :       _listeneableNotifier.removeListener(_listener!);
     110             :     }
     111             : 
     112             :     // check if the onDispose callback
     113             :     // needs to be called
     114           6 :     if (widget.onDispose != null) {
     115           3 :       widget.onDispose!(
     116           1 :         context,
     117           1 :         _notifier,
     118             :       );
     119             :     }
     120           3 :     super.dispose();
     121             :   }
     122             : 
     123             :   /// listen when the widget is updated
     124             :   /// due to the properties has changes or for hot reaload
     125           1 :   @override
     126             :   void didUpdateWidget(covariant ProviderListener<T> oldWidget) {
     127           1 :     if (_listener != null) {
     128           3 :       if (oldWidget.onChange == null && widget.onChange != null) {
     129           3 :         _listeneableNotifier.addListener(_listener!);
     130           3 :       } else if (oldWidget.onChange != null && widget.onChange == null) {
     131           3 :         _listeneableNotifier.removeListener(_listener!);
     132             :       }
     133             :     }
     134           1 :     super.didUpdateWidget(oldWidget);
     135             :   }
     136             : 
     137             :   /// listen all notify events of one notifier
     138             :   /// and call to onChange callback
     139           3 :   void _defaultListener(_) {
     140           6 :     if (widget.onChange != null) {
     141             :       // before call onChange we need to check
     142             :       // if the widget is mounted
     143           3 :       if (mounted) {
     144          15 :         widget.onChange!(context, _notifier);
     145             :       }
     146             :     }
     147             :   }
     148             : 
     149           2 :   void _buildTargetListener() {
     150           2 :     assert(_target != null);
     151           8 :     _target!.rebuild = () => _defaultListener(null);
     152             : 
     153           4 :     if (_notifier is SimpleNotifier) {
     154           3 :       if (_target!.filter == Filter.select) {
     155           2 :         createSimpleSelectListener(_target!);
     156             :       }
     157             :     } else {
     158           3 :       if (_target!.filter == Filter.select) {
     159           2 :         createStateSelectListener(_target!);
     160             :       } else {
     161           2 :         createWhenListener(_target!);
     162             :       }
     163             :     }
     164           6 :     _listener = _target!.listener;
     165           6 :     _listeneableNotifier.addListener(_listener!);
     166             :   }
     167             : 
     168           3 :   @override
     169             :   Widget build(BuildContext context) {
     170          12 :     return widget.builder(context, _notifier);
     171             :   }
     172             : }

Generated by: LCOV version 1.16