1
part of 'provider.dart';
2

3
/// A function that returns true when the update from [previous] to [current]
4
/// should notify listeners, if any.
5
///
6
/// See also:
7
///
8
///   * [InheritedWidget.updateShouldNotify]
9
typedef UpdateShouldNotify<T> = bool Function(T previous, T current);
10

11
/// A function that creates an object of type [T].
12
///
13
/// See also:
14
///
15
///  * [Dispose], to free the resources associated to the value created.
16
typedef Create<T> = T Function(BuildContext context);
17

18
/// A function that disposes an object of type [T].
19
///
20
/// See also:
21
///
22
///  * [Create], to create a value that will later be disposed of.
23
typedef Dispose<T> = void Function(BuildContext context, T value);
24

25
/// A callback used to start the listening of an object and return a function
26
/// that cancels the subscription.
27
///
28
/// It is called the first time the value is obtained (through
29
/// [InheritedContext.value]). And the returned callback will be called
30
/// when [InheritedProvider] is unmounted or when the it is rebuilt with a new
31
/// value.
32
///
33
/// See also:
34
///
35
/// - [InheritedProvider]
36
/// - [DeferredStartListening], a variant of this typedef for more advanced
37
///   listening.
38
typedef StartListening<T> = VoidCallback Function(
39
    InheritedContext<T> element, T value);
40

41
/// A generic implementation of an [InheritedWidget].
42
///
43
/// Any descendant of this widget can obtain `value` using [Provider.of].
44
///
45
/// Do not use this class directly unless you are creating a custom "Provider".
46
/// Instead use [Provider] class, which wraps [InheritedProvider].
47
///
48
/// See also:
49
///
50
///  - [DeferredInheritedProvider], a variant of this object where the provided
51
///    object and the created object are two different entity.
52
class InheritedProvider<T> extends SingleChildStatelessWidget {
53
  /// Creates a value, then expose it to its descendants.
54
  ///
55
  /// The value will be disposed of when [InheritedProvider] is removed from
56
  /// the widget tree.
57 3
  InheritedProvider({
58
    Key key,
59
    Create<T> create,
60
    T update(BuildContext context, T value),
61
    UpdateShouldNotify<T> updateShouldNotify,
62
    void Function(T value) debugCheckInvalidValueType,
63
    StartListening<T> startListening,
64
    Dispose<T> dispose,
65
    this.builder,
66
    bool lazy,
67
    Widget child,
68
  })  : _lazy = lazy,
69 3
        _delegate = _CreateInheritedProvider(
70
          create: create,
71
          update: update,
72
          updateShouldNotify: updateShouldNotify,
73
          debugCheckInvalidValueType: debugCheckInvalidValueType,
74
          startListening: startListening,
75
          dispose: dispose,
76
        ),
77 3
        super(key: key, child: child);
78

79
  /// Expose to its descendants an existing value,
80 3
  InheritedProvider.value({
81
    Key key,
82
    @required T value,
83
    UpdateShouldNotify<T> updateShouldNotify,
84
    StartListening<T> startListening,
85
    bool lazy,
86
    this.builder,
87
    Widget child,
88
  })  : _lazy = lazy,
89 3
        _delegate = _ValueInheritedProvider(
90
          value: value,
91
          updateShouldNotify: updateShouldNotify,
92
          startListening: startListening,
93
        ),
94 3
        super(key: key, child: child);
95

96 3
  InheritedProvider._constructor({
97
    Key key,
98
    _Delegate<T> delegate,
99
    bool lazy,
100
    this.builder,
101
    Widget child,
102
  })  : _lazy = lazy,
103
        _delegate = delegate,
104 3
        super(key: key, child: child);
105

106
  final _Delegate<T> _delegate;
107
  final bool _lazy;
108

109
  /// Syntax sugar for obtaining a [BuildContext] that can read the provider
110
  /// created.
111
  ///
112
  /// This code:
113
  ///
114
  /// ```dart
115
  /// Provider<int>(
116
  ///   create: (context) => 42,
117
  ///   builder: (context, child) {
118
  ///     final value = context.watch<int>();
119
  ///     return Text('$value');
120
  ///   }
121
  /// )
122
  /// ```
123
  ///
124
  /// is strictly equivalent to:
125
  ///
126
  /// ```dart
127
  /// Provider<int>(
128
  ///   create: (context) => 42,
129
  ///   child: Builder(
130
  ///     builder: (context) {
131
  ///       final value = context.watch<int>();
132
  ///       return Text('$value');
133
  ///     },
134
  ///   ),
135
  /// )
136
  /// ```
137
  ///
138
  /// For an explanation on the `child` parameter that `builder` receives,
139
  /// see the "Performance optimizations" section of [AnimatedBuilder].
140
  final TransitionBuilder builder;
141

142 3
  @override
143
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
144 3
    super.debugFillProperties(properties);
145 3
    _delegate.debugFillProperties(properties);
146
  }
