using System; using Unity.UIWidgets.foundation; using Unity.UIWidgets.ui; using Unity.UIWidgets.widgets; namespace Unity.UIWidgets.Sample.Redux { public class StoreProvider : InheritedWidget { readonly Store _store; public StoreProvider(Store store, Widget child, Key key = null) : base(key: key, child: child) { D.assert(store != null); D.assert(child != null); this._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(this._store, ((StoreProvider) old)._store); } } public delegate Widget ViewModelBuilder(BuildContext context, ViewModel vm); public delegate ViewModel StoreConverter(State state, Dispatcher dispatcher); public delegate bool ShouldRebuildCallback(ViewModel pre, ViewModel current); public class StoreConnector : StatelessWidget { public readonly ViewModelBuilder builder; public readonly StoreConverter converter; public readonly ShouldRebuildCallback shouldRebuild; public readonly bool distinct; public StoreConnector(ViewModelBuilder builder, StoreConverter converter, bool distinct = false, ShouldRebuildCallback shouldRebuild = null, Key key = null) : base(key) { D.assert(builder != null); D.assert(converter != null); this.distinct = distinct; this.builder = builder; this.converter = converter; this.shouldRebuild = shouldRebuild; } public override Widget build(BuildContext context) { return new _StoreListener( store: StoreProvider.of(context), builder: this.builder, converter: this.converter, distinct: this.distinct, shouldRebuild: this.shouldRebuild ); } } public class _StoreListener : StatefulWidget { public readonly ViewModelBuilder builder; public readonly StoreConverter converter; public readonly Store store; public readonly ShouldRebuildCallback shouldRebuild; public readonly bool distinct; public _StoreListener(ViewModelBuilder builder = null, StoreConverter converter = null, Store store = null, bool distinct = 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.distinct = distinct; this.shouldRebuild = shouldRebuild; } public override widgets.State createState() { return new _StoreListenerState(); } } class _StoreListenerState : State<_StoreListener> { ViewModel latestValue; public override void initState() { base.initState(); this._init(); } public override void dispose() { this.widget.store.stateChanged -= this._handleStateChanged; base.dispose(); } public override void didUpdateWidget(StatefulWidget oldWidget) { var oldStore = ((_StoreListener) oldWidget).store; if (this.widget.store != oldStore) { oldStore.stateChanged -= this._handleStateChanged; this._init(); } base.didUpdateWidget(oldWidget); } void _init() { this.widget.store.stateChanged += this._handleStateChanged; this.latestValue = this.widget.converter(this.widget.store.state, this.widget.store.Dispatch); } void _handleStateChanged(State state) { if (Window.hasInstance) { this._innerStateChanged(state); } else { using (WindowProvider.of(this.context).getScope()) { this._innerStateChanged(state); } } } void _innerStateChanged(State state) { var preValue = this.latestValue; this.latestValue = this.widget.converter(this.widget.store.state, this.widget.store.Dispatch); if (this.widget.shouldRebuild != null) { if (!this.widget.shouldRebuild(preValue, this.latestValue)) { return; } } else if (this.widget.distinct) { if (Equals(preValue, this.latestValue)) { return; } } this.setState(() => { }); } public override Widget build(BuildContext context) { return this.widget.builder(context, this.latestValue); } } }