using System; using Unity.UIWidgets.foundation; using Unity.UIWidgets.ui; using Unity.UIWidgets.widgets; namespace Unity.UIWidgets.Redux { public class StoreProvider : InheritedWidget { readonly Store _store; public StoreProvider( Store store = null, Widget child = null, Key key = null) : base(key: key, child: child) { D.assert(store != null); D.assert(child != null); _store = store; } public static Store of(BuildContext context) { var type = _typeOf>(); StoreProvider provider = context.inheritFromWidgetOfExactType(type) as StoreProvider; if (provider == null) { throw new UIWidgetsError("StoreProvider is missing"); } return provider._store; } static Type _typeOf() { return typeof(T); } public override bool updateShouldNotify(InheritedWidget old) { return !Equals(objA: _store, objB: ((StoreProvider) old)._store); } } public delegate Widget ViewModelBuilder(BuildContext context, ViewModel viewModel, Dispatcher dispatcher); public delegate ViewModel StoreConverter(State state); public delegate bool ShouldRebuildCallback(ViewModel previous, ViewModel current); public class StoreConnector : StatelessWidget { public readonly ViewModelBuilder builder; public readonly StoreConverter converter; public readonly ShouldRebuildCallback shouldRebuild; public readonly bool pure; public StoreConnector( ViewModelBuilder builder = null, StoreConverter converter = null, bool pure = false, ShouldRebuildCallback shouldRebuild = null, Key key = null) : base(key) { D.assert(builder != null); D.assert(converter != null); this.pure = pure; this.builder = builder; this.converter = converter; this.shouldRebuild = shouldRebuild; } public override Widget build(BuildContext context) { return new _StoreListener( store: StoreProvider.of(context), builder: builder, converter: converter, pure: pure, shouldRebuild: shouldRebuild ); } } public class _StoreListener : StatefulWidget { public readonly ViewModelBuilder builder; public readonly StoreConverter converter; public readonly Store store; public readonly ShouldRebuildCallback shouldRebuild; public readonly bool pure; public _StoreListener( ViewModelBuilder builder = null, StoreConverter converter = null, Store store = null, bool pure = false, ShouldRebuildCallback shouldRebuild = null, Key key = null) : base(key) { D.assert(builder != null); D.assert(converter != null); D.assert(store != null); this.store = store; this.builder = builder; this.converter = converter; this.pure = pure; this.shouldRebuild = shouldRebuild; } public override widgets.State createState() { return new _StoreListenerState(); } } class _StoreListenerState : State<_StoreListener> { ViewModel latestValue; public override void initState() { base.initState(); _init(); } public override void dispose() { widget.store.stateChanged -= _handleStateChanged; base.dispose(); } public override void didUpdateWidget(StatefulWidget oldWidget) { var oldStore = ((_StoreListener) oldWidget).store; if (widget.store != oldStore) { oldStore.stateChanged -= _handleStateChanged; _init(); } base.didUpdateWidget(oldWidget); } void _init() { widget.store.stateChanged += _handleStateChanged; latestValue = widget.converter(widget.store.getState()); } void _handleStateChanged(State state) { if (Window.instance._panel != null) { _innerStateChanged(state: state); } else { var isolate = Isolate.current; using (Isolate.getScope(isolate: isolate)) { _innerStateChanged(state: state); } } } void _innerStateChanged(State state) { var preValue = latestValue; latestValue = widget.converter(widget.store.getState()); if (widget.shouldRebuild != null) { if (!widget.shouldRebuild(preValue, latestValue)) { return; } } else if (widget.pure) { if (Equals(preValue, latestValue)) { return; } } setState(); } public override Widget build(BuildContext context) { return widget.builder(context, latestValue, widget.store.dispatcher); } } }