147

148 3
  @override
149
  _InheritedProviderElement<T> createElement() {
150 3
    return _InheritedProviderElement<T>(this);
151
  }
152

153 3
  @override
154
  Widget buildWithChild(BuildContext context, Widget child) {
155
    assert(
156 3
      builder != null || child != null,
157 3
      '$runtimeType used outside of MultiProvider must specify a child',
158
    );
159 3
    return _InheritedProviderScope<T>(
160
      owner: this,
161 3
      child: builder != null
162 3
          ? Builder(
163 3
              builder: (context) => builder(context, child),
164
            )
165
          : child,
166
    );
167
  }
168
}
169

170
class _InheritedProviderElement<T> extends SingleChildStatelessElement {
171 3
  _InheritedProviderElement(InheritedProvider<T> widget) : super(widget);
172

173 3
  @override
174
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
175 3
    super.debugFillProperties(properties);
176 3
    visitChildren((e) => e.debugFillProperties(properties));
177
  }
178
}
179

180
bool _debugIsSelecting = false;
181

182
/// Adds a `select` method on [BuildContext].
183
extension SelectContext on BuildContext {
184
  /// Watch a value of type [T] exposed from a provider, and listen only partially
185
  /// to changes.
186
  ///
187
  /// [select] must be used only inside the `build` method of a widget.
188
  /// It will not work inside other life-cycles, including [State.didChangeDependencies].
189
  ///
190
  /// By using [select], instead of watching the entire object, the listener will
191
  /// rebuild only if the value returned by `selector` changes.
192
  ///
193
  /// When a provider emits an update, it will call synchronously all `selector`.
194
  ///
195
  /// Then, if they return a value different from the previously returned value,
196
  /// the dependent will be marked as needing to rebuild.
197
  ///
198
  /// For example, consider the following object:
199
  ///
200
  /// ```dart
201
  /// class Person with ChangeNotifier {
202
  ///   String name;
203
  ///   int age;
204
  ///
205
  ///   // Add some logic that may update `name` and `age`
206
  /// }
207
  /// ```
208
  ///
209
  /// Then a widget may want to listen to a person's `name` without listening
210
  /// to its `age`.
211
  ///
212
  /// This cannot be done using `context.watch`/[Provider.of]. Instead, we
213
  /// can use [select], by writing the following:
214
  ///
215
  /// ```dart
216
  /// Widget build(BuildContext context) {
217
  ///   final name = context.select((Person p) => p.name);
218
  ///
219
  ///   return Text(name);
220
  /// }
221
  /// ```
222
  ///
223
  /// It is fine to call `select` multiple times.
224 3
  R select<T, R>(R selector(T value)) {
225 3
    assert(widget is! SliverWithKeepAliveWidget, '''
226
    Tried to use context.select inside a SliverList/SliderGridView.
227

228
    This is likely a mistake, as instead of rebuilding only the item that cares
229
    about the selected value, this would rebuild the entire list/grid.
230

231
    To fix, add a `Builder` or extract the content of `itemBuilder` in a separate widget:
232

233
    ```dart
234
    ListView.builder(
235
      itemBuilder: (context, index) {
236
        return Builder(builder: (context) {
237
          final todo = context.select((TodoList list) => list[index]);
238
          return Text(todo.name);
239
        });
240
      },
241
    );
242
    ```
243
    ''');
244 3
    assert(widget is LayoutBuilder || debugDoingBuild, '''
245
Tried to use `context.select` outside of the `build` method of a widget.
246

247
Any usage other than inside the `build` method of a widget are not supported.
248
''');
249 3
    final inheritedElement = Provider._inheritedElementOf<T>(this);
250
    try {
251 3
      var value = inheritedElement.value;
252 3
      assert(() {
253
        _debugIsSelecting = true;
254
        return true;
255 3
      }());
256 3
      final selected = selector(value);
257 3
      dependOnInheritedElement(
258
        inheritedElement,
259 3
        aspect: (T newValue) => !const DeepCollectionEquality()
260 3
            .equals(selector(newValue), selected),
261
      );
262
      return selected;
263
    } finally {
264 3
      assert(() {
265
        _debugIsSelecting = false;
266
        return true;
267 3
      }());
268
    }
269
  }
270
}
271

