浏览代码

Merge branch 'master' into yczhang

/main
Yuncong 6 年前
当前提交
a103c01c
共有 41 个文件被更改,包括 970 次插入105 次删除
  1. 6
      .DS_Store
  2. 17
      README.md
  3. 26
      Runtime/editor/editor_utils.cs
  4. 21
      Runtime/editor/editor_window.cs
  5. 93
      Runtime/engine/DisplayMetrics.cs
  6. 41
      Runtime/engine/UIWidgetsPanel.cs
  7. 4
      Runtime/foundation/basic_types.cs
  8. 2
      Runtime/foundation/node.cs
  9. 4
      Runtime/foundation/node.mixin.gen.cs
  10. 2
      Runtime/foundation/node.mixin.njk
  11. 3
      Runtime/material/input_decorator.cs
  12. 15
      Runtime/widgets/app.cs
  13. 4
      Runtime/widgets/navigator.cs
  14. 20
      Samples/ReduxSample/CounterApp/CounterAppSample.cs
  15. 4
      Samples/ReduxSample/ObjectFinder/FinderGameObject.cs
  16. 73
      Samples/ReduxSample/ObjectFinder/ObjectFinderApp.cs
  17. 95
      Samples/ReduxSample/ObjectFinder/Reducer.cs
  18. 6
      Samples/ReduxSample/ObjectFinder/StoreProvider.cs
  19. 2
      Runtime/redux/redux_thunk.cs.meta
  20. 34
      Runtime/Plugins/platform/ios/UIWidgetsViewController.h
  21. 26
      Runtime/Plugins/platform/ios/UIWidgetsViewController.h.meta
  22. 108
      Runtime/Plugins/platform/ios/UIWidgetsViewController.mm
  23. 36
      Runtime/Plugins/platform/ios/UIWidgetsViewController.mm.meta
  24. 8
      Runtime/redux.meta
  25. 63
      Samples/UIWidgetSample/HttpRequestSample.cs
  26. 11
      Samples/UIWidgetSample/HttpRequestSample.cs.meta
  27. 19
      Runtime/redux/redux_logging.cs
  28. 32
      Runtime/redux/redux_thunk.cs
  29. 81
      Runtime/redux/store.cs
  30. 171
      Runtime/redux/widget_redux.cs
  31. 24
      Samples/ReduxSample/ObjectFinder/Middleware.cs
  32. 8
      Samples/ReduxSample/redux.meta
  33. 8
      Samples/ReduxSample/redux_logging.meta
  34. 8
      scripts/node_modules.meta
  35. 0
      /Runtime/redux/redux_thunk.cs.meta
  36. 0
      /Runtime/redux/store.cs.meta
  37. 0
      /Runtime/redux/widget_redux.cs.meta
  38. 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

26
Runtime/editor/editor_utils.cs


using System.Collections;
using System.Reflection;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.ui;
using UnityEngine;

public float devicePixelRatio {
get { return this._lastDevicePixelRatio; }
}
public viewMetrics viewMetrics {
get {
return new viewMetrics {
insets_bottom = 0,
insets_left = 0,
insets_right = 0,
insets_top = 0,
padding_left = 0,
padding_top = 0,
padding_right = 0,
padding_bottom = 0
};
}
}
public WindowPadding viewPadding {
get { return WindowPadding.zero; }
}
public WindowPadding viewInsets {
get { return WindowPadding.zero; }
}
}
static class GameViewUtil {

21
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>();

float _lastWindowWidth;
float _lastWindowHeight;
bool _viewMetricsChanged;
readonly MicrotaskQueue _microtaskQueue = new MicrotaskQueue();
readonly TimerProvider _timerProvider = new TimerProvider();
readonly Rasterizer _rasterizer = new Rasterizer();

}
protected virtual void updateSafeArea() {
}
public void onViewMetricsChanged() {
this._viewMetricsChanged = true;
}
protected abstract bool hasFocus();

return true;
}
if (this._viewMetricsChanged) {
return true;
}
return false;
}

this._lastWindowHeight * this._devicePixelRatio);
this.updateSafeArea();
this._viewMetricsChanged = false;
if (this.onMetricsChanged != null) {
this.onMetricsChanged();
}

93
Runtime/engine/DisplayMetrics.cs


using System;
using System.Runtime.InteropServices;
using Unity.UIWidgets.ui;
[StructLayout(LayoutKind.Sequential)]
public struct viewMetrics {
public float insets_top;
public float insets_bottom;
public float insets_left;
public float insets_right;
public float padding_top;
public float padding_bottom;
public float padding_left;
public float padding_right;
}
public static class DisplayMetricsProvider {
public static Func<DisplayMetrics> provider = () => new PlayerDisplayMetrics();
}

