Skip to content

Instantly share code, notes, and snippets.

@PlugFox
Last active January 16, 2024 10:00
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PlugFox/9c1f3b0ee5038fa0832d3d495d9aa792 to your computer and use it in GitHub Desktop.
Save PlugFox/9c1f3b0ee5038fa0832d3d495d9aa792 to your computer and use it in GitHub Desktop.
Listenable --- selector & filter --> ValueListenable<Value>
import 'package:flutter/foundation.dart' show Listenable, ValueListenable, VoidCallback, ChangeNotifier;
/// Selector from [Listenable]
typedef ListenableSelector<Controller extends Listenable, Value> = Value Function(
Controller controller,
);
/// Filter for [Listenable]
typedef ListenableFilter<Value> = bool Function(Value prev, Value next);
/// Selects a specific value from the [Listenable]
/// for subsequent use in the ValueListenableBuilder
///
/// Listenable -- selector & filter --> ValueListenable<Value>
///
/// For example:
/// ```dart
/// ValueListenableBuilder<Locale>(
/// valueListenable: appModel.select<Locale>(
/// (cn) => cn.locale,
/// (prev, next) => prev.languageCode != next.languageCode
/// ),
/// builder: (context, locale, child) => Text(locale.languageCode),
/// )
/// ```
extension ListenableSelectorExtension<Controller extends Listenable> on Controller {
/// Transform [Listenable] in to [ValueListenable]
ValueListenable<Value> select<Value>(
ListenableSelector<Controller, Value> selector, [
ListenableFilter<Value>? test,
]) =>
_ValueListenableView<Controller, Value>(this, selector, test);
}
class _ValueListenableView<Controller extends Listenable, Value> with ChangeNotifier implements ValueListenable<Value> {
_ValueListenableView(
Controller controller,
ListenableSelector<Controller, Value> selector,
ListenableFilter<Value>? test,
) : _controller = controller,
_selector = selector,
_test = test;
final Controller _controller;
final ListenableSelector<Controller, Value> _selector;
final ListenableFilter<Value>? _test;
@override
Value get value => hasListeners ? _$value : _selector(_controller);
late Value _$value;
void _update() {
final newValue = _selector(_controller);
if (identical(_$value, newValue)) return;
if (!(_test?.call(_$value, newValue) ?? true)) return;
_$value = newValue;
notifyListeners();
}
@override
void addListener(VoidCallback listener) {
if (!hasListeners) {
_$value = _selector(_controller);
_controller.addListener(_update);
}
super.addListener(listener);
}
@override
void removeListener(VoidCallback listener) {
super.removeListener(listener);
if (!hasListeners) _controller.removeListener(_update);
}
@override
void dispose() {
_controller.removeListener(_update);
super.dispose();
}
}
@TekExplorer
Copy link

The documentation on that extension doesnt match the method signature https://gist.github.com/PlugFox/9c1f3b0ee5038fa0832d3d495d9aa792#file-listenable_selector-dart-L20-L30

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment