LCOV - code coverage report
Current view: top level - lib/consumer - consumer_widget.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 52 52 100.0 %
Date: 2023-10-11 10:27:27 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/foundation.dart';
       2             : import 'package:flutter/material.dart';
       3             : import 'package:flutter/widgets.dart';
       4             : 
       5             : import '../notifiers/state_notifier.dart';
       6             : import '../provider/filters.dart';
       7             : import '../provider/state_notifier_provider.dart';
       8             : 
       9             : part 'consumer.dart';
      10             : 
      11             : typedef _ListenerCallback<T> = void Function(T);
      12             : 
      13             : /// A [StatefulWidget] that can read providers.
      14             : abstract class ConsumerStatefulWidget extends StatefulWidget {
      15           5 :   const ConsumerStatefulWidget({Key? key}) : super(key: key);
      16             : 
      17             :   @override
      18             :   // ignore: no_logic_in_create_state
      19             :   ConsumerState createState();
      20             : 
      21           2 :   @override
      22             :   ConsumerStatefulElement createElement() {
      23           2 :     return ConsumerStatefulElement(this);
      24             :   }
      25             : }
      26             : 
      27             : /// A [State] that has access to a [BuilderRef] through [ref], allowing
      28             : /// it to read providers.
      29             : abstract class ConsumerState<T extends ConsumerStatefulWidget>
      30             :     extends State<T> {
      31             :   /// An object that allows widgets to interact with providers.
      32             :   late final BuilderRef ref = context as BuilderRef;
      33             : }
      34             : 
      35             : class ConsumerStatefulElement extends StatefulElement implements BuilderRef {
      36           4 :   ConsumerStatefulElement(StatefulWidget widget) : super(widget);
      37             : 
      38             :   Map<StateNotifier, Function> _builders = {};
      39             :   Map<StateNotifier, Function> _listeners = {};
      40             :   Map<StateNotifier, Function> _selectListeners = {};
      41             :   Map<StateNotifier, Function> _whenListeners = {};
      42             : 
      43             :   Map<StateNotifier, BaseStateNotifierProvider> _targets = {};
      44             : 
      45             :   // initialized at true for the first build
      46             :   bool _isExternalBuild = true;
      47             : 
      48             :   bool _mounted = true;
      49             :   bool _init = false;
      50             : 
      51             :   @override // coverage:ignore-line
      52             :   void didChangeDependencies() {
      53             :     super.didChangeDependencies(); // coverage:ignore-line
      54             :     _isExternalBuild = true; // coverage:ignore-line
      55             :   }
      56             : 
      57           2 :   @override
      58             :   void mount(Element? parent, Object? newSlot) {
      59           2 :     super.mount(parent, newSlot);
      60           2 :     _init = true;
      61             :   }
      62             : 
      63             :   /// force the widget update
      64           1 :   void _rebuild() {
      65           1 :     if (_mounted) {
      66           1 :       markNeedsBuild();
      67             :     }
      68             :   }
      69             : 
      70           2 :   @override
      71             :   void unmount() {
      72           2 :     _mounted = false;
      73           2 :     _clearDependencies();
      74           2 :     super.unmount();
      75             :   }
      76             : 
      77             :   /// clear the listeners for this widget
      78           2 :   void _clearDependencies() {
      79           2 :     void clearListeners(Map<StateNotifier, Function> map) {
      80           4 :       for (final e in map.entries) {
      81           4 :         if (!e.key.disposed) {
      82           6 :           (e.key as dynamic).removeListener(e.value);
      83             :         }
      84             :       }
      85           2 :       map.clear();
      86             :     }
      87             : 
      88           4 :     clearListeners(_builders);
      89           4 :     clearListeners(_listeners);
      90           4 :     clearListeners(_selectListeners);
      91           4 :     clearListeners(_whenListeners);
      92             : 
      93           4 :     _targets.clear();
      94             :   }
      95             : 
      96           1 :   @override
      97             :   N listen<N extends StateNotifier<S>, S>(
      98             :     BaseStateNotifierProvider<N, S> providerOrFilter, {
      99             :     required void Function(N notifier) callback,
     100             :     String? tag,
     101             :   }) {
     102           1 :     return _buildWatcher(
     103             :       providerOrFilter: providerOrFilter,
     104             :       tag: tag,
     105             :       isListener: true,
     106           1 :       callback: (notifier) {
     107           2 :         if (_init && mounted) {
     108           1 :           callback(notifier);
     109             :         }
     110             :       },
     111             :     );
     112             :   }
     113             : 
     114             :   /// read a Notifier from one provider and subscribe the widget to the changes of this Notifier.
     115             :   ///
     116             :   /// [providerOrTarget] this param is required to decide when the Consumer
     117             :   /// needs to be rebuilded, if [providerOrTarget] is a [SimpleProvider] or a
     118             :   /// [StateProvider] the  widget will be rebuilded when the notify method is called
     119             :   /// inside a SimpleNotifier or StateNotifier.
     120             :   ///
     121             :   /// If [providerOrTarget] is a value gotten from .select, .ids or .when
     122             :   /// the  widget only will be rebuilded depending of the condition of each method.
     123           1 :   @override
     124             :   N watch<N extends StateNotifier<S>, S>(
     125             :     BaseStateNotifierProvider<N, S> providerOrFilter, {
     126             :     String? tag,
     127             :   }) {
     128           1 :     return _buildWatcher(
     129             :       providerOrFilter: providerOrFilter,
     130             :       tag: tag,
     131             :       isListener: false,
     132           2 :       callback: (_) => _rebuild(),
     133             :     ); // coverage:ignore-line
     134             :   }
     135             : 
     136             :   /// read a Notifier from one provider and subscribe the widget to the changes of this Notifier.
     137             :   ///
     138             :   /// [target] is a value gotten from .select or .when
     139             :   ///
     140             :   /// the  widget only will be rebuilded depending of the condition of each method.
     141           1 :   @override
     142             :   R select<N extends StateNotifier<S>, S, R>(
     143             :     SelectFilteredProvider<N, S, R> filter,
     144             :   ) {
     145             :     // if the widget was rebuilded
     146           1 :     if (_isExternalBuild) {
     147           1 :       _clearDependencies();
     148             :     }
     149           1 :     _isExternalBuild = false;
     150           1 :     final notifier = filter.notifier;
     151             : 
     152           2 :     final insideDependencies = _builders.containsKey(notifier);
     153             :     // if there is not a listener for the current provider
     154             :     if (!insideDependencies) {
     155           3 :       filter.reaction = (_) => _rebuild();
     156           1 :       filter.createListener();
     157             :       // add the listener to the current notifier
     158           3 :       _builders[notifier] = filter.listener;
     159           2 :       _targets[notifier] = filter;
     160           2 :       notifier.addListener(filter.listener);
     161             :     }
     162           2 :     return (_targets[notifier] as SelectFilteredProvider)
     163             :         .selectValue; // coverage:ignore-line
     164             :   }
     165             : 
     166             : // coverage:ignore-start
     167             :   @override
     168             :   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     169             :     super.debugFillProperties(properties);
     170             :     properties.add(
     171             :       DiagnosticsProperty(
     172             :         '_notifiers',
     173             :         _builders.keys.map((e) => e.runtimeType.toString()),
     174             :       ),
     175             :     );
     176             :   }
     177             :   // coverage:ignore-end
     178             : }
     179             : 
     180             : /// A interface that must be implemented in the ConsumerWidget
     181             : abstract class BuilderRef {
     182             :   /// A function to read SimpleProvider or a StateProvider and subscribe to the events.
     183             :   ///
     184             :   /// this method returns the Notifier linked to the provider
     185             :   N listen<N extends StateNotifier<S>, S>(
     186             :     BaseStateNotifierProvider<N, S> providerOrFilter, {
     187             :     required void Function(N notifier) callback,
     188             :     String? tag,
     189             :   });
     190             : 
     191             :   /// A function to read SimpleProvider or a StateProvider and subscribe to the events.
     192             :   ///
     193             :   /// this method returns the Notifier linked to the provider
     194             :   N watch<N extends StateNotifier<S>, S>(
     195             :     BaseStateNotifierProvider<N, S> providerOrFilter, {
     196             :     String? tag,
     197             :   });
     198             : 
     199             :   /// A function to read SimpleProvider or a StateProvider and subscribe to the events.
     200             :   ///
     201             :   /// this method returns the value returned by the select or when methods
     202             :   R select<N extends StateNotifier<S>, S, R>(
     203             :     SelectFilteredProvider<N, S, R> filter,
     204             :   );
     205             : }
     206             : 
     207             : /// {@template meedu.consumerwidget}
     208             : /// A base-class for widgets that wants to listen to providers
     209             : /// ```dart
     210             : /// class Example extends ConsumerWidget {
     211             : ///   const Example({Key? key}): super(key: key);
     212             : ///
     213             : ///   @override
     214             : ///   Widget build(BuildContext context, ref) {
     215             : ///     final value = ref.watch(myProvider);
     216             : ///     return YOUR_WIDGET;
     217             : ///   }
     218             : /// }
     219             : /// ```
     220             : /// {@endtemplate}
     221             : abstract class ConsumerWidget extends ConsumerStatefulWidget {
     222             :   // ignore: public_member_api_docs
     223           5 :   const ConsumerWidget({Key? key}) : super(key: key);
     224             : 
     225             :   // ignore: public_member_api_docs
     226             :   Widget build(BuildContext context, BuilderRef ref);
     227             : 
     228           2 :   @override
     229             :   // ignore: library_private_types_in_public_api
     230           2 :   _ConsumerState createState() => _ConsumerState();
     231             : }
     232             : 
     233             : class _ConsumerState<T extends ConsumerWidget>
     234             :     extends ConsumerState<ConsumerWidget> {
     235             :   /// An object that allows widgets to interact with providers.
     236           2 :   @override
     237           2 :   BuilderRef get ref => context as BuilderRef;
     238             : 
     239           2 :   @override
     240             :   Widget build(BuildContext context) {
     241           6 :     return widget.build(context, ref);
     242             :   }
     243             : }

Generated by: LCOV version 1.16