浏览代码

Merge branch 'master' of github.com:UnityTech/UIWidgets into xwzhu

# Conflicts:
#	Runtime/engine/UIWidgetsPanel.cs
/main
xingwei.zhu 6 年前
当前提交
29f20ef9
共有 34 个文件被更改,包括 611 次插入100 次删除
  1. 6
      .DS_Store
  2. 17
      README.md
  3. 10
      Runtime/editor/editor_window.cs
  4. 14
      Runtime/engine/UIWidgetsPanel.cs
  5. 4
      Runtime/foundation/basic_types.cs
  6. 2
      Runtime/foundation/node.cs
  7. 4
      Runtime/foundation/node.mixin.gen.cs
  8. 2
      Runtime/foundation/node.mixin.njk
  9. 15
      Runtime/widgets/app.cs
  10. 4
      Runtime/widgets/navigator.cs
  11. 20
      Samples/ReduxSample/CounterApp/CounterAppSample.cs
  12. 4
      Samples/ReduxSample/ObjectFinder/FinderGameObject.cs
  13. 73
      Samples/ReduxSample/ObjectFinder/ObjectFinderApp.cs
  14. 95
      Samples/ReduxSample/ObjectFinder/Reducer.cs
  15. 6
      Samples/ReduxSample/ObjectFinder/StoreProvider.cs
  16. 2
      Runtime/redux/redux_thunk.cs.meta
  17. 8
      Runtime/redux.meta
  18. 63
      Samples/UIWidgetSample/HttpRequestSample.cs
  19. 11
      Samples/UIWidgetSample/HttpRequestSample.cs.meta
  20. 19
      Runtime/redux/redux_logging.cs
  21. 32
      Runtime/redux/redux_thunk.cs
  22. 81
      Runtime/redux/store.cs
  23. 171
      Runtime/redux/widget_redux.cs
  24. 24
      Samples/ReduxSample/ObjectFinder/Middleware.cs
  25. 8
      Samples/ReduxSample/redux.meta
  26. 8
      Samples/ReduxSample/redux_logging.meta
  27. 8
      scripts/node_modules.meta
  28. 0
      /Runtime/redux/redux_thunk.cs.meta
  29. 0
      /Runtime/redux/store.cs.meta
  30. 0
      /Runtime/redux/widget_redux.cs.meta
  31. 0
      /Runtime/redux/redux_logging.cs.meta

6
.DS_Store


