LCOV - code coverage report
Current view: top level - src - property_change_provider.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 42 42 100.0 %
Date: 2019-12-19 10:35:55 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/widgets.dart';
       2             : import 'package:property_change_notifier/property_change_notifier.dart';
       3             : 
       4             : /// An [InheritedWidget] that provides access to a [PropertyChangeNotifier] to descendant widgets.
       5             : /// The type parameter [T] is the type of the [PropertyChangeNotifier] subclass.
       6             : ///
       7             : /// A descendant widget can access the model instance by using the following syntax.
       8             : /// This will automatically register the widget to be rebuilt whenever any property changes on the model:
       9             : /// ```dart
      10             : /// final model = PropertyChangeProvider.of<MyModel>(context).value;
      11             : /// ```
      12             : ///
      13             : /// To access the properties that were changed in the current build frame, use the following syntax.
      14             : /// ```dart
      15             : /// final properties = PropertyChangeProvider.of<MyModel>(context).properties;
      16             : /// ```
      17             : ///
      18             : /// To register the widget to be rebuilt only on specific property changes, provide a [properties] parameter:
      19             : /// ```dart
      20             : /// final model = PropertyChangeProvider.of<MyModel>(context, properties: ['foo', 'bar']).value;
      21             : /// ```
      22             : ///
      23             : /// To access the model without registering the widget to be rebuilt, provide a [listen] parameter with a value of false:
      24             : /// ```dart
      25             : /// final model = PropertyChangeProvider.of<MyModel>(context, listen: false).value;
      26             : /// ```
      27             : class PropertyChangeProvider<T extends PropertyChangeNotifier> extends StatefulWidget {
      28             :   /// Retrieves the [PropertyChangeModel] from the nearest ancestor [PropertyChangeProvider].
      29             :   /// If [listen] is true (which is the default), the calling widget will also be rebuilt
      30             :   /// whenever the ancestor's [PropertyChangeNotifier] model changes. To only rebuild
      31             :   /// for certain properties, provide them in the [properties] parameter.
      32             :   /// If [listen] is false, the [properties] parameter must be null or empty.
      33           2 :   static PropertyChangeModel<T> of<T extends PropertyChangeNotifier>(
      34             :     BuildContext context, {
      35             :     Iterable<Object> properties,
      36             :     bool listen = true,
      37             :   }) {
      38           1 :     assert(listen || properties == null, "Don't provide properties if you're not going to listen to them.");
      39             : 
      40           1 :     final typeOf = <T>() => T;
      41             : 
      42           2 :     final nullCheck = (InheritedModel model) {
      43           4 :       assert(model != null, 'Could not find an ancestor PropertyChangeProvider<$T>');
      44             :       return model;
      45             :     };
      46             : 
      47             :     if (!listen) {
      48           1 :       final type = typeOf<PropertyChangeModel<T>>();
      49           2 :       return nullCheck(context.ancestorWidgetOfExactType(type) as PropertyChangeModel);
      50             :     }
      51             : 
      52           2 :     if (properties == null || properties.isEmpty) {
      53           4 :       return nullCheck(InheritedModel.inheritFrom<PropertyChangeModel<T>>(context));
      54             :     }
      55             : 
      56             :     InheritedModel widget;
      57           4 :     for (final property in properties) {
      58           2 :       widget = InheritedModel.inheritFrom<PropertyChangeModel<T>>(context, aspect: property);
      59             :     }
      60             : 
      61           2 :     return nullCheck(widget);
      62             :   }
      63             : 
      64             :   /// Creates a [PropertyChangeProvider] that can be accessed by descendant widgets.
      65           2 :   PropertyChangeProvider({
      66             :     Key key,
      67             :     @required this.value,
      68             :     @required this.child,
      69           1 :   })  : assert(value != null),
      70           1 :         assert(child != null),
      71           2 :         super(key: key);
      72             : 
      73             :   /// The instance of [T] to provide to descendant widgets.
      74             :   final T value;
      75             : 
      76             :   /// The widget below this widget in the tree.
      77             :   ///
      78             :   /// {@macro flutter.widgets.child}
      79             :   final Widget child;
      80             : 
      81           2 :   @override
      82           2 :   _PropertyChangeProviderState createState() => _PropertyChangeProviderState<T>();
      83             : }
      84             : 
      85             : /// The companion [State] object to [PropertyChangeProvider]. For private use only.
      86             : /// Subscribes as a global listener to the [PropertyChangeNotifier] instance at [widget].[value].
      87             : /// Rebuilds whenever a property is changed and creates a new [PropertyChangeModel] with a reference
      88             : /// to itself so it can access the original model instance and changed property names.
      89             : class _PropertyChangeProviderState<T extends PropertyChangeNotifier> extends State<PropertyChangeProvider<T>> {
      90             :   Set<Object> _properties = {};
      91             : 
      92           2 :   @override
      93             :   void initState() {
      94           2 :     super.initState();
      95           8 :     widget.value.addListener(_listener);
      96             :   }
      97             : 
      98           2 :   @override
      99             :   void dispose() {
     100           8 :     widget.value.removeListener(_listener);
     101           2 :     super.dispose();
     102             :   }
     103             : 
     104           2 :   @override
     105             :   Widget build(BuildContext context) {
     106           2 :     return PropertyChangeModel<T>(
     107             :       state: this,
     108           4 :       child: widget.child,
     109             :     );
     110             :   }
     111             : 
     112           2 :   void _listener(Object property) {
     113           4 :     setState(() {
     114           2 :       _addProperty(property);
     115             :     });
     116             :   }
     117             : 
     118           2 :   void _addProperty(Object property) {
     119           2 :     final element = this.context as StatefulElement;
     120           2 :     if (element.dirty) {
     121           2 :       _properties.add(property);
     122             :     } else {
     123           2 :       _properties = {property};
     124             :     }
     125             :   }
     126             : }
     127             : 
     128             : /// The [InheritedModel] subclass that is rebuilt by [_PropertyChangeProviderState]
     129             : /// whenever its [PropertyChangeNotifier] is updated. Notifies dependents when the
     130             : /// names of the changed properties intersect with the list of properties provided
     131             : /// to the [PropertyChangeProvider].[of] method.
     132             : /// The type parameter [T] is the type of the [PropertyChangeNotifier] subclass.
     133             : class PropertyChangeModel<T extends PropertyChangeNotifier> extends InheritedModel {
     134             :   final _PropertyChangeProviderState _state;
     135             : 
     136           2 :   PropertyChangeModel({
     137             :     Key key,
     138             :     _PropertyChangeProviderState state,
     139             :     Widget child,
     140             :   })  : _state = state,
     141           2 :         super(key: key, child: child);
     142             : 
     143             :   /// The instance of [T] originally provided to the [PropertyChangeProvider] constructor.
     144           8 :   T get value => _state.widget.value;
     145             : 
     146             :   /// The names of the properties on the [value] instance that were changed in the current build frame.
     147           6 :   Set<Object> get properties => _state._properties;
     148             : 
     149           2 :   @override
     150             :   bool updateShouldNotify(PropertyChangeModel oldWidget) {
     151             :     return true;
     152             :   }
     153             : 
     154           2 :   @override
     155             :   bool updateShouldNotifyDependent(PropertyChangeModel<T> oldWidget, Set<Object> aspects) {
     156           8 :     return aspects.intersection(_state._properties).isNotEmpty;
     157             :   }
     158             : }

Generated by: LCOV version 1.14