浏览代码

Merge branch 'yczhang' into antialias

/main
Yuncong Zhang 6 年前
当前提交
9813cb26
共有 54 个文件被更改,包括 3031 次插入107 次删除
  1. 17
      README.md
  2. 2
      Runtime/async/timer.cs
  3. 26
      Runtime/editor/editor_utils.cs
  4. 21
      Runtime/editor/editor_window.cs
  5. 93
      Runtime/engine/DisplayMetrics.cs
  6. 48
      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. 2
      Runtime/gestures/multidrag.cs
  12. 3
      Runtime/material/input_decorator.cs
  13. 5
      Runtime/ui/painting/canvas_impl.cs
  14. 15
      Runtime/widgets/app.cs
  15. 56
      Runtime/widgets/basic.cs
  16. 6
      Runtime/widgets/navigator.cs
  17. 329
      Runtime/widgets/scroll_view.cs
  18. 20
      Samples/ReduxSample/CounterApp/CounterAppSample.cs
  19. 4
      Samples/ReduxSample/ObjectFinder/FinderGameObject.cs
  20. 73
      Samples/ReduxSample/ObjectFinder/ObjectFinderApp.cs
  21. 95
      Samples/ReduxSample/ObjectFinder/Reducer.cs
  22. 6
      Samples/ReduxSample/ObjectFinder/StoreProvider.cs
  23. 2
      Samples/UIWidgetsGallery/demo/shrine/shrine_order.cs
  24. 2
      Runtime/redux/redux_thunk.cs.meta
  25. 34
      Runtime/Plugins/platform/ios/UIWidgetsViewController.h
  26. 26
      Runtime/Plugins/platform/ios/UIWidgetsViewController.h.meta
  27. 108
      Runtime/Plugins/platform/ios/UIWidgetsViewController.mm
  28. 36
      Runtime/Plugins/platform/ios/UIWidgetsViewController.mm.meta
  29. 387
      Runtime/material/refresh_indicator.cs
  30. 3
      Runtime/material/refresh_indicator.cs.meta
  31. 397
      Runtime/material/reorderable_list.cs
  32. 3
      Runtime/material/reorderable_list.cs.meta
  33. 348
      Runtime/material/user_accounts_drawer_header.cs
  34. 3
      Runtime/material/user_accounts_drawer_header.cs.meta
  35. 8
      Runtime/redux.meta
  36. 520
      Runtime/widgets/overscroll_indicator.cs
  37. 3
      Runtime/widgets/overscroll_indicator.cs.meta
  38. 63
      Samples/UIWidgetSample/HttpRequestSample.cs
  39. 11
      Samples/UIWidgetSample/HttpRequestSample.cs.meta
  40. 19
      Runtime/redux/redux_logging.cs
  41. 32
      Runtime/redux/redux_thunk.cs
  42. 81
      Runtime/redux/store.cs
  43. 171
      Runtime/redux/widget_redux.cs
  44. 24
      Samples/ReduxSample/ObjectFinder/Middleware.cs
  45. 8
      Samples/ReduxSample/redux.meta
  46. 8
      Samples/ReduxSample/redux_logging.meta
  47. 8
      scripts/node_modules.meta
  48. 0
      /Runtime/redux/redux_thunk.cs.meta
  49. 0
      /Runtime/redux/store.cs.meta
  50. 0
      /Runtime/redux/widget_redux.cs.meta
  51. 0
      /Runtime/redux/redux_logging.cs.meta

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

2
Runtime/async/timer.cs


}
}
class TimerImpl : Timer, IComparable<TimerImpl> {
public class TimerImpl : Timer, IComparable<TimerImpl> {
float _deadline;
readonly Action _callback;
bool _done;

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

48
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 override void OnDisable() {
D.assert(this._windowAdapter != null);
this._windowAdapter.OnDisable();
this._windowAdapter = null;
base.OnDisable();
}
protected virtual Widget createWidget() {
return null;
}

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

2
Runtime/gestures/multidrag.cs


TimeSpan? delay = null)
: base(initialPosition) {
D.assert(delay != null);
this._timer = Window.instance.run(delay ?? Constants.kLongPressTimeout, this._delayPassed, true);
this._timer = Window.instance.run(delay ?? Constants.kLongPressTimeout, this._delayPassed, false);
}
Timer _timer;

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) {

5
Runtime/ui/painting/canvas_impl.cs


foreach (var subLayer in layer.layers) {
cmdBuf.ReleaseTemporaryRT(subLayer.rtID);
}
if (layer.rtID == 0) {
// this is necessary for webgl2. not sure why... just to be safe to disable the scissor.
cmdBuf.DisableScissorRect();
}
}
void _clearLayer(RenderLayer layer) {

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

56
Runtime/widgets/basic.cs


}
}
public class OverflowBox : SingleChildRenderObjectWidget {
public OverflowBox(
Key key = null,
Alignment alignment = null,
float? minWidth = null,
float? maxWidth = null,
float? minHeight = null,
float? maxHeight = null,
Widget child = null
) : base(key: key, child: child) {
this.alignment = alignment ?? Alignment.center;
this.minWidth = minWidth;
this.maxWidth = maxWidth;
this.minHeight = minHeight;
this.maxHeight = maxHeight;
}
public readonly Alignment alignment;
public readonly float? minWidth;
public readonly float? maxWidth;
public readonly float? minHeight;
public readonly float? maxHeight;
public override RenderObject createRenderObject(BuildContext context) {
return new RenderConstrainedOverflowBox(
alignment: this.alignment,
minWidth: this.minWidth,
maxWidth: this.maxWidth,
minHeight: this.minHeight,
maxHeight: this.maxHeight
);
}
public override void updateRenderObject(BuildContext context, RenderObject _renderObject) {
RenderConstrainedOverflowBox renderObject = _renderObject as RenderConstrainedOverflowBox;
renderObject.alignment = this.alignment;
renderObject.minWidth = this.minWidth;
renderObject.maxWidth = this.maxWidth;
renderObject.minHeight = this.minHeight;
renderObject.maxHeight = this.maxHeight;
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new DiagnosticsProperty<Alignment>("alignment", this.alignment));
properties.add(new FloatProperty("minWidth", this.minWidth, defaultValue: null));
properties.add(new FloatProperty("maxWidth", this.maxWidth, defaultValue: null));
properties.add(new FloatProperty("minHeight", this.minHeight, defaultValue: null));
properties.add(new FloatProperty("maxHeight", this.maxHeight, defaultValue: null));
}
}
public class SizedBox : SingleChildRenderObjectWidget {
public SizedBox(Key key = null, float? width = null, float? height = null, Widget child = null)
: base(key: key, child: child) {

6
Runtime/widgets/navigator.cs


get { return false; }
}
public object currentResult {
public virtual object currentResult {
get { return null; }
}

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

329
Runtime/widgets/scroll_view.cs


using System;
using com.unity.uiwidgets.Runtime.rendering;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;

base.debugFillProperties(properties);
properties.add(new FloatProperty("itemExtent", this.itemExtent,
defaultValue: Diagnostics.kNullDefaultValue));
}
}
public class GridView : BoxScrollView {
public GridView(
Key key = null,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
SliverGridDelegate gridDelegate = null,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null,
List<Widget> children = null
) : base(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
cacheExtent: cacheExtent
) {
D.assert(gridDelegate != null);
this.childrenDelegate = new SliverChildListDelegate(
children ?? new List<Widget>(),
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries
);
}
public GridView(
Key key = null,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
SliverGridDelegate gridDelegate = null,
IndexedWidgetBuilder itemBuilder = null,
int? itemCount = null,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null
) : base(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
cacheExtent: cacheExtent
) {
this.gridDelegate = gridDelegate;
this.childrenDelegate = new SliverChildBuilderDelegate(
itemBuilder,
childCount: itemCount,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries
);
}
public static GridView builder(
Key key = null,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
SliverGridDelegate gridDelegate = null,
IndexedWidgetBuilder itemBuilder = null,
int? itemCount = null,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null
) {
return new GridView(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
gridDelegate: gridDelegate,
itemBuilder: itemBuilder,
itemCount: itemCount,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
cacheExtent: cacheExtent
);
}
public GridView(
Key key = null,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
SliverGridDelegate gridDelegate = null,
SliverChildDelegate childrenDelegate = null,
float? cacheExtent = null
) : base(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
cacheExtent: cacheExtent
) {
D.assert(gridDelegate != null);
D.assert(childrenDelegate != null);
this.gridDelegate = gridDelegate;
this.childrenDelegate = childrenDelegate;
}
public static GridView custom(
Key key = null,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
SliverGridDelegate gridDelegate = null,
SliverChildDelegate childrenDelegate = null,
float? cacheExtent = null
) {
return new GridView(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
gridDelegate: gridDelegate,
childrenDelegate: childrenDelegate,
cacheExtent: cacheExtent
);
}
public GridView(
Key key = null,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
int? crossAxisCount = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null,
List<Widget> children = null
) : base(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
cacheExtent: cacheExtent
) {
this.gridDelegate = new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount ?? 0,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio
);
this.childrenDelegate = new SliverChildListDelegate(
children ?? new List<Widget>(),
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries
);
}
public static GridView count(
Key key = null,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
int? crossAxisCount = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
float? cacheExtent = null,
List<Widget> children = null
) {
return new GridView(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
crossAxisCount: crossAxisCount,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
cacheExtent: cacheExtent,
children: children
);
}
public GridView(
Key key = null,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
float? maxCrossAxisExtent = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
bool addSemanticIndexes = true,
List<Widget> children = null
) : base(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding
) {
this.gridDelegate = new SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent ?? 0,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio
);
this.childrenDelegate = new SliverChildListDelegate(
children ?? new List<Widget> { },
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries
);
}
public static GridView extent(
Key key = null,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller = null,
bool? primary = null,
ScrollPhysics physics = null,
bool shrinkWrap = false,
EdgeInsets padding = null,
float? maxCrossAxisExtent = null,
float mainAxisSpacing = 0.0f,
float crossAxisSpacing = 0.0f,
float childAspectRatio = 1.0f,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
List<Widget> children = null
) {
return new GridView(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
padding: padding,
maxCrossAxisExtent: maxCrossAxisExtent,
mainAxisSpacing: mainAxisSpacing,
crossAxisSpacing: crossAxisSpacing,
childAspectRatio: childAspectRatio,
addAutomaticKeepAlives: addAutomaticKeepAlives,
addRepaintBoundaries: addRepaintBoundaries,
children: children
);
}
public readonly SliverGridDelegate gridDelegate;
public readonly SliverChildDelegate childrenDelegate;
protected override Widget buildChildLayout(BuildContext context) {
return new SliverGrid(
layoutDelegate: this.childrenDelegate,
gridDelegate: this.gridDelegate
);
}
}
}

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
Samples/UIWidgetsGallery/demo/shrine/shrine_order.cs


