import 'dart:async'; import 'package:flutter/foundation.dart'; import 'store.dart'; extension StoreChangeExtension on S { Future changeFuture(T Function(S) onChange) async { /// Setup a completer final completer = Completer(); /// Get the current value for onChange. T current = onChange(this); /// Setup a listener void listener() async { final next = onChange(this); /// Check if there's a change if (next != current) { completer.complete(next); this.removeListener(listener); } } this.addListener(listener); return completer.future; } } class StoreChangeObserver { /// Observe a store and if [observe] changes, fire [onChange] StoreChangeObserver({ @required this.store, @required this.observe, @required this.onChange, }); /// The store to listen to for changes. final K store; /// The field on the store to check for changes. final T Function(K) observe; /// The callback to fire when [observe] changes. final void Function(T) onChange; Future initState() async { /// Setup the change listener store.addListener(_listener); /// Trigger the first value _listener(); } void dispose() { /// Remove the change listener store.removeListener(_listener); } /// Store the previous value so we can determine when a change has occurred. T _previous; bool _hasDispatchedFirstValue = false; void _listener() { /// Get the current value. final next = observe(store); final hasChanged = _previous != next; /// This is the first value, let's dispatch it and ensure we don't trigger this multiple times. if (_hasDispatchedFirstValue == false) { _hasDispatchedFirstValue = true; _previous = next; onChange(next); } /// There's been an update, let's save the last value so we don't trigger this multiple times. else if (hasChanged) { _previous = next; onChange(next); } } }