272
/// A [BuildContext] associated to an [InheritedProvider].
273
///
274
/// It an extra [markNeedsNotifyDependents] method and the exposed value.
275
abstract class InheritedContext<T> extends BuildContext {
276
  /// The current value exposed by [InheritedProvider].
277
  ///
278
  /// This property is lazy loaded, and reading it the first time may trigger
279
  /// some side-effects such as creating a [T] instance or start a subscription.
280
  T get value;
281

282
  /// Marks the [InheritedProvider] as needing to update dependents.
283
  ///
284
  /// This bypass [InheritedWidget.updateShouldNotify] and will force widgets
285
  /// that depends on [T] to rebuild.
286
  void markNeedsNotifyDependents();
287

288
  /// Wether `setState` was called at least once or not.
289
  ///
290
  /// It can be used by [DeferredStartListening] to differentiate between the
291
  /// very first listening, and a rebuild after `controller` changed.
292
  bool get hasValue;
293
}
294

295
class _InheritedProviderScope<T> extends InheritedWidget {
296 3
  _InheritedProviderScope({
297
    this.owner,
298
    @required Widget child,
299 3
  }) : super(child: child);
300

301
  final InheritedProvider<T> owner;
302

303 3
  @override
304
  bool updateShouldNotify(InheritedWidget oldWidget) {
305
    return false;
306
  }
307

308 3
  @override
309
  _InheritedProviderScopeElement<T> createElement() {
310 3
    return _InheritedProviderScopeElement<T>(this);
311
  }
312
}
313

314
class _Dependency<T> {
315
  bool shouldClearSelectors = false;
316
  bool shouldClearMutationScheduled = false;
317
  final selectors = <_SelectorAspect<T>>[];
318
}
319

320
class _InheritedProviderScopeElement<T> extends InheritedElement
321
    implements InheritedContext<T> {
322 3
  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
323 3
      : super(widget);
324

325
  bool _shouldNotifyDependents = false;
326
  bool _debugInheritLocked = false;
327
  bool _isNotifyDependentsEnabled = true;
328
  bool _firstBuild = true;
329
  bool _updatedShouldNotify = false;
330
  bool _isBuildFromExternalSources = false;
331
  _DelegateState<T, _Delegate<T>> _delegateState;
332

333 3
  @override
334
  _InheritedProviderScope<T> get widget =>
335 3
      super.widget as _InheritedProviderScope<T>;
336

337 3
  @override
338
  void reassemble() {
339 3
    super.reassemble();
340

341 3
    final value = _delegateState.hasValue ? _delegateState.value : null;
342 3
    if (value is ReassembleHandler) {
343 3
      value.reassemble();
344
    }
345
  }
346

347 3
  @override
348
  void updateDependencies(Element dependent, Object aspect) {
349 3
    final dependencies = getDependencies(dependent);
350
    // once subscribed to everything once, it always stays subscribed to everything
351 3
    if (dependencies != null && dependencies is! _Dependency<T>) {
352
      return;
353
    }
354

355 3
    if (aspect is _SelectorAspect<T>) {
356
      final selectorDependency =
357 3
          (dependencies ?? _Dependency<T>()) as _Dependency<T>;
358

359 3
      if (selectorDependency.shouldClearSelectors) {
360 3
        selectorDependency.shouldClearSelectors = false;
361 3
        selectorDependency.selectors.clear();
362
      }
363 3
      if (selectorDependency.shouldClearMutationScheduled == false) {
364 3
        selectorDependency.shouldClearMutationScheduled = true;
365 3
        SchedulerBinding.instance.addPostFrameCallback((_) {
366
          selectorDependency
367 3
            ..shouldClearMutationScheduled = false
368 3
            ..shouldClearSelectors = true;
369
        });
370
      }
371 3
      selectorDependency.selectors.add(aspect);
372 3
      setDependencies(dependent, selectorDependency);
373
    } else {
374
      // subscribes to everything
375 3
      setDependencies(dependent, const Object());
376
    }
377
  }
378

379 3
  @override
380
  void notifyDependent(InheritedWidget oldWidget, Element dependent) {
381 3
    final dependencies = getDependencies(dependent);
382

383
    var shouldNotify = false;
384
    if (dependencies != null) {
385 3
      if (dependencies is _Dependency<T>) {
386
        // select can never be used inside `didChangeDependencies`, so if the
387
        // dependent is already marked as needed build, there is no point
388
        // in executing the selectors.
389 3
        if (dependent.dirty) {
390
          return;
391
        }
392

393 3
        for (final updateShouldNotify in dependencies.selectors) {
394
          try {
395 3
            assert(() {
396
              _debugIsSelecting = true;
397
              return true;
398 3
            }());
399 3
            shouldNotify = updateShouldNotify(value);
400
          } finally {
401 3
            assert(() {
402
              _debugIsSelecting = false;
403
              return true;
404 3
            }());
405
          }
406
          if (shouldNotify) {
407
            break;
408
          }
409
        }
410
      } else {
411
        shouldNotify = true;
412
      }
413
    }
414

415
    if (shouldNotify) {
416 3
      dependent.didChangeDependencies();
417
    }
418
  }
419

420 3
  @override
421
  void performRebuild() {
422 3
    if (_firstBuild) {
423 3
      _firstBuild = false;
424 3
      _delegateState = widget.owner._delegate.createState()..element = this;
425
    }
426 3
    super.performRebuild();
427
  }
428

429 3
  @override
430
  void update(_InheritedProviderScope<T> newWidget) {
431 3
    assert(() {
432 3
      if (widget.owner._delegate.runtimeType !=
433 3
          newWidget.owner._delegate.runtimeType) {
434 3
        throw StateError('''Rebuilt $widget using a different constructor.
435
      
436
This is likely a mistake and is unsupported.
437
If you're in this situation, consider passing a `key` unique to each individual constructor.
438 3
''');
439
      }
440
      return true;
441 3
    }());
442

443 3
    _isBuildFromExternalSources = true;
444 3
    _updatedShouldNotify =
445 3
        _delegateState.willUpdateDelegate(newWidget.owner._delegate);
446 3
    super.update(newWidget);
447 3
    _updatedShouldNotify = false;
448
  }
449

450 3
  @override
451
  void updated(InheritedWidget oldWidget) {
452 3
    super.updated(oldWidget);
453 3
    if (_updatedShouldNotify) {
454 3
      notifyClients(oldWidget);
455
    }
456
  }
457

458 3
  @override
459
  void didChangeDependencies() {
460 3
    _isBuildFromExternalSources = true;
461 3
    super.didChangeDependencies();
462
  }
463

464 3
  @override
465
  Widget build() {
466 3
    if (widget.owner._lazy == false) {
467 3
      value; // this will force the value to be computed.
468
    }
469 3
    _delegateState.build(_isBuildFromExternalSources);
470 3
    _isBuildFromExternalSources = false;
471 3
    if (_shouldNotifyDependents) {
472 3
      _shouldNotifyDependents = false;
473 3
      notifyClients(widget);
474
    }
475 3
    return super.build();
476
  }
477

478 3
  @override
479
  void unmount() {
480 3
    _delegateState.dispose();
481 3
    super.unmount();
482
  }
483

484 3
  @override
485 3
  bool get hasValue => _delegateState.hasValue;
486

487 3
  @override
488
  void markNeedsNotifyDependents() {
489 3
    if (!_isNotifyDependentsEnabled) return;
490

491 3
    markNeedsBuild();
492 3
    _shouldNotifyDependents = true;
493
  }
494

495 3
  bool _debugSetInheritedLock(bool value) {
496 3
    assert(() {
497 3
      _debugInheritLocked = value;
498
      return true;
499 3
    }());
500
    return true;
501
  }
502

503 3
  @override
504 3
  T get value => _delegateState.value;
505

506 3
  @override
507
  InheritedWidget dependOnInheritedElement(
508
    InheritedElement ancestor, {
509
    Object aspect,
510
  }) {
511 3
    assert(() {
512 3
      if (_debugInheritLocked) {
513 3
        throw FlutterError.fromParts(
514 3
          <DiagnosticsNode>[
515 3
            ErrorSummary(
516
              'Tried to listen to an InheritedWidget '
517
              'in a life-cycle that will never be called again.',
518
            ),
519 3
            ErrorDescription('''
520
This error typically happens when calling Provider.of with `listen` to `true`,
521
in a situation where listening to the provider doesn't make sense, such as:
522
- initState of a StatefulWidget
523
- the "create" callback of a provider
524

525
This is undesired because these life-cycles are called only once in the
526
lifetime of a widget. As such, while `listen` is `true`, the widget has
527
no mean to handle the update scenario.
528

529
To fix, consider:
530
- passing `listen: false` to `Provider.of`
531
- use a life-cycle that handles updates (like didChangeDependencies)
532
- use a provider that handles updates (like ProxyProvider).
533
'''),
534
          ],
535
        );
536
      }
537
      return true;
538 3
    }());
539 3
    return super.dependOnInheritedElement(ancestor, aspect: aspect);
540
  }
541

542 3
  @override
543
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
544 3
    super.debugFillProperties(properties);
545 3
    _delegateState.debugFillProperties(properties);
546
  }