void Update();
float devicePixelRatio { get; }
viewMetrics viewMetrics { get; }
WindowPadding viewPadding { get; }
WindowPadding viewInsets { get; }
viewMetrics? _viewMetrics = null;
public void OnEnable() {
}

}
public void Update() {
//view metrics marks dirty
this._viewMetrics = null;
}

}
public WindowPadding viewPadding {
get {
return new WindowPadding(this.viewMetrics.padding_left,
this.viewMetrics.padding_top,
this.viewMetrics.padding_right,
this.viewMetrics.padding_bottom);
}
}
public WindowPadding viewInsets {
get {
return new WindowPadding(this.viewMetrics.insets_left,
this.viewMetrics.insets_top,
this.viewMetrics.insets_right,
this.viewMetrics.insets_bottom);
}
}
public viewMetrics viewMetrics {
get {
if (this._viewMetrics != null) {
return this._viewMetrics.Value;
}
#if UNITY_ANDROID
this._viewMetrics = new viewMetrics {
insets_bottom = 0,
insets_left = 0,
insets_right = 0,
insets_top = 0,
padding_left = Screen.safeArea.x,
padding_top = Screen.safeArea.y,
padding_right = Screen.width - Screen.safeArea.width - Screen.safeArea.x,
padding_bottom = Screen.height - Screen.safeArea.height - Screen.safeArea.y
};
#elif UNITY_WEBGL
this._viewMetrics = new viewMetrics {
insets_bottom = 0,
insets_left = 0,
insets_right = 0,
insets_top = 0,
padding_left = 0,
padding_top = 0,
padding_right = 0,
padding_bottom = 0
};
#elif UNITY_IOS
viewMetrics metrics = IOSGetViewportPadding();
this._viewMetrics = metrics;
#else
this._viewMetrics = new viewMetrics {
insets_bottom = 0,
insets_left = 0,
insets_right = 0,
insets_top = 0,
padding_left = 0,
padding_top = 0,
padding_right = 0,
padding_bottom = 0
};
#endif
return this._viewMetrics.Value;
}
}
#if UNITY_ANDROID
static float AndroidDevicePixelRatio() {
using (

#if UNITY_IOS
[DllImport("__Internal")]
static extern int IOSDeviceScaleFactor();
[DllImport("__Internal")]
static extern viewMetrics IOSGetViewportPadding();
}
}

41
Runtime/engine/UIWidgetsPanel.cs


using System.Collections.Generic;
using Unity.UIWidgets.async;
using Unity.UIWidgets.editor;
using Unity.UIWidgets.external.simplejson;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;

