diff --git a/packages/ui_primitives/lib/src/foundation/value_notifier.dart b/packages/ui_primitives/lib/src/foundation/value_notifier.dart index 832de12c8..0419f1db5 100644 --- a/packages/ui_primitives/lib/src/foundation/value_notifier.dart +++ b/packages/ui_primitives/lib/src/foundation/value_notifier.dart @@ -396,14 +396,33 @@ class _ChangeNotifier implements Listenable { /// /// Because of this behavior, [ValueNotifier] is best used with immutable data /// types. -interface class ValueNotifier implements ValueListenable { +class ValueNotifier implements ValueListenable { final _ChangeNotifier _changeNotifier = _ChangeNotifier(); /// Creates a [_ChangeNotifier] that wraps this value. ValueNotifier(this._value) { - if (kTrackMemoryLeaks) { - debugMaybeDispatchCreated(runtimeType.toString(), this); - } + assert(() { + if (kTrackMemoryLeaks) { + debugMaybeDispatchCreated(runtimeType.toString(), this); + } + return true; + }()); + } + + bool _debugDisposed = false; + + static bool debugAssertNotDisposed(ValueNotifier notifier) { + assert(() { + if (notifier._debugDisposed) { + throw UiError( + 'A ${notifier.runtimeType} was used after being disposed.\n' + 'Once you have called dispose() on a ${notifier.runtimeType}, it ' + 'can no longer be used.', + ); + } + return true; + }()); + return true; } /// The current value stored in this notifier. @@ -426,9 +445,12 @@ interface class ValueNotifier implements ValueListenable { String toString() => '${describeIdentity(this)}($value)'; void dispose() { - if (kTrackMemoryLeaks) { - debugMaybeDispatchDisposed(this); - } + assert(() { + _debugDisposed = true; + if (kTrackMemoryLeaks) debugMaybeDispatchDisposed(this); + return true; + }()); + _changeNotifier.dispose(); } @@ -439,4 +461,10 @@ interface class ValueNotifier implements ValueListenable { @override void removeListener(VoidCallback listener) => _changeNotifier.removeListener(listener); + + @protected + bool get hasListeners => _changeNotifier.hasListeners; + + @protected + void notifyListeners() => _changeNotifier.notifyListeners(); } diff --git a/packages/ui_primitives/pubspec.yaml b/packages/ui_primitives/pubspec.yaml index 374370b39..79ac07e33 100644 --- a/packages/ui_primitives/pubspec.yaml +++ b/packages/ui_primitives/pubspec.yaml @@ -5,7 +5,7 @@ name: ui_primitives description: Highly experimental package. repository: https://github.com/flutter/genui/tree/main/packages/ui_primitives -version: 0.0.1-dev-003 +version: 0.0.1-dev-005 resolution: workspace diff --git a/packages/ui_primitives/test/smoke_test.dart b/packages/ui_primitives/test/smoke_test.dart index 36c602ddd..d60edb10c 100644 --- a/packages/ui_primitives/test/smoke_test.dart +++ b/packages/ui_primitives/test/smoke_test.dart @@ -6,7 +6,7 @@ import 'package:test/test.dart'; import 'package:ui_primitives/ui_primitives.dart'; // ignore: unused_element, tests that ValueNotifier can be implemented. -class _ValueNotifierOtherImplementaion implements ValueNotifier { +class _ValueNotifierImplementaion implements ValueNotifier { @override void addListener(VoidCallback listener) {} @@ -21,6 +21,17 @@ class _ValueNotifierOtherImplementaion implements ValueNotifier { @override set value(T newValue) {} + + @override + bool get hasListeners => throw UnimplementedError(); + + @override + void notifyListeners() {} +} + +// ignore: unused_element, tests that ValueNotifier can be extended. +class _ValueNotifierExtention extends ValueNotifier { + _ValueNotifierExtention(super.value); } void main() {