public Order order;
public new Order currentResult {
public override object currentResult {
get { return this.order; }
}

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:

387
Runtime/material/refresh_indicator.cs


using System;
using System.Collections.Generic;
using RSG;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
namespace Unity.UIWidgets.material {
class RefreshIndicatorUtils {
public const float _kDragContainerExtentPercentage = 0.25f;
public const float _kDragSizeFactorLimit = 1.5f;
public static readonly TimeSpan _kIndicatorSnapDuration = new TimeSpan(0, 0, 0, 0, 150);
public static readonly TimeSpan _kIndicatorScaleDuration = new TimeSpan(0, 0, 0, 0, 200);
}
public delegate Promise RefreshCallback();
enum _RefreshIndicatorMode {
drag, // Pointer is down.
armed, // Dragged far enough that an up event will run the onRefresh callback.
snap, // Animating to the indicator"s final "displacement".
refresh, // Running the refresh callback.
done, // Animating the indicator"s fade-out after refreshing.
canceled, // Animating the indicator"s fade-out after not arming.
}
public class RefreshIndicator : StatefulWidget {
public RefreshIndicator(
Key key = null,
Widget child = null,
float displacement = 40.0f,
RefreshCallback onRefresh = null,
Color color = null,
Color backgroundColor = null,
ScrollNotificationPredicate notificationPredicate = null
) : base(key: key) {
D.assert(child != null);
D.assert(onRefresh != null);
this.child = child;
this.displacement = displacement;
this.onRefresh = onRefresh;
this.color = color;
this.backgroundColor = backgroundColor;
this.notificationPredicate = notificationPredicate ?? ScrollNotification.defaultScrollNotificationPredicate;
}
public readonly Widget child;
public readonly float displacement;
public readonly RefreshCallback onRefresh;
public readonly Color color;
public readonly Color backgroundColor;
public readonly ScrollNotificationPredicate notificationPredicate;
public override State createState() {
return new RefreshIndicatorState();
}
}
public class RefreshIndicatorState : TickerProviderStateMixin<RefreshIndicator> {
AnimationController _positionController;
AnimationController _scaleController;
Animation<float> _positionFactor;
Animation<float> _scaleFactor;
Animation<float> _value;
Animation<Color> _valueColor;
_RefreshIndicatorMode? _mode;
Promise _pendingRefreshFuture;
bool? _isIndicatorAtTop;
float? _dragOffset;
static readonly Animatable<float> _threeQuarterTween = new FloatTween(begin: 0.0f, end: 0.75f);
static readonly Animatable<float> _kDragSizeFactorLimitTween =
new FloatTween(begin: 0.0f, end: RefreshIndicatorUtils._kDragSizeFactorLimit);
static readonly Animatable<float> _oneToZeroTween = new FloatTween(begin: 1.0f, end: 0.0f);
public RefreshIndicatorState() {
}
public override void initState() {
base.initState();
this._positionController = new AnimationController(vsync: this);
this._positionFactor = this._positionController.drive(_kDragSizeFactorLimitTween);
this._value =
this._positionController
.drive(_threeQuarterTween); // The "value" of the circular progress indicator during a drag.
this._scaleController = new AnimationController(vsync: this);
this._scaleFactor = this._scaleController.drive(_oneToZeroTween);
}
public override void didChangeDependencies() {
ThemeData theme = Theme.of(this.context);
this._valueColor = this._positionController.drive(
new ColorTween(
begin: (this.widget.color ?? theme.accentColor).withOpacity(0.0f),
end: (this.widget.color ?? theme.accentColor).withOpacity(1.0f)
).chain(new CurveTween(
curve: new Interval(0.0f, 1.0f / RefreshIndicatorUtils._kDragSizeFactorLimit)
))
);
base.didChangeDependencies();
}
public override void dispose() {
this._positionController.dispose();
this._scaleController.dispose();
base.dispose();
}
bool _handleScrollNotification(ScrollNotification notification) {
if (!this.widget.notificationPredicate(notification)) {
return false;
}
if (notification is ScrollStartNotification && notification.metrics.extentBefore() == 0.0f &&
this._mode == null && this._start(notification.metrics.axisDirection)) {
this.setState(() => { this._mode = _RefreshIndicatorMode.drag; });
return false;
}
bool? indicatorAtTopNow = null;
switch (notification.metrics.axisDirection) {
case AxisDirection.down:
indicatorAtTopNow = true;
break;
case AxisDirection.up:
indicatorAtTopNow = false;
break;
case AxisDirection.left:
case AxisDirection.right:
indicatorAtTopNow = null;
break;
}
if (indicatorAtTopNow != this._isIndicatorAtTop) {
if (this._mode == _RefreshIndicatorMode.drag || this._mode == _RefreshIndicatorMode.armed) {
this._dismiss(_RefreshIndicatorMode.canceled);
}
}
else if (notification is ScrollUpdateNotification) {
if (this._mode == _RefreshIndicatorMode.drag || this._mode == _RefreshIndicatorMode.armed) {
if (notification.metrics.extentBefore() > 0.0f) {
this._dismiss(_RefreshIndicatorMode.canceled);
}
else {
this._dragOffset -= (notification as ScrollUpdateNotification).scrollDelta;
this._checkDragOffset(notification.metrics.viewportDimension);
}
}
if (this._mode == _RefreshIndicatorMode.armed &&
(notification as ScrollUpdateNotification).dragDetails == null) {
this._show();
}
}
else if (notification is OverscrollNotification) {
if (this._mode == _RefreshIndicatorMode.drag || this._mode == _RefreshIndicatorMode.armed) {
this._dragOffset -= (notification as OverscrollNotification).overscroll / 2.0f;
this._checkDragOffset(notification.metrics.viewportDimension);
}
}
else if (notification is ScrollEndNotification) {
switch (this._mode) {
case _RefreshIndicatorMode.armed:
this._show();
break;
case _RefreshIndicatorMode.drag:
this._dismiss(_RefreshIndicatorMode.canceled);
break;
default:
break;
}
}
return false;
}
bool _handleGlowNotification(OverscrollIndicatorNotification notification) {
if (notification.depth != 0 || !notification.leading) {
return false;
}
if (this._mode == _RefreshIndicatorMode.drag) {
notification.disallowGlow();
return true;
}
return false;
}
bool _start(AxisDirection direction) {
D.assert(this._mode == null);
D.assert(this._isIndicatorAtTop == null);
D.assert(this._dragOffset == null);
switch (direction) {
case AxisDirection.down:
this._isIndicatorAtTop = true;
break;
case AxisDirection.up:
this._isIndicatorAtTop = false;
break;
case AxisDirection.left:
case AxisDirection.right:
this._isIndicatorAtTop = null;
return false;
}
this._dragOffset = 0.0f;
this._scaleController.setValue(0.0f);
this._positionController.setValue(0.0f);
return true;
}
void _checkDragOffset(float containerExtent) {
D.assert(this._mode == _RefreshIndicatorMode.drag || this._mode == _RefreshIndicatorMode.armed);
float? newValue = this._dragOffset /
(containerExtent * RefreshIndicatorUtils._kDragContainerExtentPercentage);
if (this._mode == _RefreshIndicatorMode.armed) {
newValue = Mathf.Max(newValue ?? 0.0f, 1.0f / RefreshIndicatorUtils._kDragSizeFactorLimit);
}
this._positionController.setValue(newValue?.clamp(0.0f, 1.0f) ?? 0.0f); // this triggers various rebuilds
if (this._mode == _RefreshIndicatorMode.drag && this._valueColor.value.alpha == 0xFF) {
this._mode = _RefreshIndicatorMode.armed;
}
}
IPromise _dismiss(_RefreshIndicatorMode newMode) {
D.assert(newMode == _RefreshIndicatorMode.canceled || newMode == _RefreshIndicatorMode.done);
this.setState(() => { this._mode = newMode; });
switch (this._mode) {
case _RefreshIndicatorMode.done:
return this._scaleController
.animateTo(1.0f, duration: RefreshIndicatorUtils._kIndicatorScaleDuration).Then(() => {
if (this.mounted && this._mode == newMode) {
this._dragOffset = null;
this._isIndicatorAtTop = null;
this.setState(() => { this._mode = null; });
}
});
case _RefreshIndicatorMode.canceled:
return this._positionController
.animateTo(0.0f, duration: RefreshIndicatorUtils._kIndicatorScaleDuration).Then(() => {
if (this.mounted && this._mode == newMode) {
this._dragOffset = null;
this._isIndicatorAtTop = null;
this.setState(() => { this._mode = null; });
}
});
default:
throw new Exception("Unknown refresh indicator mode: " + this._mode);
}
}
void _show() {
D.assert(this._mode != _RefreshIndicatorMode.refresh);
D.assert(this._mode != _RefreshIndicatorMode.snap);
Promise completer = new Promise();
this._pendingRefreshFuture = completer;
this._mode = _RefreshIndicatorMode.snap;
this._positionController
.animateTo(1.0f / RefreshIndicatorUtils._kDragSizeFactorLimit,
duration: RefreshIndicatorUtils._kIndicatorSnapDuration)
.Then(() => {
if (this.mounted && this._mode == _RefreshIndicatorMode.snap) {
D.assert(this.widget.onRefresh != null);
this.setState(() => { this._mode = _RefreshIndicatorMode.refresh; });
Promise refreshResult = this.widget.onRefresh();
D.assert(() => {
if (refreshResult == null) {
UIWidgetsError.reportError(new UIWidgetsErrorDetails(
exception: new UIWidgetsError(
"The onRefresh callback returned null.\n" +
"The RefreshIndicator onRefresh callback must return a Promise."
),
context: "when calling onRefresh",
library: "material library"
));
}
return true;
});
if (refreshResult == null) {
return;
}
refreshResult.Then(() => {
if (this.mounted && this._mode == _RefreshIndicatorMode.refresh) {
completer.Resolve();
this._dismiss(_RefreshIndicatorMode.done);
}
});
}
});
}
Promise show(bool atTop = true) {
if (this._mode != _RefreshIndicatorMode.refresh && this._mode != _RefreshIndicatorMode.snap) {
if (this._mode == null) {
this._start(atTop ? AxisDirection.down : AxisDirection.up);
}
this._show();
}
return this._pendingRefreshFuture;
}
GlobalKey _key = GlobalKey.key();
public override Widget build(BuildContext context) {
D.assert(MaterialD.debugCheckHasMaterialLocalizations(context));
Widget child = new NotificationListener<ScrollNotification>(
key: this._key,
onNotification: this._handleScrollNotification,
child: new NotificationListener<OverscrollIndicatorNotification>(
onNotification: this._handleGlowNotification,
child: this.widget.child
)
);
if (this._mode == null) {
D.assert(this._dragOffset == null);
D.assert(this._isIndicatorAtTop == null);
return child;
}
D.assert(this._dragOffset != null);
D.assert(this._isIndicatorAtTop != null);
bool showIndeterminateIndicator =
this._mode == _RefreshIndicatorMode.refresh || this._mode == _RefreshIndicatorMode.done;
return new Stack(
children: new List<Widget> {
child,
new Positioned(
top: this._isIndicatorAtTop == true ? 0.0f : (float?) null,
bottom: this._isIndicatorAtTop != true ? 0.0f : (float?) null,
left: 0.0f,
right: 0.0f,
child: new SizeTransition(
axisAlignment: this._isIndicatorAtTop == true ? 1.0f : -1.0f,
sizeFactor: this._positionFactor, // this is what brings it down
child: new Container(
padding: this._isIndicatorAtTop == true
? EdgeInsets.only(top: this.widget.displacement)
: EdgeInsets.only(bottom: this.widget.displacement),
alignment: this._isIndicatorAtTop == true
? Alignment.topCenter
: Alignment.bottomCenter,
child: new ScaleTransition(
scale: this._scaleFactor,
child: new AnimatedBuilder(
animation: this._positionController,
builder: (BuildContext _context, Widget _child) => {
return new RefreshProgressIndicator(
value: showIndeterminateIndicator ? (float?) null : this._value.value,
valueColor: this._valueColor,
backgroundColor: this.widget.backgroundColor
);
}
)
)
)
)
)
}
);
}
}
}

3
Runtime/material/refresh_indicator.cs.meta


fileFormatVersion: 2
guid: 74dd879101fe4541a5b42619cf4f309c
timeCreated: 1554344854

397
Runtime/material/reorderable_list.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
namespace Unity.UIWidgets.material {
public delegate void ReorderCallback(int oldIndex, int newIndex);
public class ReorderableListView : StatefulWidget {
public ReorderableListView(
Widget header = null,
List<Widget> children = null,
ReorderCallback onReorder = null,
Axis scrollDirection = Axis.vertical,
EdgeInsets padding = null
) {
D.assert(onReorder != null);
D.assert(children != null);
D.assert(
children.All((Widget w) => w.key != null),
"All children of this widget must have a key."
);
this.header = header;
this.children = children;
this.scrollDirection = scrollDirection;
this.padding = padding;
this.onReorder = onReorder;
}
public readonly Widget header;
public readonly List<Widget> children;
public readonly Axis scrollDirection;
public readonly EdgeInsets padding;
public readonly ReorderCallback onReorder;
public override State createState() {
return new _ReorderableListViewState();
}
}
class _ReorderableListViewState : State<ReorderableListView> {
GlobalKey _overlayKey = GlobalKey.key(debugLabel: "$ReorderableListView overlay key");
OverlayEntry _listOverlayEntry;
public override void initState() {
base.initState();
this._listOverlayEntry = new OverlayEntry(
opaque: true,
builder: (BuildContext context) => {
return new _ReorderableListContent(
header: this.widget.header,
children: this.widget.children,
scrollDirection: this.widget.scrollDirection,
onReorder: this.widget.onReorder,
padding: this.widget.padding
);
}
);
}
public override Widget build(BuildContext context) {
return new Overlay(
key: this._overlayKey,
initialEntries: new List<OverlayEntry> {
this._listOverlayEntry
});
}
}
class _ReorderableListContent : StatefulWidget {
public _ReorderableListContent(
Widget header,
List<Widget> children,
Axis scrollDirection,
EdgeInsets padding,
ReorderCallback onReorder
) {
this.header = header;
this.children = children;
this.scrollDirection = scrollDirection;
this.padding = padding;
this.onReorder = onReorder;
}
public readonly Widget header;
public readonly List<Widget> children;
public readonly Axis scrollDirection;
public readonly EdgeInsets padding;
public readonly ReorderCallback onReorder;
public override State createState() {
return new _ReorderableListContentState();
}
}
class _ReorderableListContentState : TickerProviderStateMixin<_ReorderableListContent> {
const float _defaultDropAreaExtent = 100.0f;
const float _dropAreaMargin = 8.0f;
readonly TimeSpan _reorderAnimationDuration = new TimeSpan(0, 0, 0, 0, 200);
readonly TimeSpan _scrollAnimationDuration = new TimeSpan(0, 0, 0, 0, 200);
ScrollController _scrollController;
AnimationController _entranceController;
AnimationController _ghostController;
Key _dragging;
Size _draggingFeedbackSize;
int _dragStartIndex = 0;
int _ghostIndex = 0;
int _currentIndex = 0;
int _nextIndex = 0;
bool _scrolling = false;
float _dropAreaExtent {
get {
if (this._draggingFeedbackSize == null) {
return _defaultDropAreaExtent;
}
float dropAreaWithoutMargin;
switch (this.widget.scrollDirection) {
case Axis.horizontal:
dropAreaWithoutMargin = this._draggingFeedbackSize.width;
break;
case Axis.vertical:
default:
dropAreaWithoutMargin = this._draggingFeedbackSize.height;
break;
}
return dropAreaWithoutMargin + _dropAreaMargin;
}
}
public override void initState() {
base.initState();
this._entranceController = new AnimationController(vsync: this, duration: this._reorderAnimationDuration);
this._ghostController = new AnimationController(vsync: this, duration: this._reorderAnimationDuration);
this._entranceController.addStatusListener(this._onEntranceStatusChanged);
}
public override void didChangeDependencies() {
this._scrollController = PrimaryScrollController.of(this.context) ?? new ScrollController();
base.didChangeDependencies();
}
public override void dispose() {
this._entranceController.dispose();
this._ghostController.dispose();
base.dispose();
}
void _requestAnimationToNextIndex() {
if (this._entranceController.isCompleted) {
this._ghostIndex = this._currentIndex;
if (this._nextIndex == this._currentIndex) {
return;
}
this._currentIndex = this._nextIndex;
this._ghostController.reverse(from: 1.0f);
this._entranceController.forward(from: 0.0f);
}
}
void _onEntranceStatusChanged(AnimationStatus status) {
if (status == AnimationStatus.completed) {
this.setState(() => { this._requestAnimationToNextIndex(); });
}
}
void _scrollTo(BuildContext context) {
if (this._scrolling) {
return;
}
RenderObject contextObject = context.findRenderObject();
RenderAbstractViewport viewport = RenderViewportUtils.of(contextObject);
D.assert(viewport != null);
float margin = this._dropAreaExtent;
float scrollOffset = this._scrollController.offset;
float topOffset = Mathf.Max(this._scrollController.position.minScrollExtent,
viewport.getOffsetToReveal(contextObject, 0.0f).offset - margin
);
float bottomOffset = Mathf.Min(this._scrollController.position.maxScrollExtent,
viewport.getOffsetToReveal(contextObject, 1.0f).offset + margin
);
bool onScreen = scrollOffset <= topOffset && scrollOffset >= bottomOffset;
if (!onScreen) {
this._scrolling = true;
this._scrollController.position.animateTo(
scrollOffset < bottomOffset ? bottomOffset : topOffset,
duration: this._scrollAnimationDuration,
curve: Curves.easeInOut
).Then(() => { this.setState(() => { this._scrolling = false; }); });
}
}
Widget _buildContainerForScrollDirection(List<Widget> children = null) {
switch (this.widget.scrollDirection) {
case Axis.horizontal:
return new Row(children: children);
case Axis.vertical:
default:
return new Column(children: children);
}
}
Widget _wrap(Widget toWrap, int index, BoxConstraints constraints) {
D.assert(toWrap.key != null);
GlobalObjectKey<State<_ReorderableListContent>> keyIndexGlobalKey = new GlobalObjectKey<State<_ReorderableListContent>>(toWrap.key);
void onDragStarted() {
this.setState(() => {
this._dragging = toWrap.key;
this._dragStartIndex = index;
this._ghostIndex = index;
this._currentIndex = index;
this._entranceController.setValue(1.0f);
this._draggingFeedbackSize = keyIndexGlobalKey.currentContext.size;
});
}
void reorder(int startIndex, int endIndex) {
this.setState(() => {
if (startIndex != endIndex) {
this.widget.onReorder(startIndex, endIndex);
}
this._ghostController.reverse(from: 0.1f);
this._entranceController.reverse(from: 0.1f);
this._dragging = null;
});
}
void onDragEnded() {
reorder(this._dragStartIndex, this._currentIndex);
}
Widget wrapWithKeyedSubtree() {
return new KeyedSubtree(
key: keyIndexGlobalKey,
child: toWrap
);
}
Widget buildDragTarget(BuildContext context, List<Key> acceptedCandidates, List<Key> rejectedCandidates) {
Widget toWrapWithKeyedSubtree = wrapWithKeyedSubtree();
Widget child = new LongPressDraggable<Key>(
maxSimultaneousDrags: 1,
axis: this.widget.scrollDirection,
data: toWrap.key,
feedback: new Container(
alignment: Alignment.topLeft,
// These constraints will limit the cross axis of the drawn widget.
constraints: constraints,
child: new Material(
elevation: 6.0f,
child: toWrapWithKeyedSubtree
)
),
child: this._dragging == toWrap.key ? new SizedBox() : toWrapWithKeyedSubtree,
childWhenDragging: new SizedBox(),
dragAnchor: DragAnchor.child,
onDragStarted: onDragStarted,
onDragCompleted: onDragEnded,
onDraggableCanceled: (Velocity velocity, Offset offset) => { onDragEnded(); }
);
if (index >= this.widget.children.Count) {
child = toWrap;
}
Widget spacing;
switch (this.widget.scrollDirection) {
case Axis.horizontal:
spacing = new SizedBox(width: this._dropAreaExtent);
break;
case Axis.vertical:
default:
spacing = new SizedBox(height: this._dropAreaExtent);
break;
}
if (this._currentIndex == index) {
return this._buildContainerForScrollDirection(children: new List<Widget> {
new SizeTransition(
sizeFactor: this._entranceController,
axis: this.widget.scrollDirection,
child: spacing
),
child
});
}
if (this._ghostIndex == index) {
return this._buildContainerForScrollDirection(children: new List<Widget> {
new SizeTransition(
sizeFactor: this._ghostController,
axis: this.widget.scrollDirection,
child: spacing
),
child
});
}
return child;
}
return new Builder(builder: (BuildContext context) => {
return new DragTarget<Key>(
builder: buildDragTarget,
onWillAccept: (Key toAccept) => {
this.setState(() => {
this._nextIndex = index;
this._requestAnimationToNextIndex();
});
this._scrollTo(context);
return this._dragging == toAccept && toAccept != toWrap.key;
},
onAccept: (Key accepted) => { },
onLeave: (Key leaving) => { }
);
});
}
public override Widget build(BuildContext context) {
D.assert(MaterialD.debugCheckHasMaterialLocalizations(context));
return new LayoutBuilder(builder: (BuildContext _, BoxConstraints constraints) => {
List<Widget> wrappedChildren = new List<Widget> { };
if (this.widget.header != null) {
wrappedChildren.Add(this.widget.header);
}
for (int i = 0; i < this.widget.children.Count; i += 1) {
wrappedChildren.Add(this._wrap(this.widget.children[i], i, constraints));
}
Key endWidgetKey = Key.key("DraggableList - End Widget");
Widget finalDropArea;
switch (this.widget.scrollDirection) {
case Axis.horizontal:
finalDropArea = new SizedBox(
key: endWidgetKey,
width: _defaultDropAreaExtent,
height: constraints.maxHeight
);
break;
case Axis.vertical:
default:
finalDropArea = new SizedBox(
key: endWidgetKey,
height: _defaultDropAreaExtent,
width: constraints.maxWidth
);
break;
}
wrappedChildren.Add(this._wrap(
finalDropArea, this.widget.children.Count,
constraints)
);
return new SingleChildScrollView(
scrollDirection: this.widget.scrollDirection,
child: this._buildContainerForScrollDirection(children: wrappedChildren),
padding: this.widget.padding,
controller: this._scrollController
);
});
}
}
}

3
Runtime/material/reorderable_list.cs.meta


fileFormatVersion: 2
guid: 730da7185538491389639e2cc7099a21
timeCreated: 1554301017

348
Runtime/material/user_accounts_drawer_header.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Transform = Unity.UIWidgets.widgets.Transform;
namespace Unity.UIWidgets.material {
class UserAccountsDrawerHeaderUtils {
public const float _kAccountDetailsHeight = 56.0f;
}
class _AccountPictures : StatelessWidget {
public _AccountPictures(
Key key = null,
Widget currentAccountPicture = null,
List<Widget> otherAccountsPictures = null
) : base(key: key) {
this.currentAccountPicture = currentAccountPicture;
this.otherAccountsPictures = otherAccountsPictures;
}
public readonly Widget currentAccountPicture;
public readonly List<Widget> otherAccountsPictures;
public override Widget build(BuildContext context) {
return new Stack(
children: new List<Widget> {
new Positioned(
top: 0.0f,
right: 0.0f,
child: new Row(
children: (this.otherAccountsPictures ?? new List<Widget> { })
.GetRange(0, Math.Min(3, this.otherAccountsPictures?.Count ?? 0))
.Select<Widget, Widget>(
(Widget picture) => {
return new Padding(
padding: EdgeInsets.only(left: 8.0f),
child: new Container(
padding: EdgeInsets.only(left: 8.0f, bottom: 8.0f),
width: 48.0f,
height: 48.0f,
child: picture
)
);
}).ToList()
)
),
new Positioned(
top: 0.0f,
child: new SizedBox(
width: 72.0f,
height: 72.0f,
child: this.currentAccountPicture
)
)
}
);
}
}
class _AccountDetails : StatefulWidget {
public _AccountDetails(
Key key = null,
Widget accountName = null,
Widget accountEmail = null,
VoidCallback onTap = null,
bool? isOpen = null
) : base(key: key) {
D.assert(accountName != null);
D.assert(accountEmail != null);
this.accountName = accountName;
this.accountEmail = accountEmail;
this.onTap = onTap;
this.isOpen = isOpen;
}
public readonly Widget accountName;
public readonly Widget accountEmail;
public readonly VoidCallback onTap;
public readonly bool? isOpen;
public override State createState() {
return new _AccountDetailsState();
}
}
class _AccountDetailsState : SingleTickerProviderStateMixin<_AccountDetails> {
Animation<float> _animation;
AnimationController _controller;
public override void initState() {
base.initState();
this._controller = new AnimationController(
value: this.widget.isOpen == true ? 1.0f : 0.0f,
duration: new TimeSpan(0, 0, 0, 0, 200),
vsync: this
);
this._animation = new CurvedAnimation(
parent: this._controller,
curve: Curves.fastOutSlowIn,
reverseCurve: Curves.fastOutSlowIn.flipped
);
this._animation.addListener(() => this.setState(() => { }));
}
public override void dispose() {
this._controller.dispose();
base.dispose();
}
public override void didUpdateWidget(StatefulWidget _oldWidget) {
base.didUpdateWidget(_oldWidget);
_AccountDetails oldWidget = _oldWidget as _AccountDetails;
if (this._animation.status == AnimationStatus.dismissed ||
this._animation.status == AnimationStatus.reverse) {
this._controller.forward();
}
else {
this._controller.reverse();
}
}
public override Widget build(BuildContext context) {
D.assert(WidgetsD.debugCheckHasDirectionality(context));
D.assert(MaterialD.debugCheckHasMaterialLocalizations(context));
D.assert(MaterialD.debugCheckHasMaterialLocalizations(context));
ThemeData theme = Theme.of(context);
List<Widget> children = new List<Widget> { };
if (this.widget.accountName != null) {
Widget accountNameLine = new LayoutId(
id: _AccountDetailsLayout.accountName,
child: new Padding(
padding: EdgeInsets.symmetric(vertical: 2.0f),
child: new DefaultTextStyle(
style: theme.primaryTextTheme.body2,
overflow: TextOverflow.ellipsis,
child: this.widget.accountName
)
)
);
children.Add(accountNameLine);
}
if (this.widget.accountEmail != null) {
Widget accountEmailLine = new LayoutId(
id: _AccountDetailsLayout.accountEmail,
child: new Padding(
padding: EdgeInsets.symmetric(vertical: 2.0f),
child: new DefaultTextStyle(
style: theme.primaryTextTheme.body1,
overflow: TextOverflow.ellipsis,
child: this.widget.accountEmail
)
)
);
children.Add(accountEmailLine);
}
if (this.widget.onTap != null) {
MaterialLocalizations localizations = MaterialLocalizations.of(context);
Widget dropDownIcon = new LayoutId(
id: _AccountDetailsLayout.dropdownIcon,
child: new SizedBox(
height: UserAccountsDrawerHeaderUtils._kAccountDetailsHeight,
width: UserAccountsDrawerHeaderUtils._kAccountDetailsHeight,
child: new Center(
child: Transform.rotate(
degree: this._animation.value * Mathf.PI,
child: new Icon(
Icons.arrow_drop_down,
color: Colors.white
)
)
)
)
);
children.Add(dropDownIcon);
}
Widget accountDetails = new CustomMultiChildLayout(
layoutDelegate: new _AccountDetailsLayout(),
children: children
);
if (this.widget.onTap != null) {
accountDetails = new InkWell(
onTap: this.widget.onTap == null ? (GestureTapCallback) null : () => { this.widget.onTap(); },
child: accountDetails
);
}
return new SizedBox(
height: UserAccountsDrawerHeaderUtils._kAccountDetailsHeight,
child: accountDetails
);
}
}
class _AccountDetailsLayout : MultiChildLayoutDelegate {
public _AccountDetailsLayout() {
}
public const string accountName = "accountName";
public const string accountEmail = "accountEmail";
public const string dropdownIcon = "dropdownIcon";
public override void performLayout(Size size) {
Size iconSize = null;
if (this.hasChild(dropdownIcon)) {
iconSize = this.layoutChild(dropdownIcon, BoxConstraints.loose(size));
this.positionChild(dropdownIcon, this._offsetForIcon(size, iconSize));
}
string bottomLine = this.hasChild(accountEmail)
? accountEmail
: (this.hasChild(accountName) ? accountName : null);
if (bottomLine != null) {
Size constraintSize = iconSize == null ? size : size - new Offset(iconSize.width, 0.0f);
iconSize = iconSize ?? new Size(UserAccountsDrawerHeaderUtils._kAccountDetailsHeight,
UserAccountsDrawerHeaderUtils._kAccountDetailsHeight);
Size bottomLineSize = this.layoutChild(bottomLine, BoxConstraints.loose(constraintSize));
Offset bottomLineOffset = this._offsetForBottomLine(size, iconSize, bottomLineSize);
this.positionChild(bottomLine, bottomLineOffset);
if (bottomLine == accountEmail && this.hasChild(accountName)) {
Size nameSize = this.layoutChild(accountName, BoxConstraints.loose(constraintSize));
this.positionChild(accountName, this._offsetForName(size, nameSize, bottomLineOffset));
}
}
}
public override bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) {
return true;
}
Offset _offsetForIcon(Size size, Size iconSize) {
return new Offset(size.width - iconSize.width, size.height - iconSize.height);
}
Offset _offsetForBottomLine(Size size, Size iconSize, Size bottomLineSize) {
float y = size.height - 0.5f * iconSize.height - 0.5f * bottomLineSize.height;
return new Offset(0.0f, y);
}
Offset _offsetForName(Size size, Size nameSize, Offset bottomLineOffset) {
float y = bottomLineOffset.dy - nameSize.height;
return new Offset(0.0f, y);
}
}
public class UserAccountsDrawerHeader : StatefulWidget {
public UserAccountsDrawerHeader(
Key key = null,
Decoration decoration = null,
EdgeInsets margin = null,
Widget currentAccountPicture = null,
List<Widget> otherAccountsPictures = null,
Widget accountName = null,
Widget accountEmail = null,
VoidCallback onDetailsPressed = null
) : base(key: key) {
D.assert(accountName != null);
D.assert(accountEmail != null);
this.decoration = decoration;
this.margin = margin ?? EdgeInsets.only(bottom: 8.0f);
this.currentAccountPicture = currentAccountPicture;
this.otherAccountsPictures = otherAccountsPictures;
this.accountName = accountName;
this.accountEmail = accountEmail;
this.onDetailsPressed = onDetailsPressed;
}
public readonly Decoration decoration;
public readonly EdgeInsets margin;
public readonly Widget currentAccountPicture;
public readonly List<Widget> otherAccountsPictures;
public readonly Widget accountName;
public readonly Widget accountEmail;
public readonly VoidCallback onDetailsPressed;
public override State createState() {
return new _UserAccountsDrawerHeaderState();
}
}
class _UserAccountsDrawerHeaderState : State<UserAccountsDrawerHeader> {
bool _isOpen = false;
void _handleDetailsPressed() {
this.setState(() => { this._isOpen = !this._isOpen; });
this.widget.onDetailsPressed();
}
public override Widget build(BuildContext context) {
D.assert(MaterialD.debugCheckHasMaterial(context));
D.assert(MaterialD.debugCheckHasMaterialLocalizations(context));
return new DrawerHeader(
decoration: this.widget.decoration ?? new BoxDecoration(
color: Theme.of(context).primaryColor
),
margin: this.widget.margin,
padding: EdgeInsets.only(top: 16.0f, left: 16.0f),
child: new SafeArea(
bottom: false,
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: new List<Widget> {
new Expanded(
child: new Padding(
padding: EdgeInsets.only(right: 16.0f),
child: new _AccountPictures(
currentAccountPicture: this.widget.currentAccountPicture,
otherAccountsPictures: this.widget.otherAccountsPictures
)
)
),
new _AccountDetails(
accountName: this.widget.accountName,
accountEmail: this.widget.accountEmail,
isOpen: this._isOpen,
onTap: this.widget.onDetailsPressed == null
? (VoidCallback) null
: () => { this._handleDetailsPressed(); })
}
)
)
);
}
}
}