Bud1  d.batIl  @� @� @� @ build.batIlocblob;(������build.bat.metaIlocblob�(������build.shIlocblob(������ build.sh.metaIlocblob�(������ CHANGELOG.mdIlocblob�(������CHANGELOG.md.metaIlocblob;�������CONTRIBUTING.mdIlocblob��������CONTRIBUTING.md.metaIlocblob�������Documentation~Ilocblob��������EditorIlocblob�������� Editor.metaIlocblob;������
Bud1 GELOG.  @� @� @� @ CHANGELOG.mdIlocblob�(������CHANGELOG.md.metaIlocblob;�������CONTRIBUTING.mdIlocblob��������CONTRIBUTING.md.metaIlocblob�������Documentation~Ilocblob��������EditorIlocblob�������� Editor.metaIlocblob;������
Tests.metaIlocblob�X������Third Party Notices.mdIlocblobX������Third Party Notices.md.metaIlocblob�X������!UIWidgetCleanupPlugin.DotSettingsIlocblob�X������&UIWidgetCleanupPlugin.DotSettings.metaIlocblob;������� E DSDB `� @� @� @lesIlocblob�������� Samples.metaIlocblob�������scriptsIlocblob�������� scripts.metaIlocblob��������TestsIlocblob;X������
Tests.metaIlocblob�X������Third Party Notices.mdIlocblobX������Third Party Notices.md.metaIlocblob�X������!UIWidgetCleanupPlugin.DotSettingsIlocblob�X������&UIWidgetCleanupPlugin.DotSettings.metaIlocblob;�������
Tests.metaIlocblob�X������Third Party Notices.mdIlocblobX������Third Party Notices.md.metaIlocblob�X������!UIWidgetCleanupPlugin.DotSettingsIlocblob�X������&UIWidgetCleanupPlugin.DotSettings.metaIlocblob;������� E DSDB `� @� @� @;X������
Tests.metaIlocblob�X������Third Party Notices.mdIlocblobX������Third Party Notices.md.metaIlocblob�X������!UIWidgetCleanupPlugin.DotSettingsIlocblob�X������&UIWidgetCleanupPlugin.DotSettings.metaIlocblob;�������

17
README.md


2. You can add loading1@2.gif.bytes and loading1@3.gif.bytes in the same folder to support HD screens.
3. Use Image.asset("loading1.gif") to load the gif images.
#### Using Window Scope
If you see the error ```AssertionError: Window.instance is null``` or null pointer error of ```Window.instance```,
it means the code is not running in the window scope. In this case, you can enclose your code
with window scope as below:
```
using(WindowProvider.of(your gameObject with UIWidgetsPanel).getScope()) {
// code dealing with UIWidgets,
// e.g. setState(() => {....})
}
```
This is needed if the code is in methods
not invoked by UIWidgets. For example, if the code is in ```completed``` callback of ```UnityWebRequest```,
you need to enclose them with window scope.
Please see [HttpRequestSample](./Samples/UIWidgetSample/HttpRequestSample.cs) for detail.
For callback/event handler methods from UIWidgets (e.g ```Widget.build, State.initState...```), you don't need do
it yourself, since the framework ensure it's in window scope.
## Debug UIWidgets Application
#### Define UIWidgets_DEBUG

10
Runtime/editor/editor_window.cs


namespace Unity.UIWidgets.editor {
#if UNITY_EDITOR
public abstract class UIWidgetsEditorWindow : EditorWindow {
public abstract class UIWidgetsEditorWindow : EditorWindow, WindowHost {
WindowAdapter _windowAdapter;
public UIWidgetsEditorWindow() {

}
protected abstract Widget createWidget();
public Window window {
get { return this._windowAdapter; }
}
}
public class EditorWindowAdapter : WindowAdapter {

#endif
public interface WindowHost {
Window window { get; }
}
public abstract class WindowAdapter : Window {
static readonly List<WindowAdapter> _windowAdapters = new List<WindowAdapter>();

14
Runtime/engine/UIWidgetsPanel.cs


[RequireComponent(typeof(RectTransform))]
public class UIWidgetsPanel : RawImage, IPointerDownHandler, IPointerUpHandler, IDragHandler,
IPointerEnterHandler, IPointerExitHandler {
IPointerEnterHandler, IPointerExitHandler, WindowHost {
static Event _repaintEvent;
[SerializeField] protected float devicePixelRatioOverride;

public WindowPadding viewInsets {
get { return this._displayMetrics.viewInsets; }
}
protected override void OnDisable() {
D.assert(this._windowAdapter != null);
this._windowAdapter.OnDisable();
this._windowAdapter = null;
base.OnDisable();
}
protected virtual Widget createWidget() {

physicalX: position.x,
physicalY: position.y
));
}
public Window window {
get { return this._windowAdapter; }
}
}
}

4
Runtime/foundation/basic_types.cs


return true;
}
if (ReferenceEquals(it, list)) {
return true;
}
if (it == null || list == null) {
return false;
}

2
Runtime/foundation/node.cs


foreach (var field in fields) {
if (!field.IsInitOnly) {
throw new UIWidgetsError(
type + " should be immutable. All public fields need to be readonly. " +
type + " is pure and should be immutable. All public fields need to be readonly. " +
field + " is not readonly.");
}
}

4
Runtime/foundation/node.mixin.gen.cs


static readonly Dictionary<_DependencyList, WeakReference> _canonicalObjects =
new Dictionary<_DependencyList, WeakReference>();
public bool alwaysUpdate { get; set; } = true; // if canonicalEquals should not be used.
public bool pure { get; set; } // pure = false, if canonicalEquals should not be used.
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {

return false;
}
if (this.alwaysUpdate) {
if (!this.pure) {
return ReferenceEquals(this, obj);
} else {
return ReferenceEquals(this._getCanonical(), ((CanonicalMixinDiagnosticableTree) obj)._getCanonical());

2
Runtime/foundation/node.mixin.njk


return false;
}
if (this.alwaysUpdate) {
if (!this.pure) {
return ReferenceEquals(this, obj);
} else {
return ReferenceEquals(this._getCanonical(), ((CanonicalMixin{{with}}) obj)._getCanonical());

15
Runtime/widgets/app.cs


using System.Collections.Generic;
using RSG;
using Unity.UIWidgets.editor;
using Unity.UIWidgets.engine;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
using TextStyle = Unity.UIWidgets.painting.TextStyle;
namespace Unity.UIWidgets.widgets {

return provider.window;
}
public static Window of(GameObject gameObject) {
var panel = gameObject.GetComponent<UIWidgetsPanel>();
return panel == null ? null : panel.window;
}
#if UNITY_EDITOR
public static Window of(UIWidgetsEditorWindow editorWindow) {
return editorWindow.window;
}
#endif
public override bool updateShouldNotify(InheritedWidget oldWidget) {
D.assert(this.window == ((WindowProvider) oldWidget).window);

4
Runtime/widgets/navigator.cs


key: this._overlayKey,
initialEntries: this._initialOverlayEntries
)
) {
alwaysUpdate = true,
}
)
)
);
}

20
Samples/ReduxSample/CounterApp/CounterAppSample.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.Redux;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using TextStyle = Unity.UIWidgets.painting.TextStyle;

public class CounterApp : StatelessWidget {
public override Widget build(BuildContext context) {
var store = new Store<CouterState>(reduce, new CouterState(),
ReduxLogging.Create<CouterState>());
ReduxLogging.create<CouterState>());
return new StoreProvider<CouterState>(store, this.createWidget());
}

child: new Column(
children: new List<Widget>() {
new StoreConnector<CouterState, string>(
converter: (state, dispatch) => $"Count:{state.count}",
builder: (context, countText) => new Text(countText, style: new TextStyle(
converter: (state) => $"Count:{state.count}",
builder: (context, countText, dispatcher) => new Text(countText, style: new TextStyle(
))
)),
pure: true
new StoreConnector<CouterState, Action>(
converter: (state, dispatch) => () => { dispatch(new CounterIncAction() {amount = 1}); },
builder: (context, onPress) => new CustomButton(
new StoreConnector<CouterState, object>(
converter: (state) => null,
builder: (context, _, dispatcher) => new CustomButton(
)), onPressed: () => { onPress(); })
)), onPressed: () => { dispatcher.dispatch(new CounterIncAction() {amount = 1}); }),
pure: true
),
}
)

4
Samples/ReduxSample/ObjectFinder/FinderGameObject.cs


// Update is called once per frame
void Update() {
var selectedId = StoreProvider.store.state.selected;
var selectedId = StoreProvider.store.getState().selected;
if (selectedId == this.GetInstanceID()) {
this.GetComponent<MeshRenderer>().material.color = new Color(1.0f, 0, 0, 1.0f);
}

}
void OnMouseDown() {
StoreProvider.store.Dispatch(new SelectObjectAction() {id = this.GetInstanceID()});
StoreProvider.store.dispatcher.dispatch(new SelectObjectAction() {id = this.GetInstanceID()});
}
}
}

73
Samples/ReduxSample/ObjectFinder/ObjectFinderApp.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.Redux;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
using TextStyle = Unity.UIWidgets.painting.TextStyle;
namespace Unity.UIWidgets.Sample.Redux.ObjectFinder {

Widget createRootWidget() {
return new StoreConnector<FinderAppState, ObjectFinderAppWidgetModel>(
(context, viewModel) => new ObjectFinderAppWidget(
viewModel, this.gameObject.name
pure: true,
builder: (context, viewModel, dispatcher) => new ObjectFinderAppWidget(
model: viewModel,
doSearch: (text) => dispatcher.dispatch(SearchAction.create(text)),
onSelect: (id) => dispatcher.dispatch(new SelectObjectAction() {id = id}),
title: this.gameObject.name
(state, dispacher) => new ObjectFinderAppWidgetModel() {
converter: (state) => new ObjectFinderAppWidgetModel() {
doSearch = (text) => dispacher(new SearchAction() {keyword = text}),
onSelect = (id) => dispacher(new SelectObjectAction() {id = id})
}
);
}

public delegate void onFindCallback(string keyword);
public class ObjectFinderAppWidgetModel {
public class ObjectFinderAppWidgetModel : IEquatable<ObjectFinderAppWidgetModel> {
public Action<string> doSearch;
public Action<int> onSelect;
public bool Equals(ObjectFinderAppWidgetModel other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return this.selected == other.selected && this.objects.equalsList(other.objects);
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != this.GetType()) {
return false;
}
return this.Equals((ObjectFinderAppWidgetModel) obj);
}
public override int GetHashCode() {
unchecked {
return (this.selected * 397) ^ this.objects.hashList();
}
}
public static bool operator ==(ObjectFinderAppWidgetModel left, ObjectFinderAppWidgetModel right) {
return Equals(left, right);
}
public static bool operator !=(ObjectFinderAppWidgetModel left, ObjectFinderAppWidgetModel right) {
return !Equals(left, right);
}
}
public class ObjectFinderAppWidget : StatefulWidget {

public readonly string title;
public ObjectFinderAppWidget(ObjectFinderAppWidgetModel model, string title, Key key = null) : base(key) {
public ObjectFinderAppWidget(
ObjectFinderAppWidgetModel model = null,
Action<string> doSearch = null,
Action<int> onSelect = null,
string title = null,
Key key = null) : base(key) {
this.doSearch = model.doSearch;
this.onSelect = model.onSelect;
this.doSearch = doSearch;
this.onSelect = onSelect;
this.title = title;
}

this._controller = new TextEditingController("");
this._focusNode = new FocusNode();
if (this.widget.doSearch != null) {
//scheduler.SchedulerBinding.instance.scheduleFrameCallback
Window.instance.scheduleMicrotask(() => this.widget.doSearch(""));
}

base.dispose();
}
public override Widget build(BuildContext context) {
public override Widget build(BuildContext context) {
Debug.Log("build ObjectFinderAppWidget");
return new Container(
padding: EdgeInsets.all(10),
decoration: new BoxDecoration(color: new Color(0x4FFFFFFF),

95
Samples/ReduxSample/ObjectFinder/Reducer.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.Redux;
public class GameObjectInfo {
public class GameObjectInfo : IEquatable<GameObjectInfo> {
public bool Equals(GameObjectInfo other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return this.id == other.id && string.Equals(this.name, other.name);
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != this.GetType()) {
return false;
}
return this.Equals((GameObjectInfo) obj);
}
public override int GetHashCode() {
unchecked {
return (this.id * 397) ^ (this.name != null ? this.name.GetHashCode() : 0);
}
}
public static bool operator ==(GameObjectInfo left, GameObjectInfo right) {
return Equals(left, right);
}
public static bool operator !=(GameObjectInfo left, GameObjectInfo right) {
return !Equals(left, right);
}
public class FinderAppState {
public class FinderAppState : IEquatable<FinderAppState> {
public int selected;
public List<GameObjectInfo> objects;

}
public bool Equals(FinderAppState other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return this.selected == other.selected && Equals(this.objects, other.objects);
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != this.GetType()) {
return false;
}
return this.Equals((FinderAppState) obj);
}
public override int GetHashCode() {
unchecked {
return (this.selected * 397) ^ (this.objects != null ? this.objects.GetHashCode() : 0);
}
}
public static bool operator ==(FinderAppState left, FinderAppState right) {
return Equals(left, right);
}
public static bool operator !=(FinderAppState left, FinderAppState right) {
return !Equals(left, right);
}
public class SearchAction {
public string keyword;
public static class SearchAction {
public static ThunkAction<FinderAppState> create(string keyword) {
return new ThunkAction<FinderAppState>(
displayName: "SearchAction",
action: (dispatcher, getState) => {
var objects = UnityEngine.Object.FindObjectsOfType(typeof(FinderGameObject)).Where(
obj => keyword == "" || obj.name.ToUpper().Contains(keyword.ToUpper())).Select(
obj => new GameObjectInfo {id = obj.GetInstanceID(), name = obj.name}).ToList();
dispatcher.dispatch(new SearchResultAction {keyword = keyword, results = objects});
return null;
});
}
}
[Serializable]

6
Samples/ReduxSample/ObjectFinder/StoreProvider.cs


using Unity.UIWidgets.Redux;
namespace Unity.UIWidgets.Sample.Redux.ObjectFinder {
public static class StoreProvider {
static Store<FinderAppState> _store;

}
var middlewares = new Middleware<FinderAppState>[] {
ReduxLogging.Create<FinderAppState>(),
GameFinderMiddleware.Create(),
ReduxLogging.create<FinderAppState>(),
ReduxThunk.create<FinderAppState>(),
};
_store = new Store<FinderAppState>(ObjectFinderReducer.Reduce,
new FinderAppState(),

2
Runtime/redux/redux_thunk.cs.meta


fileFormatVersion: 2
guid: d80e14622d3da4c6eaa3f72c29fa1fd3
guid: f837de040a3fa4a3fb3e6c344153e1eb
MonoImporter:
externalObjects: {}
serializedVersion: 2

8
Runtime/redux.meta


fileFormatVersion: 2
guid: 3a7bb5e4fb043482e8bf223c2d3fa76c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

63
Samples/UIWidgetSample/HttpRequestSample.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.material;
using Unity.UIWidgets.widgets;
using UnityEngine;
using UnityEngine.Networking;
public class HttpRequestSample : UIWidgetsPanel
{
protected override Widget createWidget() {
return new MaterialApp(
title: "Http Request Sample",
home: new Scaffold(
body:new AsyncRequestWidget(this.gameObject)
)
);
}
}
public class AsyncRequestWidget : StatefulWidget {
public readonly GameObject gameObjOfUIWidgetsPanel;
public AsyncRequestWidget(GameObject gameObjOfUiWidgetsPanel, Key key = null) : base(key) {
this.gameObjOfUIWidgetsPanel = gameObjOfUiWidgetsPanel;
}
public override State createState() {
return new _AsyncRequestWidgetState();
}
}
[Serializable]
public class TimeData {
public long currentFileTime;
}
class _AsyncRequestWidgetState : State<AsyncRequestWidget> {
long _fileTime;
public override Widget build(BuildContext context) {
return new Column(
children: new List<Widget>() {
new FlatButton(child: new Text("Click To Get Time"), onPressed: () => {
UnityWebRequest www = UnityWebRequest.Get("http://worldclockapi.com/api/json/est/now");
var asyncOperation = www.SendWebRequest();
asyncOperation.completed += operation => {
var timeData = JsonUtility.FromJson<TimeData>(www.downloadHandler.text);
using(WindowProvider.of(this.widget.gameObjOfUIWidgetsPanel).getScope())
{
this.setState(() => { this._fileTime = timeData.currentFileTime; });
}
};
}),
new Text($"current file time: {this._fileTime}")
});
}
}

11
Samples/UIWidgetSample/HttpRequestSample.cs.meta


fileFormatVersion: 2
guid: cfa3e1cd78bb74aef90a7a0289dfc23c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

19
Runtime/redux/redux_logging.cs


using UnityEngine;
namespace Unity.UIWidgets.Redux {
public static class ReduxLogging {
public static Middleware<State> create<State>() {
return (store) => (next) => new DispatcherImpl((action) => {
var previousState = store.getState();
var previousStateDump = JsonUtility.ToJson(previousState);
var result = next.dispatch(action);
var afterState = store.getState();
var afterStateDump = JsonUtility.ToJson(afterState);
Debug.LogFormat("Action name={0} data={1}", action.ToString(), JsonUtility.ToJson(action));
Debug.LogFormat("previousState=\n{0}", previousStateDump);
Debug.LogFormat("afterState=\n{0}", afterStateDump);
return result;
});
}
}
}

32
Runtime/redux/redux_thunk.cs


using System;
namespace Unity.UIWidgets.Redux {
public static class ReduxThunk {
public static Middleware<State> create<State>() {
return (store) => (next) => new DispatcherImpl((action) => {
var thunkAction = action as ThunkAction<State>;
if (thunkAction != null && thunkAction.action != null) {
return thunkAction.action(store.dispatcher, store.getState);
}
return next.dispatch(action);
});
}
}
public sealed class ThunkAction<State> {
public readonly Func<Dispatcher, Func<State>, object> action;
public readonly string displayName;
public ThunkAction(
Func<Dispatcher, Func<State>, object> action = null,
string displayName = null) {
this.action = action;
this.displayName = displayName ?? "";
}
public override string ToString() {
return "ThunkAction(" + this.displayName + ")";
}
}
}

81
Runtime/redux/store.cs


using System;
using System.Linq;
namespace Unity.UIWidgets {
public interface Dispatcher {
T dispatch<T>(object action);
object dispatch(object action);
}
public class DispatcherImpl : Dispatcher {
readonly Func<object, object> _impl;
public DispatcherImpl(Func<object, object> impl) {
this._impl = impl;
}
public T dispatch<T>(object action) {
if (this._impl == null) {
return default;
}
return (T) this._impl(action);
}
public object dispatch(object action) {
if (this._impl == null) {
return default;
}
return this._impl(action);
}
}
public delegate State Reducer<State>(State previousState, object action);
public delegate Func<Dispatcher, Dispatcher> Middleware<State>(Store<State> store);
public delegate void StateChangedHandler<State>(State action);
public class Store<State> {
public StateChangedHandler<State> stateChanged;
readonly Dispatcher _dispatcher;
readonly Reducer<State> _reducer;
State _state;
public Store(
Reducer<State> reducer,
State initialState = default,
params Middleware<State>[] middleware) {
this._reducer = reducer;
this._dispatcher = this._applyMiddleware(middleware);
this._state = initialState;
}
public Dispatcher dispatcher {
get { return this._dispatcher; }
}
public State getState() {
return this._state;
}
Dispatcher _applyMiddleware(params Middleware<State>[] middleware) {
return middleware.Reverse().Aggregate<Middleware<State>, Dispatcher>(
new DispatcherImpl(this._innerDispatch),
(current, middlewareItem) => middlewareItem(this)(current));
}
object _innerDispatch(object action) {
this._state = this._reducer(this._state, action);
if (this.stateChanged != null) {
this.stateChanged(this._state);
}
return action;
}
}
}

171
Runtime/redux/widget_redux.cs


using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
namespace Unity.UIWidgets.Redux {
public class StoreProvider<State> : InheritedWidget {
readonly Store<State> _store;
public StoreProvider(
Store<State> store = null,
Widget child = null,
Key key = null) : base(key: key, child: child) {
D.assert(store != null);
D.assert(child != null);
this._store = store;
}
public static Store<State> of(BuildContext context) {
var type = _typeOf<StoreProvider<State>>();
StoreProvider<State> provider = context.inheritFromWidgetOfExactType(type) as StoreProvider<State>;
if (provider == null) {
throw new UIWidgetsError("StoreProvider is missing");
}
return provider._store;
}
static Type _typeOf<T>() {
return typeof(T);
}
public override bool updateShouldNotify(InheritedWidget old) {
return !Equals(this._store, ((StoreProvider<State>) old)._store);
}
}
public delegate Widget ViewModelBuilder<ViewModel>(BuildContext context, ViewModel viewModel, Dispatcher dispatcher);
public delegate ViewModel StoreConverter<State, ViewModel>(State state);
public delegate bool ShouldRebuildCallback<ViewModel>(ViewModel previous, ViewModel current);
public class StoreConnector<State, ViewModel> : StatelessWidget {
public readonly ViewModelBuilder<ViewModel> builder;
public readonly StoreConverter<State, ViewModel> converter;
public readonly ShouldRebuildCallback<ViewModel> shouldRebuild;
public readonly bool pure;
public StoreConnector(
ViewModelBuilder<ViewModel> builder = null,
StoreConverter<State, ViewModel> converter = null,
bool pure = false,
ShouldRebuildCallback<ViewModel> 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<State, ViewModel>(
store: StoreProvider<State>.of(context),
builder: this.builder,
converter: this.converter,
pure: this.pure,
shouldRebuild: this.shouldRebuild
);
}
}
public class _StoreListener<State, ViewModel> : StatefulWidget {
public readonly ViewModelBuilder<ViewModel> builder;
public readonly StoreConverter<State, ViewModel> converter;
public readonly Store<State> store;
public readonly ShouldRebuildCallback<ViewModel> shouldRebuild;
public readonly bool pure;
public _StoreListener(
ViewModelBuilder<ViewModel> builder = null,
StoreConverter<State, ViewModel> converter = null,
Store<State> store = null,
bool pure = false,
ShouldRebuildCallback<ViewModel> 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<State, ViewModel>();
}
}
class _StoreListenerState<State, ViewModel> : State<_StoreListener<State, ViewModel>> {
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<State, ViewModel>) 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.getState());
}
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.getState());
if (this.widget.shouldRebuild != null) {
if (!this.widget.shouldRebuild(preValue, this.latestValue)) {
return;
}
}
else if (this.widget.pure) {
if (Equals(preValue, this.latestValue)) {
return;
}
}
this.setState();
}
public override Widget build(BuildContext context) {
return this.widget.builder(context, this.latestValue, this.widget.store.dispatcher);
}
}
}

24
Samples/ReduxSample/ObjectFinder/Middleware.cs


using System.Linq;
using UnityEngine;
namespace Unity.UIWidgets.Sample.Redux.ObjectFinder {
public class GameFinderMiddleware {
public static Middleware<FinderAppState> Create() {
return (store) => (next) => (action) => {
if (action is SearchAction) {
var searchAction = (SearchAction) action;
var objects = Object.FindObjectsOfType(typeof(FinderGameObject)).Where((obj) => {
return searchAction.keyword == "" ||
obj.name.ToUpper().Contains(searchAction.keyword.ToUpper());
}).Select(obj => new GameObjectInfo {id = obj.GetInstanceID(), name = obj.name}).ToList();
var result = next(action);
store.Dispatch(new SearchResultAction() {keyword = searchAction.keyword, results = objects});
return result;
}
return next(action);
};
}
}
}

8
Samples/ReduxSample/redux.meta


fileFormatVersion: 2
guid: b6da4bbe4d8914b81a78b7d08ad4c7a4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Samples/ReduxSample/redux_logging.meta


fileFormatVersion: 2
guid: 5efe762e4ce804533b403e22eedb2e3b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
scripts/node_modules.meta


fileFormatVersion: 2
guid: 7d78b565ea82c414a9c59aa6ccd9bd2c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

/Samples/ReduxSample/ObjectFinder/Middleware.cs.meta → /Runtime/redux/redux_thunk.cs.meta

/Samples/ReduxSample/redux/store.cs.meta → /Runtime/redux/store.cs.meta

/Samples/ReduxSample/redux/widget_redux.cs.meta → /Runtime/redux/widget_redux.cs.meta

/Samples/ReduxSample/redux_logging/redux_logging.cs.meta → /Runtime/redux/redux_logging.cs.meta

正在加载...
取消
保存