547
}
548

549
typedef _SelectorAspect<T> = bool Function(T value);
550

551
@immutable
552
abstract class _Delegate<T> {
553
  _DelegateState<T, _Delegate<T>> createState();
554

555 3
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
556
}
557

558
abstract class _DelegateState<T, D extends _Delegate<T>> {
559
  _InheritedProviderScopeElement<T> element;
560

561
  T get value;
562

563 3
  D get delegate => element.widget.owner._delegate as D;
564

565
  bool get hasValue;
566

567 3
  bool debugSetInheritedLock(bool value) {
568 3
    return element._debugSetInheritedLock(value);
569
  }
570

571 3
  bool willUpdateDelegate(D newDelegate) => false;
572

573 3
  void dispose() {}
574

575 3
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
576

577 3
  void build(bool isBuildFromExternalSources) {}
578
}
579

580
class _CreateInheritedProvider<T> extends _Delegate<T> {
581 3
  _CreateInheritedProvider({
582
    this.create,
583
    this.update,
584
    UpdateShouldNotify<T> updateShouldNotify,
585
    this.debugCheckInvalidValueType,
586
    this.startListening,
587
    this.dispose,
588 3
  })  : assert(create != null || update != null),
589
        _updateShouldNotify = updateShouldNotify;
590

591
  final Create<T> create;
592
  final T Function(BuildContext context, T value) update;
593
  final UpdateShouldNotify<T> _updateShouldNotify;
594
  final void Function(T value) debugCheckInvalidValueType;
595
  final StartListening<T> startListening;
596
  final Dispose<T> dispose;
597

598 3
  @override
599
  _CreateInheritedProviderState<T> createState() =>
600 3
      _CreateInheritedProviderState();
601
}
602

603
@visibleForTesting
604
// ignore: public_member_api_docs
605
bool debugIsInInheritedProviderUpdate = false;
606

607
@visibleForTesting
608
// ignore: public_member_api_docs
609
bool debugIsInInheritedProviderCreate = false;
610