readonly UIWidgetsPanel _uiWidgetsPanel;
bool _needsPaint;
this._padding = new WindowPadding(
Screen.safeArea.x,
Screen.safeArea.y,
Screen.width - Screen.safeArea.width - Screen.safeArea.x,
Screen.height - Screen.safeArea.height - Screen.safeArea.y);
this._padding = this._uiWidgetsPanel.viewPadding;
this._viewInsets = this._uiWidgetsPanel.viewInsets;
}
protected override bool hasFocus() {

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

Vector2 _lastMouseMove;
HashSet<int> _enteredPointers;
bool _viewMetricsCallbackRegistered;
bool _mouseEntered {
get { return !this._enteredPointers.isEmpty(); }

const int mouseButtonNum = 3;
void _handleViewMetricsChanged(string method, List<JSONNode> args) {
this._windowAdapter.onViewMetricsChanged();
this._displayMetrics.Update();
}
protected override void OnEnable() {
base.OnEnable();
//Disable the default touch -> mouse event conversion on mobile devices

this._displayMetrics.OnEnable();
if (_repaintEvent == null) {
_repaintEvent = new Event {type = EventType.Repaint};
}

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

protected virtual void Update() {
this._displayMetrics.Update();
UIWidgetsMessageManager.ensureUIWidgetsMessageManagerIfNeeded();
if (!this._viewMetricsCallbackRegistered) {
this._viewMetricsCallbackRegistered = true;
UIWidgetsMessageManager.instance?.AddChannelMessageDelegate("ViewportMatricsChanged",
this._handleViewMetricsChanged);
}
if (this._mouseEntered) {
if (this._lastMouseMove.x != Input.mousePosition.x || this._lastMouseMove.y != Input.mousePosition.y) {

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());

3
Runtime/material/input_decorator.cs


protected override void removeChildRenderObject(RenderObject child) {
D.assert(child is RenderBox);
D.assert(this.renderObject.childToSlot.ContainsKey((RenderBox) child));
var slot = this.renderObject.childToSlot[(RenderBox) child];
D.assert(!this.renderObject.slotToChild.ContainsKey((_DecorationSlot) this.slot));
D.assert(!this.renderObject.slotToChild.ContainsKey(slot));
}
protected override void moveChildRenderObject(RenderObject child, object slotValue) {

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

34
Runtime/Plugins/platform/ios/UIWidgetsViewController.h


#ifndef PLATFORM_IOS_FRAMEWORK_SOURCE_UIWIDGETSVIEWCONTROLLER_H_
#define PLATFORM_IOS_FRAMEWORK_SOURCE_UIWIDGETSVIEWCONTROLLER_H_
#import <UIKit/UIKit.h>
#include "UIWidgetsTextInputDelegate.h"
struct viewPadding
{
float top;
float bottom;
float left;
float right;
};
struct viewMetrics
{
float insets_top;
float insets_bottom;
float insets_left;
float insets_right;
float padding_top;
float padding_bottom;
float padding_left;
float padding_right;
};
@interface UIWidgetsViewController : NSObject
@property viewPadding padding;
@property viewPadding viewInsets;
@end
#endif // PLATFORM_IOS_FRAMEWORK_SOURCE_UIWIDGETSVIEWCONTROLLER_H_

26
Runtime/Plugins/platform/ios/UIWidgetsViewController.h.meta


fileFormatVersion: 2
guid: a797fb0a2ddb84d4e8ac7f6da5d70819
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

108
Runtime/Plugins/platform/ios/UIWidgetsViewController.mm


#include "UIWidgetsViewController.h"
#include "UIWidgetsMessageManager.h"
#include <Foundation/Foundation.h>
#include <UIKit/UIKit.h>
@implementation UIWidgetsViewController {
}
@synthesize viewInsets;
@synthesize padding;
- (instancetype)init {
self = [super init];
if (self) {
viewInsets.bottom = 0;
viewInsets.top = 0;
viewInsets.left = 0;
viewInsets.right = 0;
CGFloat scale = [[UIScreen mainScreen] scale];
if (@available(iOS 11, *)) {
padding.bottom = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom * scale;
padding.top = [UIApplication sharedApplication].keyWindow.safeAreaInsets.top * scale;
padding.left = [UIApplication sharedApplication].keyWindow.safeAreaInsets.left * scale;
padding.right = [UIApplication sharedApplication].keyWindow.safeAreaInsets.right * scale;
} else {
CGRect statusFrame = [UIApplication sharedApplication].statusBarFrame;
padding.bottom = 0;
padding.top = statusFrame.size.height * scale;
padding.left = 0;
padding.right = 0;
}
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(keyboardWillChangeFrame:)
name:UIKeyboardWillChangeFrameNotification
object:nil];
[center addObserver:self
selector:@selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification
object:nil];
}
return self;
}
-(void)keyboardWillBeHidden:(NSNotification*)notification {
viewInsets.bottom = 0;
CGFloat scale = [UIScreen mainScreen].scale;
if (@available(iOS 11, *)) {
CGFloat cur_padding = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom * scale;
padding.bottom = cur_padding;
} else {
CGRect statusFrame = [UIApplication sharedApplication].statusBarFrame;
CGFloat cur_padding = statusFrame.size.height * scale;
padding.top = cur_padding;
}
UIWidgetsMethodMessage(@"ViewportMatricsChanged", @"UIWidgetViewController.keyboardHide", @[]);
}
-(void)keyboardWillChangeFrame:(NSNotification*)notification {
NSDictionary* info = [notification userInfo];
CGFloat bottom = CGRectGetHeight([[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]);
CGFloat scale = [UIScreen mainScreen].scale;
viewInsets.bottom = bottom * scale;
padding.bottom = 0;
UIWidgetsMethodMessage(@"ViewportMatricsChanged", @"UIWidgetViewController.keyboardHide", @[]);
}
-(void)tryLaunch {
}
+ (instancetype)sharedInstance {
static UIWidgetsViewController *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[UIWidgetsViewController alloc] init];
});
return sharedInstance;
}
@end
extern "C"
{
viewMetrics IOSGetViewportPadding()
{
viewMetrics metrics;
viewPadding insets = [[UIWidgetsViewController sharedInstance] viewInsets];
viewPadding padding = [[UIWidgetsViewController sharedInstance] padding];
metrics.insets_bottom = insets.bottom;
metrics.insets_top = insets.top;
metrics.insets_left = insets.left;
metrics.insets_right = insets.right;
metrics.padding_bottom = padding.bottom;
metrics.padding_top = padding.top;
metrics.padding_left = padding.left;
metrics.padding_right = padding.right;
return metrics;
}
}

36
Runtime/Plugins/platform/ios/UIWidgetsViewController.mm.meta


fileFormatVersion: 2
guid: fc3d8a9d616f147929ae9b8898fa01bf
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings: {}
- first:
tvOS: tvOS
second:
enabled: 1
settings: {}
userData:
assetBundleName:
assetBundleVariant:

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

正在加载...
取消
保存