3
Runtime/material/user_accounts_drawer_header.cs.meta


fileFormatVersion: 2
guid: fb34d1a7ff484d05b8074a10730d51a5
timeCreated: 1554352270

8
Runtime/redux.meta


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

520
Runtime/widgets/overscroll_indicator.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.physics;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.scheduler;
using Unity.UIWidgets.ui;
using UnityEngine;
using Canvas = Unity.UIWidgets.ui.Canvas;
using Color = Unity.UIWidgets.ui.Color;
using Rect = Unity.UIWidgets.ui.Rect;
namespace Unity.UIWidgets.widgets {
public class GlowingOverscrollIndicator : StatefulWidget {
public GlowingOverscrollIndicator(
Key key = null,
bool showLeading = true,
bool showTrailing = true,
AxisDirection axisDirection = AxisDirection.up,
Color color = null,
ScrollNotificationPredicate notificationPredicate = null,
Widget child = null
) : base(key: key) {
D.assert(color != null);
this.showLeading = showLeading;
this.showTrailing = showTrailing;
this.axisDirection = axisDirection;
this.child = child;
this.color = color;
this.notificationPredicate = notificationPredicate ?? ScrollNotification.defaultScrollNotificationPredicate;
}
public readonly bool showLeading;
public readonly bool showTrailing;
public readonly AxisDirection axisDirection;
public Axis axis {
get { return AxisUtils.axisDirectionToAxis(this.axisDirection); }
}
public readonly Color color;
public readonly ScrollNotificationPredicate notificationPredicate;
public readonly Widget child;
public override State createState() {
return new _GlowingOverscrollIndicatorState();
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
base.debugFillProperties(properties);
properties.add(new EnumProperty<AxisDirection>("axisDirection", this.axisDirection));
string showDescription;
if (this.showLeading && this.showTrailing) {
showDescription = "both sides";
}
else if (this.showLeading) {
showDescription = "leading side only";
}
else if (this.showTrailing) {
showDescription = "trailing side only";
}
else {
showDescription = "neither side (!)";
}
properties.add(new MessageProperty("show", showDescription));
properties.add(new DiagnosticsProperty<Color>("color", this.color, showName: false));
}
}
class _GlowingOverscrollIndicatorState : TickerProviderStateMixin<GlowingOverscrollIndicator> {
_GlowController _leadingController;
_GlowController _trailingController;
Listenable _leadingAndTrailingListener;
public override void initState() {
base.initState();
this._leadingController =
new _GlowController(vsync: this, color: this.widget.color, axis: this.widget.axis);
this._trailingController =
new _GlowController(vsync: this, color: this.widget.color, axis: this.widget.axis);
this._leadingAndTrailingListener = ListenableUtils.merge(new List<Listenable>
{this._leadingController, this._trailingController});
}
public override void didUpdateWidget(StatefulWidget _oldWidget) {
base.didUpdateWidget(_oldWidget);
GlowingOverscrollIndicator oldWidget = _oldWidget as GlowingOverscrollIndicator;
if (oldWidget.color != this.widget.color || oldWidget.axis != this.widget.axis) {
this._leadingController.color = this.widget.color;
this._leadingController.axis = this.widget.axis;
this._trailingController.color = this.widget.color;
this._trailingController.axis = this.widget.axis;
}
}
Type _lastNotificationType;
Dictionary<bool, bool> _accepted = new Dictionary<bool, bool> {{false, true}, {true, true}};
bool _handleScrollNotification(ScrollNotification notification) {
if (!this.widget.notificationPredicate(notification)) {
return false;
}
if (notification is OverscrollNotification) {
_GlowController controller;
OverscrollNotification _notification = notification as OverscrollNotification;
if (_notification.overscroll < 0.0f) {
controller = this._leadingController;
}
else if (_notification.overscroll > 0.0f) {
controller = this._trailingController;
}
else {
throw new Exception("overscroll is 0.0f!");
}
bool isLeading = controller == this._leadingController;
if (this._lastNotificationType != typeof(OverscrollNotification)) {
OverscrollIndicatorNotification confirmationNotification =
new OverscrollIndicatorNotification(leading: isLeading);
confirmationNotification.dispatch(this.context);
this._accepted[isLeading] = confirmationNotification._accepted;
}
D.assert(controller != null);
D.assert(_notification.metrics.axis() == this.widget.axis);
if (this._accepted[isLeading]) {
if (_notification.velocity != 0.0f) {
D.assert(_notification.dragDetails == null);
controller.absorbImpact(_notification.velocity.abs());
}
else {
D.assert(_notification.overscroll != 0.0f);
if (_notification.dragDetails != null) {
D.assert(_notification.dragDetails.globalPosition != null);
RenderBox renderer = (RenderBox) _notification.context.findRenderObject();
D.assert(renderer != null);
D.assert(renderer.hasSize);
Size size = renderer.size;
Offset position = renderer.globalToLocal(_notification.dragDetails.globalPosition);
switch (_notification.metrics.axis()) {
case Axis.horizontal:
controller.pull(_notification.overscroll.abs(), size.width,
position.dy.clamp(0.0f, size.height), size.height);
break;
case Axis.vertical:
controller.pull(_notification.overscroll.abs(), size.height,
position.dx.clamp(0.0f, size.width), size.width);
break;
}
}
}
}
}
else if (notification is ScrollEndNotification || notification is ScrollUpdateNotification) {
if ((notification as ScrollEndNotification).dragDetails != null) {
this._leadingController.scrollEnd();
this._trailingController.scrollEnd();
}
}
this._lastNotificationType = notification.GetType();
return false;
}
public override void dispose() {
this._leadingController.dispose();
this._trailingController.dispose();
base.dispose();
}
public override Widget build(BuildContext context) {
return new NotificationListener<ScrollNotification>(
onNotification: this._handleScrollNotification,
child: new RepaintBoundary(
child: new CustomPaint(
foregroundPainter: new _GlowingOverscrollIndicatorPainter(
leadingController: this.widget.showLeading ? this._leadingController : null,
trailingController: this.widget.showTrailing ? this._trailingController : null,
axisDirection: this.widget.axisDirection,
repaint: this._leadingAndTrailingListener
),
child: new RepaintBoundary(
child: this.widget.child
)
)
)
);
}
}
enum _GlowState {
idle,
absorb,
pull,
recede
}
class _GlowController : ChangeNotifier {
public _GlowController(
TickerProvider vsync,
Color color,
Axis axis
) {
D.assert(vsync != null);
D.assert(color != null);
this._color = color;
this._axis = axis;
this._glowController = new AnimationController(vsync: vsync);
this._glowController.addStatusListener(this._changePhase);
Animation<float> decelerator = new CurvedAnimation(
parent: this._glowController,
curve: Curves.decelerate
);
decelerator.addListener(this.notifyListeners);
this._glowOpacity = decelerator.drive(this._glowOpacityTween);
this._glowSize = decelerator.drive(this._glowSizeTween);
this._displacementTicker = vsync.createTicker(this._tickDisplacement);
}
_GlowState _state = _GlowState.idle;
AnimationController _glowController;
Timer _pullRecedeTimer;
FloatTween _glowOpacityTween = new FloatTween(begin: 0.0f, end: 0.0f);
Animation<float> _glowOpacity;
FloatTween _glowSizeTween = new FloatTween(begin: 0.0f, end: 0.0f);
Animation<float> _glowSize;
Ticker _displacementTicker;
TimeSpan? _displacementTickerLastElapsed;
float _displacementTarget = 0.5f;
float _displacement = 0.5f;
float _pullDistance = 0.0f;
public Color color {
get { return this._color; }
set {
D.assert(this.color != null);
if (this.color == value) {
return;
}
this._color = value;
this.notifyListeners();
}
}
Color _color;
public Axis axis {
get { return this._axis; }
set {
if (this.axis == value) {
return;
}
this._axis = value;
this.notifyListeners();
}
}
Axis _axis;
readonly TimeSpan _recedeTime = new TimeSpan(0, 0, 0, 0, 600);
readonly TimeSpan _pullTime = new TimeSpan(0, 0, 0, 0, 167);
readonly TimeSpan _pullHoldTime = new TimeSpan(0, 0, 0, 0, 167);
readonly TimeSpan _pullDecayTime = new TimeSpan(0, 0, 0, 0, 2000);
static readonly TimeSpan _crossAxisHalfTime = new TimeSpan(0, 0, 0, 0, (1000.0f / 60.0f).round());
const float _maxOpacity = 0.5f;
const float _pullOpacityGlowFactor = 0.8f;
const float _velocityGlowFactor = 0.00006f;
const float _sqrt3 = 1.73205080757f; // Mathf.Sqrt(3)
const float _widthToHeightFactor = (3.0f / 4.0f) * (2.0f - _sqrt3);
const float _minVelocity = 100.0f; // logical pixels per second
const float _maxVelocity = 10000.0f; // logical pixels per second
public override void dispose() {
this._glowController.dispose();
this._displacementTicker.dispose();
this._pullRecedeTimer?.cancel();
base.dispose();
}
public void absorbImpact(float velocity) {
D.assert(velocity >= 0.0f);
this._pullRecedeTimer?.cancel();
this._pullRecedeTimer = null;
velocity = velocity.clamp(_minVelocity, _maxVelocity);
this._glowOpacityTween.begin = this._state == _GlowState.idle ? 0.3f : this._glowOpacity.value;
this._glowOpacityTween.end =
(velocity * _velocityGlowFactor).clamp(this._glowOpacityTween.begin, _maxOpacity);
this._glowSizeTween.begin = this._glowSize.value;
this._glowSizeTween.end = Mathf.Min(0.025f + 7.5e-7f * velocity * velocity, 1.0f);
this._glowController.duration = new TimeSpan(0, 0, 0, 0, (0.15f + velocity * 0.02f).round());
this._glowController.forward(from: 0.0f);
this._displacement = 0.5f;
this._state = _GlowState.absorb;
}
public void pull(float overscroll, float extent, float crossAxisOffset, float crossExtent) {
this._pullRecedeTimer?.cancel();
this._pullDistance +=
overscroll / 200.0f; // This factor is magic. Not clear why we need it to match Android.
this._glowOpacityTween.begin = this._glowOpacity.value;
this._glowOpacityTween.end =
Mathf.Min(this._glowOpacity.value + overscroll / extent * _pullOpacityGlowFactor, _maxOpacity);
float height = Mathf.Min(extent, crossExtent * _widthToHeightFactor);
this._glowSizeTween.begin = this._glowSize.value;
this._glowSizeTween.end = Mathf.Max(1.0f - 1.0f / (0.7f * Mathf.Sqrt(this._pullDistance * height)),
this._glowSize.value);
this._displacementTarget = crossAxisOffset / crossExtent;
if (this._displacementTarget != this._displacement) {
if (!this._displacementTicker.isTicking) {
D.assert(this._displacementTickerLastElapsed == null);
this._displacementTicker.start();
}
}
else {
this._displacementTicker.stop();
this._displacementTickerLastElapsed = null;
}
this._glowController.duration = this._pullTime;
if (this._state != _GlowState.pull) {
this._glowController.forward(from: 0.0f);
this._state = _GlowState.pull;
}
else {
if (!this._glowController.isAnimating) {
D.assert(this._glowController.value == 1.0f);
this.notifyListeners();
}
}
this._pullRecedeTimer =
new TimerProvider.TimerImpl(this._pullHoldTime, () => this._recede(this._pullDecayTime));
}
public void scrollEnd() {
if (this._state == _GlowState.pull) {
this._recede(this._recedeTime);
}
}
void _changePhase(AnimationStatus status) {
if (status != AnimationStatus.completed) {
return;
}
switch (this._state) {
case _GlowState.absorb:
this._recede(this._recedeTime);
break;
case _GlowState.recede:
this._state = _GlowState.idle;
this._pullDistance = 0.0f;
break;
case _GlowState.pull:
case _GlowState.idle:
break;
}
}
void _recede(TimeSpan duration) {
if (this._state == _GlowState.recede || this._state == _GlowState.idle) {
return;
}
this._pullRecedeTimer?.cancel();
this._pullRecedeTimer = null;
this._glowOpacityTween.begin = this._glowOpacity.value;
this._glowOpacityTween.end = 0.0f;
this._glowSizeTween.begin = this._glowSize.value;
this._glowSizeTween.end = 0.0f;
this._glowController.duration = duration;
this._glowController.forward(from: 0.0f);
this._state = _GlowState.recede;
}
void _tickDisplacement(TimeSpan elapsed) {
if (this._displacementTickerLastElapsed != null) {
float? t = elapsed.Milliseconds - this._displacementTickerLastElapsed?.Milliseconds;
this._displacement = this._displacementTarget - (this._displacementTarget - this._displacement) *
Mathf.Pow(2.0f, (-t ?? 0.0f) / _crossAxisHalfTime.Milliseconds);
this.notifyListeners();
}
if (PhysicsUtils.nearEqual(this._displacementTarget, this._displacement,
Tolerance.defaultTolerance.distance)) {
this._displacementTicker.stop();
this._displacementTickerLastElapsed = null;
}
else {
this._displacementTickerLastElapsed = elapsed;
}
}
public void paint(Canvas canvas, Size size) {
if (this._glowOpacity.value == 0.0f) {
return;
}
float baseGlowScale = size.width > size.height ? size.height / size.width : 1.0f;
float radius = size.width * 3.0f / 2.0f;
float height = Mathf.Min(size.height, size.width * _widthToHeightFactor);
float scaleY = this._glowSize.value * baseGlowScale;
Rect rect = Rect.fromLTWH(0.0f, 0.0f, size.width, height);
Offset center = new Offset((size.width / 2.0f) * (0.5f + this._displacement), height - radius);
Paint paint = new Paint();
paint.color = this.color.withOpacity(this._glowOpacity.value);
canvas.save();
canvas.scale(1.0f, scaleY);
canvas.clipRect(rect);
canvas.drawCircle(center, radius, paint);
canvas.restore();
}
}
class _GlowingOverscrollIndicatorPainter : AbstractCustomPainter {
public _GlowingOverscrollIndicatorPainter(
_GlowController leadingController,
_GlowController trailingController,
AxisDirection axisDirection,
Listenable repaint
) : base(
repaint: repaint
) {
this.leadingController = leadingController;
this.trailingController = trailingController;
this.axisDirection = axisDirection;
}
public readonly _GlowController leadingController;
public readonly _GlowController trailingController;
public readonly AxisDirection axisDirection;
const float piOver2 = Mathf.PI / 2.0f;
void _paintSide(Canvas canvas, Size size, _GlowController controller, AxisDirection axisDirection,
GrowthDirection growthDirection) {
if (controller == null) {
return;
}
switch (GrowthDirectionUtils.applyGrowthDirectionToAxisDirection(axisDirection, growthDirection)) {
case AxisDirection.up:
controller.paint(canvas, size);
break;
case AxisDirection.down:
canvas.save();
canvas.translate(0.0f, size.height);
canvas.scale(1.0f, -1.0f);
controller.paint(canvas, size);
canvas.restore();
break;
case AxisDirection.left:
canvas.save();
canvas.rotate(piOver2);
canvas.scale(1.0f, -1.0f);
controller.paint(canvas, new Size(size.height, size.width));
canvas.restore();
break;
case AxisDirection.right:
canvas.save();
canvas.translate(size.width, 0.0f);
canvas.rotate(piOver2);
controller.paint(canvas, new Size(size.height, size.width));
canvas.restore();
break;
}
}
public override void paint(Canvas canvas, Size size) {
this._paintSide(canvas, size, this.leadingController, this.axisDirection, GrowthDirection.reverse);
this._paintSide(canvas, size, this.trailingController, this.axisDirection, GrowthDirection.forward);
}
public override bool shouldRepaint(CustomPainter _oldDelegate) {
_GlowingOverscrollIndicatorPainter oldDelegate = _oldDelegate as _GlowingOverscrollIndicatorPainter;
return oldDelegate.leadingController != this.leadingController
|| oldDelegate.trailingController != this.trailingController;
}
}
public class OverscrollIndicatorNotification : ViewportNotificationMixinNotification {
public OverscrollIndicatorNotification(
bool leading
) {
this.leading = leading;
}
public readonly bool leading;
internal bool _accepted = true;
public void disallowGlow() {
this._accepted = false;
}
protected override void debugFillDescription(List<string> description) {
base.debugFillDescription(description);
description.Add($"side: {(this.leading ? "leading edge" : "trailing edge")}");
}
}
}

3
Runtime/widgets/overscroll_indicator.cs.meta


fileFormatVersion: 2
guid: b87c58140c4b442e82a27b804f8502c7
timeCreated: 1554348404

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

正在加载...
取消
保存