611
class _CreateInheritedProviderState<T>
612
    extends _DelegateState<T, _CreateInheritedProvider<T>> {
613
  VoidCallback _removeListener;
614
  bool _didInitValue = false;
615
  T _value;
616
  _CreateInheritedProvider<T> _previousWidget;
617

618 3
  @override
619
  T get value {
620
    bool _debugPreviousIsInInheritedProviderCreate;
621
    bool _debugPreviousIsInInheritedProviderUpdate;
622

623 3
    assert(() {
624
      _debugPreviousIsInInheritedProviderCreate =
625
          debugIsInInheritedProviderCreate;
626
      _debugPreviousIsInInheritedProviderUpdate =
627
          debugIsInInheritedProviderUpdate;
628
      return true;
629 3
    }());
630

631 3
    if (!_didInitValue) {
632 3
      _didInitValue = true;
633 3
      if (delegate.create != null) {
634 3
        assert(debugSetInheritedLock(true));
635
        try {
636 3
          assert(() {
637
            debugIsInInheritedProviderCreate = true;
638
            debugIsInInheritedProviderUpdate = false;
639
            return true;
640 3
          }());
641 3
          _value = delegate.create(element);
642
        } finally {
643 3
          assert(() {
644
            debugIsInInheritedProviderCreate =
645
                _debugPreviousIsInInheritedProviderCreate;
646
            debugIsInInheritedProviderUpdate =
647
                _debugPreviousIsInInheritedProviderUpdate;
648
            return true;
649 3
          }());
650
        }
651 3
        assert(debugSetInheritedLock(false));
652

653 3
        assert(() {
654 3
          delegate.debugCheckInvalidValueType?.call(_value);
655
          return true;
656 3
        }());
657
      }
658 3
      if (delegate.update != null) {
659
        try {
660 3
          assert(() {
661
            debugIsInInheritedProviderCreate = false;
662
            debugIsInInheritedProviderUpdate = true;
663
            return true;
664 3
          }());
665 3
          _value = delegate.update(element, _value);
666
        } finally {
667 3
          assert(() {
668
            debugIsInInheritedProviderCreate =
669
                _debugPreviousIsInInheritedProviderCreate;
670
            debugIsInInheritedProviderUpdate =
671
                _debugPreviousIsInInheritedProviderUpdate;
672
            return true;
673 3
          }());
674
        }
675

676 3
        assert(() {
677 3
          delegate.debugCheckInvalidValueType?.call(_value);
678
          return true;
679 3
        }());
680
      }
681
    }
682

683 3
    element._isNotifyDependentsEnabled = false;
684 3
    _removeListener ??= delegate.startListening?.call(element, _value);
685 3
    element._isNotifyDependentsEnabled = true;
686 3
    assert(delegate.startListening == null || _removeListener != null);
687 3
    return _value;
688
  }
689

690 3
  @override
691
  void dispose() {
692 3
    super.dispose();
693 3
    _removeListener?.call();
694 3
    if (_didInitValue) {
695 3
      delegate.dispose?.call(element, _value);
696
    }
697
  }
698

699 3
  @override
700
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
701 3
    super.debugFillProperties(properties);
702 3
    if (_didInitValue) {
703
      properties
704 3
        ..add(DiagnosticsProperty('value', value))
705 3
        ..add(
706 3
          FlagProperty(
707
            null,
708 3
            value: _removeListener != null,
709
            defaultValue: false,
710
            ifTrue: 'listening to value',
711
          ),
712
        );
713
    } else {
714 3
      properties.add(
715 3
        FlagProperty(
716
          'value',
717
          value: true,
718
          showName: true,
719
          ifTrue: '<not yet loaded>',
720
        ),
721
      );
722
    }
723
  }
724

725 3
  @override
726
  void build(bool isBuildFromExternalSources) {
727
    var shouldNotify = false;
728
    // Don't call `update` unless the build was triggered from `updated`/`didChangeDependencies`
729
    // otherwise `markNeedsNotifyDependents` will trigger unnecessary `update` calls
730
    if (isBuildFromExternalSources &&
731 3
        _didInitValue &&
732 3
        delegate.update != null) {
733 3
      final previousValue = _value;
734

735
      bool _debugPreviousIsInInheritedProviderCreate;
736
      bool _debugPreviousIsInInheritedProviderUpdate;
737 3
      assert(() {
738
        _debugPreviousIsInInheritedProviderCreate =
739
            debugIsInInheritedProviderCreate;
740
        _debugPreviousIsInInheritedProviderUpdate =
741
            debugIsInInheritedProviderUpdate;
742
        return true;
743 3
      }());
744
      try {
745 3
        assert(() {
746
          debugIsInInheritedProviderCreate = false;
747
          debugIsInInheritedProviderUpdate = true;
748
          return true;
749 3
        }());
750 3
        _value = delegate.update(element, _value);
751
      } finally {
752 3
        assert(() {
753
          debugIsInInheritedProviderCreate =
754
              _debugPreviousIsInInheritedProviderCreate;
755
          debugIsInInheritedProviderUpdate =
756
              _debugPreviousIsInInheritedProviderUpdate;
757
          return true;
758 3
        }());
759
      }
760

761 3
      if (delegate._updateShouldNotify != null) {
762 3
        shouldNotify = delegate._updateShouldNotify(previousValue, _value);
763
      } else {
764 3
        shouldNotify = _value != previousValue;
765
      }
766

767
      if (shouldNotify) {
768 3
        assert(() {
769 3
          delegate.debugCheckInvalidValueType?.call(_value);
770
          return true;
771 3
        }());
772 3
        if (_removeListener != null) {
773 3
          _removeListener();
774 3
          _removeListener = null;
775
        }
776 3
        _previousWidget?.dispose?.call(element, previousValue);
777
      }
778
    }
779

780
    if (shouldNotify) {
781 3
      element._shouldNotifyDependents = true;
782
    }
783 3
    _previousWidget = delegate;
784 3
    return super.build(isBuildFromExternalSources);
785
  }
786

787 3
  @override
788 3
  bool get hasValue => _didInitValue;
789
}
790

791
class _ValueInheritedProvider<T> extends _Delegate<T> {
792 3
  _ValueInheritedProvider({
793
    @required this.value,
794
    UpdateShouldNotify<T> updateShouldNotify,
795
    this.startListening,
796
  }) : _updateShouldNotify = updateShouldNotify;
797

798
  final T value;
799
  final UpdateShouldNotify<T> _updateShouldNotify;
800
  final StartListening<T> startListening;
801

802 3
  @override
803
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
804 3
    super.debugFillProperties(properties);
805 3
    properties.add(DiagnosticsProperty('value', value));
806
  }
807

808 3
  @override
809
  _ValueInheritedProviderState<T> createState() {
810 3
    return _ValueInheritedProviderState<T>();
811
  }
812
}
813

814
class _ValueInheritedProviderState<T>
815
    extends _DelegateState<T, _ValueInheritedProvider<T>> {
816
  VoidCallback _removeListener;
817

818 3
  @override
819
  T get value {
820 3
    element._isNotifyDependentsEnabled = false;
821 3
    _removeListener ??= delegate.startListening?.call(element, delegate.value);
822 3
    element._isNotifyDependentsEnabled = true;
823 3
    assert(delegate.startListening == null || _removeListener != null);
824 3
    return delegate.value;
825
  }
826

827 3
  @override
828
  bool willUpdateDelegate(_ValueInheritedProvider<T> newDelegate) {
829
    bool shouldNotify;
830 3
    if (delegate._updateShouldNotify != null) {
831 3
      shouldNotify = delegate._updateShouldNotify(
832 3
        delegate.value,
833 3
        newDelegate.value,
834
      );
835
    } else {
836 3
      shouldNotify = newDelegate.value != delegate.value;
837
    }
838

839 3
    if (shouldNotify && _removeListener != null) {
840 3
      _removeListener();
841 3
      _removeListener = null;
842
    }
843
    return shouldNotify;
844
  }
845

846 3
  @override
847
  void dispose() {
848 3
    super.dispose();
849 3
    _removeListener?.call();
850
  }
851

852 3
  @override
853
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
854 3
    super.debugFillProperties(properties);
855 3
    properties.add(
856 3
      FlagProperty(
857
        null,
858 3
        value: _removeListener != null,
859
        defaultValue: false,
860
        ifTrue: 'listening to value',
861
      ),
862
    );
863
  }
864

865 3
  @override
866
  bool get hasValue => true;
867
}

Read our documentation on viewing source code .

Loading