diff --git a/.editorconfig b/.editorconfig index 9933dd0..e9e93bf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,9 +5,10 @@ root = true # Use tabs for indentation. [*] -indent_style = tab -trim_trailing_whitespace = true +charset = utf-8-bom +end_of_line = crlf insert_final_newline = true +indent_style = tab # (Please don't specify an indent_size here; that has too many unintended consequences.) # Code files @@ -35,7 +36,6 @@ indent_size = 2 [*.{cs,vb}] # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = true - # Avoid "this." and "Me." if not necessary dotnet_style_qualification_for_field = false:suggestion dotnet_style_qualification_for_property = false:suggestion diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml new file mode 100644 index 0000000..9e594dc --- /dev/null +++ b/.github/workflows/npmpublish.yml @@ -0,0 +1,31 @@ +name: Node.js Package + +on: + push: + branches: + - master + +jobs: + publish-npm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 12 + registry-url: https://registry.npmjs.org/ + - run: npm publish Packages/UnityFx.Mvc + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + + publish-gpr: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 12 + registry-url: https://npm.pkg.github.com/ + - run: npm publish Packages/UnityFx.Mvc + env: + NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/Assets/Plugins/UnityFx.Mvc/CHANGELOG.md b/Assets/Plugins/UnityFx.Mvc/CHANGELOG.md index efcc5f7..d0ce834 100644 --- a/Assets/Plugins/UnityFx.Mvc/CHANGELOG.md +++ b/Assets/Plugins/UnityFx.Mvc/CHANGELOG.md @@ -1,8 +1,28 @@ -# UnityFx.AppStates changelog +# UnityFx.Mvc changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). +## [0.2.0] - 2020.01.05 + +### Added +- Added support for generic commands. +- Added view layers support (via `ViewControllerAttribute`). +- Added `IViewControllerResult` interface to tag controllers that have a result value. +- Added `IConfigurable` interfaces. +- Added message box extensions. + +### Changed +- Changed the package layout. The code is now splitted into 3 assemblies (`UnityFx.Mvc`, `UnityFx.Mvc.Abstractions` and `UnityFx.Mvc.Extensions`). +- Renamed `IPresenter.PresentAsync` to `Present`. Added a group of `PresentAsync` extension methods returning `Task` instead of `IPresentResult`. +- Renamed `IPresentResult.DismissTask` to `Task`. +- Changed `Present`/`PresentAsync` arguments. +- Changed `IViewFactory` and `IViewControllerFactory` interfaces. +- `IView` now does not inherit `IComponent`. + +### Removed +- Removed `IPresentResult.PresentTask`. + ## [0.1.0] - 2019.11.14 ### Added diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts.meta b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors.meta similarity index 77% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts.meta rename to Assets/Plugins/UnityFx.Mvc/Editor/Inspectors.meta index 1cf5d63..f865241 100644 --- a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts.meta +++ b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 02b6e768c2f56214ba2c2835364eed87 +guid: 94faaafd3fb3d28488ca0fc2f7c74b09 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/PresenterEditor.cs b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/PresenterEditor.cs similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/PresenterEditor.cs rename to Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/PresenterEditor.cs diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/PresenterEditor.cs.meta b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/PresenterEditor.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/PresenterEditor.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/PresenterEditor.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewFactoryEditor.cs b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewFactoryEditor.cs similarity index 86% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewFactoryEditor.cs rename to Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewFactoryEditor.cs index 4e5a144..327adb6 100644 --- a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewFactoryEditor.cs +++ b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewFactoryEditor.cs @@ -7,14 +7,14 @@ namespace UnityFx.Mvc { - [CustomEditor(typeof(ViewFactory))] + [CustomEditor(typeof(UGUIViewFactory))] public class ViewFactoryEditor : Editor { - private ViewFactory _viewFactory; + private UGUIViewFactory _viewFactory; private void OnEnable() { - _viewFactory = (ViewFactory)target; + _viewFactory = (UGUIViewFactory)target; } public override void OnInspectorGUI() diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewFactoryEditor.cs.meta b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewFactoryEditor.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewFactoryEditor.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewFactoryEditor.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewProxyEditor.cs b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewProxyEditor.cs similarity index 69% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewProxyEditor.cs rename to Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewProxyEditor.cs index 5437a6e..2833056 100644 --- a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewProxyEditor.cs +++ b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewProxyEditor.cs @@ -7,14 +7,14 @@ namespace UnityFx.Mvc { - [CustomEditor(typeof(ViewFactory.ViewProxy), true)] + [CustomEditor(typeof(UGUIViewFactory.ViewProxy), true)] public class ViewProxyEditor : Editor { - private ViewFactory.ViewProxy _viewProxy; + private UGUIViewFactory.ViewProxy _viewProxy; private void OnEnable() { - _viewProxy = (ViewFactory.ViewProxy)target; + _viewProxy = (UGUIViewFactory.ViewProxy)target; } public override void OnInspectorGUI() @@ -23,7 +23,7 @@ public override void OnInspectorGUI() EditorGUI.BeginDisabledGroup(true); - EditorGUILayout.ObjectField("View", _viewProxy.Component as Component, typeof(Component), true); + EditorGUILayout.ObjectField("View", _viewProxy.View as Component, typeof(Component), true); EditorGUILayout.Toggle("Modal", _viewProxy.Modal); EditorGUILayout.Toggle("Exclusive", _viewProxy.Exclusive); diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewProxyEditor.cs.meta b/Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewProxyEditor.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/ViewProxyEditor.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Editor/Inspectors/ViewProxyEditor.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/MenuExtensions.cs b/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/MenuExtensions.cs deleted file mode 100644 index 2f2003e..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/MenuExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. -// See the LICENSE.md file in the project root for more information. - -using System; -using UnityEditor; -using UnityEngine; - -namespace UnityFx.Mvc -{ - /// - /// Unity menu extensions. - /// - public static class MenuExtensions - { - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/UnityFx.Mvc.Editor.asmdef b/Assets/Plugins/UnityFx.Mvc/Editor/UnityFx.Mvc.Editor.asmdef index 3712748..0e631bb 100644 --- a/Assets/Plugins/UnityFx.Mvc/Editor/UnityFx.Mvc.Editor.asmdef +++ b/Assets/Plugins/UnityFx.Mvc/Editor/UnityFx.Mvc.Editor.asmdef @@ -1,6 +1,7 @@ { "name": "UnityFx.Mvc.Editor", "references": [ + "UnityFx.Mvc.Abstractions", "UnityFx.Mvc" ], "optionalUnityReferences": [], diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/Windows.meta b/Assets/Plugins/UnityFx.Mvc/Editor/Windows.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/Windows.meta rename to Assets/Plugins/UnityFx.Mvc/Editor/Windows.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/Windows/CreateViewControllerWindow.cs b/Assets/Plugins/UnityFx.Mvc/Editor/Windows/CreateViewControllerWindow.cs similarity index 69% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/Windows/CreateViewControllerWindow.cs rename to Assets/Plugins/UnityFx.Mvc/Editor/Windows/CreateViewControllerWindow.cs index 4180bf7..85680e8 100644 --- a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/Windows/CreateViewControllerWindow.cs +++ b/Assets/Plugins/UnityFx.Mvc/Editor/Windows/CreateViewControllerWindow.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Text; +using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; @@ -11,6 +12,7 @@ namespace UnityFx.Mvc { public class CreateViewControllerWindow : EditorWindow { + private string _basePath; private string _controllerName; private string _namespace; private string _controllerBaseClass = nameof(ViewController); @@ -18,6 +20,9 @@ public class CreateViewControllerWindow : EditorWindow private bool _exclusive; private bool _modal; private bool _popup; + private bool _createArgs; + + private Regex _classNamePattern = new Regex("^[_a-zA-Z][_a-zA-Z0-9]*$"); [MenuItem("Assets/Create/UnityFx/New ViewController...")] public static void Init() @@ -27,14 +32,20 @@ public static void Init() private void OnGUI() { - var path = GetSelectedPath(); + _basePath = GetSelectedPath(); - if (!string.IsNullOrEmpty(path)) + if (string.IsNullOrEmpty(_basePath)) { - _controllerName = Path.GetFileName(path); + EditorGUILayout.HelpBox("Invalid path. Please select an asset folder.", MessageType.Error); + return; } + GUI.enabled = false; + EditorGUILayout.TextField("Base path", _basePath); + GUI.enabled = true; + _controllerName = EditorGUILayout.TextField("Controller Name", _controllerName); + _createArgs = EditorGUILayout.Toggle("Create PresentArgs", _createArgs); _exclusive = EditorGUILayout.Toggle("Exclusive", _exclusive); _popup = EditorGUILayout.Toggle("Popup", _popup); _modal = EditorGUILayout.Toggle("Modal", _modal); @@ -42,6 +53,11 @@ private void OnGUI() _controllerBaseClass = EditorGUILayout.TextField("Controller Base Class", _controllerBaseClass); _viewBaseClass = EditorGUILayout.TextField("View Base Class", _viewBaseClass); + if (string.IsNullOrWhiteSpace(_controllerName) || !_classNamePattern.IsMatch(_controllerName)) + { + EditorGUILayout.HelpBox($"Invalid controller name. Controller names should match {_classNamePattern}.", MessageType.Error); + } + if (_exclusive) { _popup = false; @@ -65,7 +81,7 @@ private void OnGUI() if (GUILayout.Button("Create")) { - CreateViewController(path); + CreateViewController(_basePath); } } @@ -81,15 +97,29 @@ private void CreateViewController(string path) } else { + path = Path.Combine(path, _controllerName); + + var fullPath = Path.Combine(Directory.GetCurrentDirectory(), path); + + if (!Directory.Exists(fullPath)) + { + Directory.CreateDirectory(fullPath); + } + var indent = " "; var controllerName = _controllerName + "Controller"; var controllerFileName = controllerName + ".cs"; - var controllerPath = Path.Combine(Directory.GetCurrentDirectory(), Path.Combine(path, controllerFileName)); + var controllerPath = Path.Combine(fullPath, controllerFileName); var controllerText = new StringBuilder(); + var argsName = _controllerName + "Args"; + var argsFileName = argsName + ".cs"; + var argsPath = Path.Combine(fullPath, argsFileName); + var argsText = new StringBuilder(); + var viewName = _controllerName + "View"; var viewFileName = viewName + ".cs"; - var viewPath = Path.Combine(Directory.GetCurrentDirectory(), Path.Combine(path, viewFileName)); + var viewPath = Path.Combine(fullPath, viewFileName); var viewText = new StringBuilder(); var prefabPath = Path.Combine(path, _controllerName + ".prefab"); @@ -115,6 +145,12 @@ private void CreateViewController(string path) controllerText.AppendLine(indent + "/// " + controllerName); controllerText.AppendLine(indent + "/// "); controllerText.AppendFormat(indent + "/// " + Environment.NewLine, viewName); + + if (_createArgs) + { + controllerText.AppendFormat(indent + "/// " + Environment.NewLine, argsName); + } + controllerText.AppendFormat(indent + "[ViewController(PresentOptions = {0})]" + Environment.NewLine, GetPresentOptions(_exclusive, _popup, _modal)); controllerText.AppendFormat(indent + "public class {0} : {1}<{2}>" + Environment.NewLine, controllerName, _controllerBaseClass, viewName); controllerText.AppendLine(indent + "{"); @@ -124,20 +160,40 @@ private void CreateViewController(string path) controllerText.AppendLine(indent + " #region interface"); controllerText.AppendLine(""); controllerText.AppendLine(indent + " /// "); - controllerText.AppendLine(indent + " /// Controller-specific commands."); + controllerText.AppendLine(indent + " /// Enumerates controller-specific commands."); controllerText.AppendLine(indent + " /// "); - controllerText.AppendFormat(indent + " public abstract new class Commands : {0}.{1}" + Environment.NewLine, nameof(ViewController), nameof(ViewController.Commands)); + controllerText.AppendLine(indent + " public enum Commands"); controllerText.AppendLine(indent + " {"); + controllerText.AppendLine(indent + " Close"); controllerText.AppendLine(indent + " }"); controllerText.AppendLine(""); controllerText.AppendLine(indent + " /// "); controllerText.AppendFormat(indent + " /// Initializes a new instance of the class." + Environment.NewLine, controllerName); controllerText.AppendLine(indent + " /// "); - controllerText.AppendFormat(indent + " public {0}({1} context)" + Environment.NewLine, controllerName, nameof(IPresentContext)); + controllerText.AppendFormat(indent + " public {0}({1} context", controllerName, nameof(IPresentContext)); + + if (_createArgs) + { + controllerText.AppendFormat(", {0} args)" + Environment.NewLine, argsName); + } + else + { + controllerText.AppendLine(")"); + } + controllerText.AppendLine(indent + " : base(context)"); controllerText.AppendLine(indent + " {"); controllerText.AppendLine(indent + " // TODO: Initialize the controller view here. Add arguments to the Configure() as needed."); - controllerText.AppendLine(indent + " View.Configure();"); + + if (_createArgs) + { + controllerText.AppendLine(indent + " View.Configure(args);"); + } + else + { + controllerText.AppendLine(indent + " View.Configure();"); + } + controllerText.AppendLine(indent + " }"); controllerText.AppendLine(""); controllerText.AppendLine(indent + " #endregion"); @@ -145,9 +201,19 @@ private void CreateViewController(string path) controllerText.AppendLine(indent + " #region ViewController"); controllerText.AppendLine(""); controllerText.AppendLine(indent + " /// "); - controllerText.AppendLine(indent + " protected override bool OnCommand(string commandName, object commandArgs)"); + controllerText.AppendLine(indent + " protected override bool OnCommand(TCommand command)"); controllerText.AppendLine(indent + " {"); controllerText.AppendLine(indent + " // TODO: Process view commands here. See list of commands in Commands."); + controllerText.AppendLine(indent + " if (CommandUtilities.TryUnpack(command, out Commands cmd))"); + controllerText.AppendLine(indent + " {"); + controllerText.AppendLine(indent + " switch (cmd)"); + controllerText.AppendLine(indent + " {"); + controllerText.AppendLine(indent + " case Commands.Close:"); + controllerText.AppendLine(indent + " Dismiss();"); + controllerText.AppendLine(indent + " return true;"); + controllerText.AppendLine(indent + " }"); + controllerText.AppendLine(indent + " }"); + controllerText.AppendLine(""); controllerText.AppendLine(indent + " return false;"); controllerText.AppendLine(indent + " }"); controllerText.AppendLine(""); @@ -182,6 +248,12 @@ private void CreateViewController(string path) viewText.AppendFormat(indent + "/// View for the ." + Environment.NewLine, controllerName); viewText.AppendLine(indent + "/// "); viewText.AppendFormat(indent + "/// " + Environment.NewLine, controllerName); + + if (_createArgs) + { + viewText.AppendFormat(indent + "/// " + Environment.NewLine, argsName); + } + viewText.AppendFormat(indent + "public class {0} : {1}" + Environment.NewLine, viewName, _viewBaseClass); viewText.AppendLine(indent + "{"); viewText.AppendLine(indent + " #region data"); @@ -199,7 +271,16 @@ private void CreateViewController(string path) viewText.AppendLine(indent + " /// "); viewText.AppendLine(indent + " /// Initializes the view. Called from the controller ctor." ); viewText.AppendLine(indent + " /// "); - viewText.AppendLine(indent + " public void Configure()"); + + if (_createArgs) + { + viewText.AppendFormat(indent + " public void Configure({0} args)" + Environment.NewLine, argsName); + } + else + { + viewText.AppendLine(indent + " public void Configure()"); + } + viewText.AppendLine(indent + " {"); viewText.AppendLine(indent + " // TODO: Setup the view. Add additional arguments as needed."); viewText.AppendLine(indent + " }"); @@ -219,6 +300,36 @@ private void CreateViewController(string path) } File.WriteAllText(viewPath, viewText.ToString()); + + // Args source. + argsText.AppendLine("using System;"); + argsText.AppendLine("using System.Collections.Generic;"); + argsText.AppendLine("using UnityEngine;"); + argsText.AppendLine("using UnityFx.Mvc;"); + argsText.AppendLine(""); + + if (!string.IsNullOrEmpty(_namespace)) + { + argsText.AppendLine("namespace " + _namespace); + argsText.AppendLine("{"); + } + + argsText.AppendLine(indent + "/// "); + argsText.AppendFormat(indent + "/// Arguments for the ." + Environment.NewLine, controllerName); + argsText.AppendLine(indent + "/// "); + argsText.AppendFormat(indent + "/// " + Environment.NewLine, controllerName); + argsText.AppendFormat(indent + "/// " + Environment.NewLine, viewName); + + argsText.AppendFormat(indent + "public class {0} : PresentArgs" + Environment.NewLine, argsName); + argsText.AppendLine(indent + "{"); + argsText.AppendLine(indent + "}"); + + if (!string.IsNullOrEmpty(_namespace)) + { + argsText.AppendLine("}"); + } + + File.WriteAllText(argsPath, argsText.ToString()); AssetDatabase.Refresh(); // Prefab. @@ -258,7 +369,7 @@ private static string GetPresentOptions(bool exclusive, bool popup, bool modal) { if (!string.IsNullOrEmpty(text)) { - text += " || "; + text += " | "; } text += nameof(PresentOptions) + '.' + nameof(PresentOptions.Popup); @@ -268,7 +379,7 @@ private static string GetPresentOptions(bool exclusive, bool popup, bool modal) { if (!string.IsNullOrEmpty(text)) { - text += " || "; + text += " | "; } text += nameof(PresentOptions) + '.' + nameof(PresentOptions.Modal); diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/Windows/CreateViewControllerWindow.cs.meta b/Assets/Plugins/UnityFx.Mvc/Editor/Windows/CreateViewControllerWindow.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/Windows/CreateViewControllerWindow.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Editor/Windows/CreateViewControllerWindow.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/README.md b/Assets/Plugins/UnityFx.Mvc/README.md index 7583dbc..3e71035 100644 --- a/Assets/Plugins/UnityFx.Mvc/README.md +++ b/Assets/Plugins/UnityFx.Mvc/README.md @@ -1,4 +1,4 @@ -# UnityFx.Outline +# UnityFx.Mvc ## SUMMARY MVC(S) framework for Unity. diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs.cs new file mode 100644 index 0000000..e430082 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs.cs @@ -0,0 +1,14 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Event arguments for an arbitraty action. + /// + public class CommandEventArgs : EventArgs + { + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/ActivatorUtilities.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs.cs.meta similarity index 83% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/ActivatorUtilities.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs.cs.meta index 6b4c14b..3a3637b 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/ActivatorUtilities.cs.meta +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0be6a428b7aff4d4f83c90dbf5242a9b +guid: c354fefe296ecac4a9e69d6c5ae654b0 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand,TArgs}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand,TArgs}.cs new file mode 100644 index 0000000..2cadae6 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand,TArgs}.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Event arguments for an arbitraty action. + /// + /// Type of the command arguments. + public class CommandEventArgs : CommandEventArgs, ICommandResultAccess + { + /// + /// Gets the command arguments. + /// + public TArgs Args { get; } + + /// + /// Initializes a new instance of the class. + /// + public CommandEventArgs(TCommand command, TArgs args) + : base(command) + { + Args = args; + } + + /// + public override string ToString() + { + if (Args != null) + { + return base.ToString() + '(' + Args.ToString() + ')'; + } + + return base.ToString(); + } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerInfo.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand,TArgs}.cs.meta similarity index 83% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerInfo.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand,TArgs}.cs.meta index ac96eed..d4ebc32 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerInfo.cs.meta +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand,TArgs}.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b5dbe7af29f99494eb94f3818c25cb48 +guid: cab31b235c3716949bff8fecdaeb1a8c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand}.cs new file mode 100644 index 0000000..1bf8ee9 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand}.cs @@ -0,0 +1,37 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Event arguments for an arbitraty action. + /// + public class CommandEventArgs : CommandEventArgs, ICommandAccess + { + /// + /// Gets the command name. + /// + public TCommand Command { get; } + + /// + /// Initializes a new instance of the class. + /// + public CommandEventArgs(TCommand command) + { + Command = command; + } + + /// + public override string ToString() + { + if (Command != null) + { + return Command.ToString(); + } + + return "Null"; + } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/CommandEventArgs.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/CommandEventArgs.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandEventArgs{TCommand}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandUtilities.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandUtilities.cs new file mode 100644 index 0000000..63670cc --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandUtilities.cs @@ -0,0 +1,49 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Command-related helpers. + /// + public static class CommandUtilities + { + /// + /// Attepts to unpack a command. + /// + public static bool TryUnpack(TPackedCommand packedCommand, out TCommand command) + { + if (packedCommand is ICommandAccess ea) + { + command = ea.Command; + return true; + } + + if (packedCommand is TCommand c) + { + command = c; + return true; + } + + command = default; + return false; + } + + /// + /// Attempts to unpack command arguments. + /// + public static bool TryUnpackArgs(TPackedCommand packedCommand, out TArgs args) + { + if (packedCommand is ICommandResultAccess ea) + { + args = ea.Args; + return true; + } + + args = default; + return false; + } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/MenuExtensions.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandUtilities.cs.meta similarity index 83% rename from Assets/Plugins/UnityFx.Mvc/Editor/Scripts/MenuExtensions.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandUtilities.cs.meta index e883bdb..e0c3c0d 100644 --- a/Assets/Plugins/UnityFx.Mvc/Editor/Scripts/MenuExtensions.cs.meta +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/CommandUtilities.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: efdb15e2cfe9a0e459e19a02be2a440d +guid: 6b7439042044478488710a0f7a760393 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandAccess{TCommand}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandAccess{TCommand}.cs new file mode 100644 index 0000000..8c67c90 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandAccess{TCommand}.cs @@ -0,0 +1,18 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Event arguments for an arbitraty action. + /// + public interface ICommandAccess + { + /// + /// Gets the command. + /// + TCommand Command { get; } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResultExtensions.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandAccess{TCommand}.cs.meta similarity index 83% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResultExtensions.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandAccess{TCommand}.cs.meta index 5de826b..825eb33 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResultExtensions.cs.meta +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandAccess{TCommand}.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1ac16b74db6ade24fbe85382bb51058a +guid: 2985597119cbef64abaceac68ba20b67 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandArgsAccess{TArgs}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandArgsAccess{TArgs}.cs new file mode 100644 index 0000000..7bc1bc5 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandArgsAccess{TArgs}.cs @@ -0,0 +1,18 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Event arguments for an arbitraty action. + /// + public interface ICommandResultAccess + { + /// + /// Gets the command arguments. + /// + TArgs Args { get; } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandArgsAccess{TArgs}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandArgsAccess{TArgs}.cs.meta new file mode 100644 index 0000000..def2bf5 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandArgsAccess{TArgs}.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: edd3d06d145315e4e8430d8df595a1ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/ICommandTarget.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTarget.cs similarity index 63% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/ICommandTarget.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTarget.cs index 3f09453..880a5d8 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/ICommandTarget.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTarget.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -14,10 +14,8 @@ public interface ICommandTarget /// /// Invokes a command. An implementation might choose to ignore the command, in this case the method should return . /// - /// Name of the command to invoke. - /// Command-specific arguments. - /// Thrown if is . + /// Command to invoke. /// Returns if the command has been handled; otherwise. - bool InvokeCommand(string commandName, object args); + bool InvokeCommand(TCommand command); } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/ICommandTarget.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTarget.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/ICommandTarget.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTarget.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTargetExtensions.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTargetExtensions.cs new file mode 100644 index 0000000..08be29f --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTargetExtensions.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Extensions of . + /// + /// + public static class ICommandTargetExtensions + { + /// + /// Invokes a command. An implementation might choose to ignore the command, in this case the method should return . + /// + /// Command to invoke. + /// Command arguments. + /// Returns if the command has been handled; otherwise. + public static bool InvokeCommand(this ICommandTarget commandTarget, TCommand command, TArgs args) + { + return commandTarget.InvokeCommand(new CommandEventArgs(command, args)); + } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTargetExtensions.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTargetExtensions.cs.meta new file mode 100644 index 0000000..048d5df --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/ICommandTargetExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 931a556c85f509047bf9e2f6ac0740fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/INotifyCommand.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/INotifyCommand.cs similarity index 88% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/INotifyCommand.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/INotifyCommand.cs index b73fdd4..df35c82 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/INotifyCommand.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/INotifyCommand.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/INotifyCommand.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/INotifyCommand.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/INotifyCommand.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Commands/INotifyCommand.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/AssemblyInfo.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/AssemblyInfo.cs new file mode 100644 index 0000000..d11c435 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/AssemblyInfo.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("UnityFx.Mvc.Abstractions")] +[assembly: AssemblyDescription("MVC framework for Unity.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("UnityFx.Mvc")] +[assembly: AssemblyCopyright("Copyright © 2018-2020 Alexander Bogarsukov")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8596BBA3-E5F5-4678-9472-9E88A647F74B")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +// Editor assembly should access core internals. +[assembly: InternalsVisibleTo("UnityFx.Mvc.Editor")] diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/AssemblyInfo.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/AssemblyInfo.cs.meta new file mode 100644 index 0000000..330c66e --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8458305ea4335d7439998f6302ae2042 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/IConfigurable{T}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/IConfigurable{T}.cs new file mode 100644 index 0000000..3623eef --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/IConfigurable{T}.cs @@ -0,0 +1,18 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// A generic configurable entity. + /// + public interface IConfigurable + { + /// + /// Configures the instance with the passed. + /// + void Configure(T args); + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/IConfigurable{T}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/IConfigurable{T}.cs.meta new file mode 100644 index 0000000..3f0b156 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Common/IConfigurable{T}.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba9a4a8a3aedef84c9b04b076038aeeb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IView.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IView.cs similarity index 55% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IView.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IView.cs index e09b3ac..e2c633f 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IView.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IView.cs @@ -1,8 +1,7 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; -using System.ComponentModel; using UnityEngine; namespace UnityFx.Mvc @@ -10,10 +9,20 @@ namespace UnityFx.Mvc /// /// A generic view. /// + /// + /// In the Model-View-Controller (MVC) pattern, the view handles the app's data presentation and user interaction. + /// A view is a . Views are created via instance. + /// /// + /// /// - public interface IView : IComponent, INotifyCommand + public interface IView : INotifyCommand, IDisposable { + /// + /// Raised when the view is disposed. + /// + event EventHandler Disposed; + /// /// Gets the this view is attached to. /// diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IView.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IView.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IView.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IView.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewController.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewController.cs similarity index 80% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewController.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewController.cs index 033073f..f1da6ff 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewController.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewController.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -10,12 +10,13 @@ namespace UnityFx.Mvc /// /// /// As the name states, main responsibility of a view controller is managing its view. + /// Controllers are created via a instance. /// /// /// /// /// - /// + /// /// public interface IViewController : ICommandTarget { diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewController.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewController.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewController.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewController.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerAccess{TController}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerAccess{TController}.cs new file mode 100644 index 0000000..9fd47b4 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerAccess{TController}.cs @@ -0,0 +1,27 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Manages access to a controller of a specific type. + /// + /// Type of the controller. + /// + public interface IViewControllerAccess where TController : IViewController + { + /// + /// Gets the view controller. + /// + /// + TController Controller { get; } + + /// + /// Gets the view. + /// + /// + IView View { get; } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerAccess{TController}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerAccess{TController}.cs.meta new file mode 100644 index 0000000..39a5907 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerAccess{TController}.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86af53f35c78ef147a23e212c100faac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerCollection.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerCollection.cs similarity index 91% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerCollection.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerCollection.cs index 43c8576..2fbb45c 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerCollection.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerCollection.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -10,7 +10,6 @@ namespace UnityFx.Mvc /// A collection of items. /// /// - /// public interface IViewControllerCollection : IReadOnlyCollection { /// diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerCollection.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerCollection.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerCollection.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerCollection.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerEvents.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerEvents.cs similarity index 89% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerEvents.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerEvents.cs index ee04495..4e05bca 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerEvents.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerEvents.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -6,7 +6,7 @@ namespace UnityFx.Mvc { /// - /// Defines event handlers for a presentable obejct. + /// Defines event handlers for a implementation. /// /// public interface IViewControllerEvents diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerEvents.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerEvents.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerEvents.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerEvents.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerFactory.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerFactory.cs similarity index 51% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerFactory.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerFactory.cs index 3b0641a..342effe 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerFactory.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerFactory.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -6,7 +6,7 @@ namespace UnityFx.Mvc { /// - /// A factory of instances. + /// Provides methods for creation and disposal of view controllers. /// /// public interface IViewControllerFactory @@ -14,18 +14,26 @@ public interface IViewControllerFactory /// /// Creates a scoped instance. /// - /// A service provider passed to the controller created by the factory. + /// A used to resolve controller dependencies. /// A disposable scope created or . - IDisposable CreateControllerScope(ref IServiceProvider serviceProvider); + IDisposable CreateScope(ref IServiceProvider serviceProvider); /// /// Creates a new instance of and injects its dependencies. /// /// Type of the controller to be created. - /// Additional arguments to use when injecting controller dependencies. + /// Additional arguments to use when resolving controller dependencies. /// Thrown if is . - /// Thrown if is not a valid controller type. + /// Thrown if is not a valid controller type (for instance, is abstract). /// The created controller instance. - IViewController CreateController(Type controllerType, params object[] args); + /// + IViewController Create(Type controllerType, params object[] args); + + /// + /// Releases a controller after it has been dismissed. + /// + /// The controller to be disposed. + /// + void Release(IViewController controller); } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerFactory.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerFactory.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerFactory.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerFactory.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController,TResult}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResultAccess{TResult}.cs similarity index 66% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController,TResult}.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResultAccess{TResult}.cs index 898f1fb..f87c121 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController,TResult}.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResultAccess{TResult}.cs @@ -1,17 +1,16 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; -using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace UnityFx.Mvc { /// - /// Result of a present operation. + /// Manages access to result of a present operation. /// - /// - public interface IPresentResult : IPresentResult where TController : IViewController + /// + public interface IViewControllerResultAccess { /// /// Gets the operation result value. @@ -21,12 +20,14 @@ public interface IPresentResult : IPresentResult property does not return a value. /// Instead, attempting to access the property value throws an exception. /// - /// Thrown if the property is accessed before operation is completed or the operation completed with errors. + /// Thrown if the property is accessed before operation is completed. + /// TResult Result { get; } /// - /// Gets a instance that can be used to await the operatino completion. + /// Gets a instance that can be used to await the operation completion. /// - new Task DismissTask { get; } + /// + Task Task { get; } } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResultAccess{TResult}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResultAccess{TResult}.cs.meta new file mode 100644 index 0000000..0b56bc6 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResultAccess{TResult}.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b24e80292872d4d4d98adef579930ac3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResult{TResult}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResult{TResult}.cs new file mode 100644 index 0000000..fa96d0c --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResult{TResult}.cs @@ -0,0 +1,15 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Tag interface for all implementations that have a result value. + /// + /// + public interface IViewControllerResult + { + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResult{TResult}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResult{TResult}.cs.meta new file mode 100644 index 0000000..f1d2878 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewControllerResult{TResult}.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a753d5d4ff1c20449aa1bea608af851c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewFactory.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewFactory.cs similarity index 58% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewFactory.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewFactory.cs index 74cc41e..f49e276 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewFactory.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewFactory.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -9,18 +9,19 @@ namespace UnityFx.Mvc { /// - /// A factory of instances. + /// Provides methods for creation and disposal of views. /// /// public interface IViewFactory { /// - /// Creates a view for the specified controller. + /// Creates a view for a controller of the specified type. /// - /// Type of the view controller. + /// Path to the view prefab asset. + /// /// Z-order index. /// Present options. /// Parent transform for the view (or ). - Task CreateViewAsync(Type controllerType, int zIndex, PresentOptions options, Transform parent); + Task CreateAsync(string prefabPath, int layer, int zIndex, PresentOptions options, Transform parent); } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewFactory.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewFactory.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewFactory.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/IViewFactory.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/View.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/View.cs similarity index 70% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/View.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/View.cs index 11f065c..c0c692d 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/View.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/View.cs @@ -1,33 +1,25 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; -using System.Collections.Generic; -using System.ComponentModel; using UnityEngine; namespace UnityFx.Mvc { /// - /// Default -based view. + /// A -based view. /// /// public class View : MonoBehaviour, IView { #region data - private ISite _site; private bool _disposed; #endregion #region interface - /// - /// Gets a transform the is attached to (if any). - /// - protected Transform SiteTransform => (_site as UnityEngine.Component)?.transform; - /// /// Gets a value indicating whether the view is disposed. /// @@ -38,12 +30,27 @@ public class View : MonoBehaviour, IView /// /// Raises event. /// - /// Name of the command. + /// Type of the command. + /// A generic command. + /// + /// + protected void NotifyCommand(TCommand command) + { + Command?.Invoke(this, new CommandEventArgs(command)); + } + + /// + /// Raises event. + /// + /// Type of the command. + /// Type of the arguments. + /// A generic command. /// Command arguments. + /// /// - protected void NotifyCommand(string commandId, object args = null) + protected void NotifyCommand(TCommand command, TArgs args) { - Command?.Invoke(this, new CommandEventArgs(commandId, args)); + Command?.Invoke(this, new CommandEventArgs(command, args)); } /// @@ -82,6 +89,13 @@ private void OnDestroy() #region IView + /// + /// Represents the method that handles the dispose event of the view. + /// + /// + /// + public event EventHandler Disposed; + /// /// Gets the this view is attached to. /// @@ -110,37 +124,12 @@ public bool Enabled /// /// Raised when a user issues a command. /// - /// + /// + /// public event EventHandler Command; #endregion - #region IComponent - - /// - /// Represents the method that handles the dispose event of a component. - /// - /// - /// - public event EventHandler Disposed; - - /// - /// Gets or sets the associated with the . - /// - public ISite Site - { - get - { - return _site; - } - set - { - _site = value; - } - } - - #endregion - #region IDisposable /// @@ -155,7 +144,6 @@ public void Dispose() if (!_disposed) { _disposed = true; - _site?.Container?.Remove(this); try { diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/View.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/View.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/View.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/View.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController.cs similarity index 50% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController.cs index f5dc32f..d8975b5 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -22,158 +22,6 @@ public abstract class ViewController : IViewController, IViewControllerEvents #region interface - /// - /// Enumerates basic controller commands. - /// - public abstract class Commands - { - #region Common - - /// - /// Name of the OK command. - /// - public const string Ok = "Ok"; - - /// - /// Name of the CANCEL command. - /// - public const string Cancel = "Cancel"; - - /// - /// Name of the APPLY command. - /// - public const string Apply = "Apply"; - - /// - /// Name of the EXIT command. - /// - public const string Exit = "Exit"; - - /// - /// Name of the HELP command. - /// - public const string Help = "Help"; - - /// - /// Name of the ABOUT command. - /// - public const string About = "About"; - - #endregion - - #region Navigation - - /// - /// Name of the BACK command. - /// - public const string Back = "Back"; - - /// - /// Name of the NEXT command. - /// - public const string Next = "Next"; - - /// - /// Name of the PREV command. - /// - public const string Prev = "Prev"; - - /// - /// Name of the HOME command. - /// - public const string Home = "Home"; - - /// - /// Name of the END command. - /// - public const string End = "End"; - - #endregion - - #region File - - /// - /// Name of the NEW command. - /// - public const string New = "New"; - - /// - /// Name of the OPEN command. - /// - public const string Open = "Open"; - - /// - /// Name of the CLOSE command. - /// - public const string Close = "Close"; - - /// - /// Name of the SAVE command. - /// - public const string Save = "Save"; - - #endregion - - #region Editing - - /// - /// Name of the ADD command. - /// - public const string Add = "Add"; - - /// - /// Name of the REMOVE command. - /// - public const string Remove = "Remove"; - - /// - /// Name of the EDIT command. - /// - public const string Edit = "Edit"; - - /// - /// Name of the COPY command. - /// - public const string Copy = "Copy"; - - /// - /// Name of the CUT command. - /// - public const string Cut = "Cut"; - - /// - /// Name of the PASTE command. - /// - public const string Paste = "Paste"; - - /// - /// Name of the INSERT command. - /// - public const string Insert = "Insert"; - - /// - /// Name of the DELETE command. - /// - public const string Delete = "Delete"; - - /// - /// Name of the DUPLICATE command. - /// - public const string Duplicate = "Duplicate"; - - /// - /// Name of the UNDO command. - /// - public const string Undo = "Undo"; - - /// - /// Name of the REDO command. - /// - public const string Redo = "Redo"; - - #endregion - } - /// /// Gets the controller context. /// @@ -193,6 +41,7 @@ public abstract class Commands protected ViewController(IPresentContext context) { _context = context ?? throw new ArgumentNullException(nameof(context)); + _context.View.Command += OnCommand; } /// @@ -220,7 +69,7 @@ protected void ThrowIfDismissed() /// Called to process a command. /// /// Returns if the command has been handles; otherwise. - protected virtual bool OnCommand(string commandName, object commandArgs) + protected virtual bool OnCommand(TCommand command) { return false; } @@ -278,34 +127,29 @@ protected virtual void OnUpdate(float frameTime) #region IViewControllerEvents - /// void IViewControllerEvents.OnActivate() { Debug.Assert(!IsDismissed); OnActivate(); } - /// void IViewControllerEvents.OnDeactivate() { Debug.Assert(!IsDismissed); OnDeactivate(); } - /// void IViewControllerEvents.OnPresent() { Debug.Assert(!IsDismissed); OnPresent(); } - /// void IViewControllerEvents.OnDismiss() { OnDismiss(); } - /// void IViewControllerEvents.OnUpdate(float frameTime) { Debug.Assert(!IsDismissed); @@ -317,28 +161,34 @@ void IViewControllerEvents.OnUpdate(float frameTime) #region ICommandTarget /// - /// Invokes a command. + /// Invokes a command. An implementation might choose to ignore the command, in this case the method should return . /// - /// Name of the command to invoke. - /// Command-specific arguments. - /// Thrown if is . - /// Thrown if the controller is disposed. - /// Returns if the command has been handles; otherwise. - public bool InvokeCommand(string commandName, object args) + /// Command to invoke. + /// Returns if the command has been handled; otherwise. + public bool InvokeCommand(TCommand command) { - ThrowIfDismissed(); - - if (commandName is null) + if (command != null && !_context.IsDismissed) { - throw new ArgumentNullException(nameof(commandName)); + return OnCommand(command); } - return OnCommand(commandName, args); + return false; } #endregion #region implementation + + private void OnCommand(object sender, EventArgs e) + { + Debug.Assert(sender == _context.View); + + if (e != null && !_context.IsDismissed) + { + OnCommand(e); + } + } + #endregion } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Attributes/ViewControllerAttribute.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerAttribute.cs similarity index 52% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Attributes/ViewControllerAttribute.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerAttribute.cs index 6dcec26..c96b882 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Attributes/ViewControllerAttribute.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerAttribute.cs @@ -1,8 +1,7 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; -using UnityEngine; namespace UnityFx.Mvc { @@ -13,25 +12,18 @@ namespace UnityFx.Mvc public sealed class ViewControllerAttribute : Attribute { /// - /// Gets or sets type of the controller result value. + /// Gets or sets default present options value. /// - public Type ResultType { get; set; } - - /// - /// Gets or sets name of the view prefab. - /// - public string ViewPrefabName { get; set; } + public PresentOptions PresentOptions { get; set; } /// - /// Gets or sets present options. + /// Gets or sets path to the view prefab. If this is not set, controller name is used as the prefab path (i.e. 'Help' for controller named 'HelpController'). /// - public PresentOptions PresentOptions { get; set; } + public string PrefabPath { get; set; } /// - /// Initializes a new instance of the class. + /// Gets or sets layer index. /// - public ViewControllerAttribute() - { - } + public int Layer { get; set; } } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Attributes/ViewControllerAttribute.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerAttribute.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Attributes/ViewControllerAttribute.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerAttribute.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerFactory.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerFactory.cs new file mode 100644 index 0000000..f4c0571 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerFactory.cs @@ -0,0 +1,162 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using System.Reflection; +using System.Runtime.ExceptionServices; + +namespace UnityFx.Mvc +{ + /// + /// Provides methods for creation and disposal of view controllers. + /// + /// + public class ViewControllerFactory : IViewControllerFactory + { + #region data + + private readonly IServiceProvider _serviceProvider; + + #endregion + + #region interface + + /// + /// Initializes a new instance of the class. + /// + /// The instance to use. + public ViewControllerFactory(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + } + + #endregion + + #region IViewControllerFactory + + /// + /// Creates a scoped instance. Default implementation does not create scopes. + /// + /// A used to resolve controller dependencies. + /// A disposable scope created or . + public virtual IDisposable CreateScope(ref IServiceProvider serviceProvider) + { + return null; + } + + /// + /// Creates a new instance of and injects its dependencies. + /// + /// Type of the controller to be created. + /// Additional arguments to use when resolving controller dependencies. + /// Thrown if is . + /// Thrown if is not a valid controller type (for instance, is abstract). + /// The created controller instance. + /// + public virtual IViewController Create(Type controllerType, params object[] args) + { + if (controllerType is null) + { + throw new ArgumentNullException(nameof(controllerType)); + } + + try + { + var constructors = controllerType.GetConstructors(BindingFlags.Instance | BindingFlags.Public); + + if (constructors.Length > 0) + { + // Select the first public non-static ctor with matching arguments. + foreach (var ctor in constructors) + { + if (TryGetMethodArguments(ctor, args, out var argValues)) + { + return (IViewController)ctor.Invoke(argValues); + } + } + + throw new InvalidOperationException($"A suitable constructor for type '{controllerType}' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor."); + } + else + { + return (IViewController)Activator.CreateInstance(controllerType); + } + } + catch (TargetInvocationException e) + { + ExceptionDispatchInfo.Capture(e.InnerException).Throw(); + throw e.InnerException; + } + } + + /// + /// Releases a controller after it has been dismissed. Default implementation calls if controller supports it. + /// + /// The controller to be disposed. + /// + public virtual void Release(IViewController controller) + { + if (controller is IDisposable d) + { + d.Dispose(); + } + } + + #endregion + + #region implementation + + private bool TryGetMethodArguments(MethodBase method, object[] args, out object[] argValues) + { + var argInfo = method.GetParameters(); + var argumentsValidated = true; + + argValues = new object[argInfo.Length]; + + for (var i = 0; i < argInfo.Length; ++i) + { + var argType = argInfo[i].ParameterType; + var argValue = default(object); + + // Try to match the argument using args first. + for (var j = 0; j < args.Length; ++j) + { + var arg = args[j]; + + if (arg != null && argType.IsAssignableFrom(arg.GetType())) + { + argValue = arg; + break; + } + } + + // If argument matching failed try to resolve the argument using serviceProvider. + if (argValue == null) + { + argValue = _serviceProvider.GetService(argType); + } + + // If the argument is matched/resolved, store the value, otherwise fail the constructor validation. + if (argValue != null) + { + argValues[i] = argValue; + } + else + { + argumentsValidated = false; + break; + } + } + + // If all arguments matched/resolved, use this constructor for activation. + if (argumentsValidated) + { + return true; + } + + return false; + } + + #endregion + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewControllerFactory.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerFactory.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewControllerFactory.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewControllerFactory.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView,TResult}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView,TResult}.cs similarity index 91% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView,TResult}.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView,TResult}.cs index d026735..3d5e8ed 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView,TResult}.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView,TResult}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -12,7 +12,7 @@ namespace UnityFx.Mvc /// Note that minimal controller implementation should implement . /// /// - public abstract class ViewController : ViewController where TView : class, IView + public abstract class ViewController : ViewController, IViewControllerResult where TView : class, IView { #region data #endregion diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView,TResult}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView,TResult}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView,TResult}.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView,TResult}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView}.cs similarity index 95% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView}.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView}.cs index d3fdb8a..d425bc1 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView}.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewController{TView}.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Mvc/ViewController{TView}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext.cs new file mode 100644 index 0000000..8828dca --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext.cs @@ -0,0 +1,76 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc +{ + /// + /// Context data for a instance. The class is a link between and its controllers. + /// + /// + /// + public interface IPresentContext : IPresenter, IServiceProvider + { + /// + /// Gets unique identifier of the controller. + /// + int Id { get; } + + /// + /// Gets the deepling identifier for this controller. + /// + string DeeplinkId { get; } + + /// + /// Gets the controller present arguments. + /// + /// + PresentArgs PresentArgs { get; } + + /// + /// Gets the present flags used when instantiating the controller. + /// + /// + PresentOptions PresentOptions { get; } + + /// + /// Gets time elapsed since the controller has been presented (in seconds). + /// + float PresentTime { get; } + + /// + /// Gets a value indicating whether the controller is active. + /// + /// + bool IsActive { get; } + + /// + /// Gets a value indicating whether the controller is dismissed. + /// + /// + /// + bool IsDismissed { get; } + + /// + /// Gets the controller view. + /// + IView View { get; } + + /// + /// Schedules a callback to be called in the specified . + /// + /// The callback to be called when the time is out. + /// Timeout value in seconds. + void Schedule(Action timerCallback, float timeout); + + /// + /// Dismisses the controller. + /// + /// + /// This call also dismisses all controllers presented by the owner. + /// + /// + void Dismiss(); + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext{TResult}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext{TResult}.cs similarity index 69% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext{TResult}.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext{TResult}.cs index c499628..9543e7f 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext{TResult}.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext{TResult}.cs @@ -1,20 +1,19 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; -using System.Net; namespace UnityFx.Mvc { /// /// Context data for an instance. The class is a link between and its controllers. - /// It is here for the sake of testability/explicit dependencies for implementations. /// + /// /// public interface IPresentContext : IPresentContext { /// - /// Dismisses the controller. + /// Dismisses the controller with a specific . /// void Dismiss(TResult result); } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext{TResult}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext{TResult}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext{TResult}.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentContext{TResult}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult.cs new file mode 100644 index 0000000..b752870 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult.cs @@ -0,0 +1,27 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using System.ComponentModel; +using System.Threading.Tasks; + +namespace UnityFx.Mvc +{ + /// + /// Result of a present operation. Disposing the present result dismisses the attached controller (and its view). + /// + /// + /// + public interface IPresentResult : ICommandTarget, IDisposable + { + /// + /// Gets unique identifier of the present operation. + /// + int Id { get; } + + /// + /// Gets a instance that can be used to await the operation completion (i.e. until the controller is dismissed). + /// + Task Task { get; } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController,TResult}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController,TResult}.cs new file mode 100644 index 0000000..8381ebf --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController,TResult}.cs @@ -0,0 +1,20 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using System.Threading.Tasks; + +namespace UnityFx.Mvc +{ + /// + /// Result of a present operation. + /// + /// + public interface IPresentResultOf : IPresentResult, IViewControllerResultAccess, IViewControllerAccess where TController : IViewController + { + /// + /// Gets a instance that can be used to await the operation completion. + /// + new Task Task { get; } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController,TResult}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController,TResult}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController,TResult}.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController,TResult}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController}.cs similarity index 53% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController}.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController}.cs index 17ac671..351c601 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController}.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -10,11 +10,7 @@ namespace UnityFx.Mvc /// Result of a present operation. /// /// - public interface IPresentResult : IPresentResult where TController : IViewController + public interface IPresentResultOf : IPresentResult, IViewControllerAccess where TController : IViewController { - /// - /// Gets the view controller. - /// - new TController Controller { get; } } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult{TController}.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResultOf{TController}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult{TResult}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult{TResult}.cs new file mode 100644 index 0000000..ea8d7f2 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult{TResult}.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using System.Threading.Tasks; + +namespace UnityFx.Mvc +{ + /// + /// Result of a present operation having with a result. + /// + /// Type of the result value. + /// + public interface IPresentResult : IPresentResult, IViewControllerResultAccess + { + /// + /// Gets a instance that can be used to await the operation completion. + /// + new Task Task { get; } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult{TResult}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult{TResult}.cs.meta new file mode 100644 index 0000000..f311e64 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresentResult{TResult}.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bfc1d02456d24494d9b6ac161f18c780 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenter.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenter.cs similarity index 73% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenter.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenter.cs index 6a8aaf8..fe1e0ca 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenter.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenter.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -9,6 +9,10 @@ namespace UnityFx.Mvc /// /// An object capable of presenting view controllers. /// + /// + /// Please note that users of this type should not access or its directly. + /// Instead, can be used to track the controller lifetime events or to dismiss it. + /// /// /// /// @@ -18,13 +22,13 @@ public interface IPresenter /// Presents a controller of the specified type. /// /// Type of the view controller to present. + /// Controller arguments. /// Present flags. /// Parent transform for the view (or ). - /// Controller arguments. - /// An object that can be used to track the operation progress. + /// An object that can be used to track the operation propress. /// Thrown if is . /// Thrown if cannot be used to instantiate the controller (for instance, it is abstract type). /// Thrown if the presenter is disposed. - IPresentResult PresentAsync(Type controllerType, PresentOptions presentOptions, Transform parent, PresentArgs args); + IPresentResult Present(Type controllerType, PresentArgs args, PresentOptions presentOptions, Transform parent); } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenter.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenter.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenter.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenter.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenterExtensions.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenterExtensions.cs new file mode 100644 index 0000000..79b6e53 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenterExtensions.cs @@ -0,0 +1,509 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using System.ComponentModel; +using System.Threading.Tasks; +using UnityEngine; + +namespace UnityFx.Mvc +{ + /// + /// Extensions of interface. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class IPresenterExtensions + { + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static IPresentResult Present(this IPresenter presenter, Type controllerType) + { + return presenter.Present(controllerType, null, PresentOptions.None, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static Task PresentAsync(this IPresenter presenter, Type controllerType) + { + return presenter.Present(controllerType, null, PresentOptions.None, null).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static IPresentResult Present(this IPresenter presenter, Type controllerType, PresentArgs args) + { + return presenter.Present(controllerType, args, PresentOptions.None, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static Task PresentAsync(this IPresenter presenter, Type controllerType, PresentArgs args) + { + return presenter.Present(controllerType, args, PresentOptions.None, null).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// Present options. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static IPresentResult Present(this IPresenter presenter, Type controllerType, PresentArgs args, PresentOptions options) + { + return presenter.Present(controllerType, args, options, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// Present options. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static Task PresentAsync(this IPresenter presenter, Type controllerType, PresentArgs args, PresentOptions options) + { + return presenter.Present(controllerType, args, options, null).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// Controller arguments. + /// Present options. + /// Parent transform of the controller view. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static Task PresentAsync(this IPresenter presenter, Type controllerType, PresentArgs args, PresentOptions options, Transform transform) + { + return presenter.Present(controllerType, args, options, transform).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// Present options. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static IPresentResult Present(this IPresenter presenter, Type controllerType, PresentOptions options) + { + return presenter.Present(controllerType, null, options, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// Present options. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static Task PresentAsync(this IPresenter presenter, Type controllerType, PresentOptions options) + { + return presenter.Present(controllerType, null, options, null).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// Present options. + /// Parent transform of the controller view. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static IPresentResult Present(this IPresenter presenter, Type controllerType, PresentOptions options, Transform transform) + { + return presenter.Present(controllerType, null, options, transform); + } + + /// + /// Presents a controller of the specified type. + /// + /// The presenter. + /// Type of the view controller to present. + /// Present options. + /// Parent transform of the controller view. + /// An object that can be used to track the operation progress. + /// Thrown if is . + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + /// + public static Task PresentAsync(this IPresenter presenter, Type controllerType, PresentOptions options, Transform transform) + { + return presenter.Present(controllerType, null, options, transform).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter) where TController : IViewController + { + return (IPresentResultOf)presenter.Present(typeof(TController), null, PresentOptions.None, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter) where TController : IViewController + { + return presenter.Present(typeof(TController), null, PresentOptions.None, null).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter, PresentArgs args) where TController : IViewController + { + return (IPresentResultOf)presenter.Present(typeof(TController), args, PresentOptions.None, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter, PresentArgs args) where TController : IViewController + { + return presenter.Present(typeof(TController), args, PresentOptions.None, null).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// Present options. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter, PresentArgs args, PresentOptions options) where TController : IViewController + { + return (IPresentResultOf)presenter.Present(typeof(TController), args, options, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// Present options. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter, PresentArgs args, PresentOptions options) where TController : IViewController + { + return presenter.Present(typeof(TController), args, options, null).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// Present options. + /// Parent transform of the controller view. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter, PresentArgs args, PresentOptions options, Transform transform) where TController : IViewController + { + return (IPresentResultOf)presenter.Present(typeof(TController), args, options, transform); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// Present options. + /// Parent transform of the controller view. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter, PresentArgs args, PresentOptions options, Transform transform) where TController : IViewController + { + return presenter.Present(typeof(TController), args, options, transform).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// Present options. + /// Parent transform of the controller view. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter, PresentOptions options, Transform transform) where TController : IViewController + { + return (IPresentResultOf)presenter.Present(typeof(TController), null, options, transform); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// The presenter. + /// Present options. + /// Parent transform of the controller view. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter, PresentOptions options, Transform transform) where TController : IViewController + { + return presenter.Present(typeof(TController), null, options, transform).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter) where TController : IViewController, IViewControllerResult + { + return (IPresentResultOf)presenter.Present(typeof(TController), null, PresentOptions.None, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter) where TController : IViewController, IViewControllerResult + { + return ((IPresentResultOf)presenter.Present(typeof(TController), null, PresentOptions.None, null)).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter, PresentArgs args) where TController : IViewController, IViewControllerResult + { + return (IPresentResultOf)presenter.Present(typeof(TController), args, PresentOptions.None, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter, PresentArgs args) where TController : IViewController, IViewControllerResult + { + return ((IPresentResultOf)presenter.Present(typeof(TController), args, PresentOptions.None, null)).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// Controller arguments. + /// Present options. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter, PresentArgs args, PresentOptions options) where TController : IViewController, IViewControllerResult + { + return (IPresentResultOf)presenter.Present(typeof(TController), args, options, null); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// Controller arguments. + /// Present options. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter, PresentArgs args, PresentOptions options) where TController : IViewController, IViewControllerResult + { + return ((IPresentResultOf)presenter.Present(typeof(TController), args, options, null)).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// Present options. + /// Parent transform of the controller view. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter, PresentArgs args, PresentOptions options, Transform transform) where TController : IViewController, IViewControllerResult + { + return (IPresentResultOf)presenter.Present(typeof(TController), args, options, transform); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// Present options. + /// Parent transform of the controller view. + /// Controller arguments. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter, PresentArgs args, PresentOptions options, Transform transform) where TController : IViewController, IViewControllerResult + { + return ((IPresentResultOf)presenter.Present(typeof(TController), args, options, transform)).Task; + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// Present options. + /// Parent transform of the controller view. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static IPresentResultOf Present(this IPresenter presenter, PresentOptions options, Transform transform) where TController : IViewController, IViewControllerResult + { + return (IPresentResultOf)presenter.Present(typeof(TController), null, options, transform); + } + + /// + /// Presents a controller of the specified type. + /// + /// Type of the controller to instantiate. + /// Type of the controller result value. + /// The presenter. + /// Present options. + /// Parent transform of the controller view. + /// An object that can be used to track the operation progress. + /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). + /// Thrown if the does not match result type of the . + /// Thrown if the presenter is disposed. + public static Task PresentAsync(this IPresenter presenter, PresentOptions options, Transform transform) where TController : IViewController, IViewControllerResult + { + return ((IPresentResultOf)presenter.Present(typeof(TController), null, options, transform)).Task; + } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenterExtensions.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenterExtensions.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenterExtensions.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/IPresenterExtensions.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs.cs similarity index 98% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs.cs index 0c6c15f..1f854b9 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs{T}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs{T}.cs similarity index 96% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs{T}.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs{T}.cs index bb937b6..a1afb21 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs{T}.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs{T}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs{T}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs{T}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentArgs{T}.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentArgs{T}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentOptions.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentOptions.cs similarity index 64% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentOptions.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentOptions.cs index a1a547b..ef1dc66 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentOptions.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentOptions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -19,7 +19,8 @@ public enum PresentOptions None = 0, /// - /// Marks the controller as exclusive. Exclusive controllers cover all other controllers below. Cannot be combined with . + /// Marks the controller as exclusive. Exclusive controllers do not forward unprocessed commands to controllers below them is the stack + /// and it is assumed their views are full-screen. Cannot be combined with . /// Exclusive = 1, @@ -33,13 +34,18 @@ public enum PresentOptions /// Modal = 4, + /// + /// Parents the presented controller to the caller. Child controllers are dismissed with their parent controllers. + /// + Child = 0x10, + /// /// If set the caller presenter is dismissed. /// DismissCurrent = 0x1000, /// - /// If set the caller presenter is dismissed. + /// If set all controllers are dismissed before presenting the new one. /// DismissAll = 0x2000 } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentOptions.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentOptions.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/PresentOptions.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/Presenters/PresentOptions.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/UnityFx.Mvc.Abstractions.asmdef b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/UnityFx.Mvc.Abstractions.asmdef new file mode 100644 index 0000000..f682de4 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/UnityFx.Mvc.Abstractions.asmdef @@ -0,0 +1,3 @@ +{ + "name": "UnityFx.Mvc.Abstractions" +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/UnityFx.Mvc.Abstractions.asmdef.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/UnityFx.Mvc.Abstractions.asmdef.meta new file mode 100644 index 0000000..62fd6a7 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Abstractions/UnityFx.Mvc.Abstractions.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2b10b0ce15871aa4c8b8aa574809b662 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Common.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Common.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Common.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Common.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Common/AssemblyInfo.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Common/AssemblyInfo.cs similarity index 86% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Common/AssemblyInfo.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Common/AssemblyInfo.cs index f3e7f47..f6bd637 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Common/AssemblyInfo.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Common/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System.Reflection; @@ -13,12 +13,12 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("UnityFx.Mvc")] -[assembly: AssemblyCopyright("Copyright © Alexander Bogarsukov 2018-2019")] +[assembly: AssemblyCopyright("Copyright © 2018-2020 Alexander Bogarsukov")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Common/AssemblyInfo.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Common/AssemblyInfo.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Common/AssemblyInfo.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Common/AssemblyInfo.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable.cs similarity index 63% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable.cs index d674b3f..3eb530e 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -8,10 +8,15 @@ namespace UnityFx.Mvc { - internal interface IPresentable : IPresentResult, ICommandTarget + internal interface IPresentable : IPresentResult { + int Layer { get; } + bool IsActive { get; } bool IsDismissed { get; } IPresentable Parent { get; } + PresentOptions PresentOptions { get; } + PresentArgs PresentArgs { get; } + Type ControllerType { get; } Task PresentAsync(IViewFactory viewFactory, int index, Transform parent); void Update(float frameTime, bool isTop); void DismissUnsafe(); diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentableExtensions.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentableExtensions.cs similarity index 89% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentableExtensions.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentableExtensions.cs index 70966e1..640f5df 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentableExtensions.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentableExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentableExtensions.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentableExtensions.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentableExtensions.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentableExtensions.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable{T}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable{T}.cs similarity index 76% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable{T}.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable{T}.cs index beb8333..9620f80 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable{T}.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable{T}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -8,7 +8,7 @@ namespace UnityFx.Mvc { - internal interface IPresentable : IPresentable, IPresentResult where T : IViewController + internal interface IPresentable : IPresentable, IPresentResultOf where T : IViewController { } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable{T}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable{T}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresentable{T}.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresentable{T}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresenterInternal.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresenterInternal.cs similarity index 71% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresenterInternal.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresenterInternal.cs index 09090ae..1bfe8dd 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresenterInternal.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresenterInternal.cs @@ -1,18 +1,14 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; -using System.Threading; -using System.Threading.Tasks; using UnityEngine; namespace UnityFx.Mvc { internal interface IPresenterInternal { - IServiceProvider ServiceProvider { get; } IPresentResult PresentAsync(IPresentable presentable, Type controllerType, PresentOptions presentOptions, Transform parent, PresentArgs args); void Dismiss(IPresentable presentable); - int GetNextId(); } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresenterInternal.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresenterInternal.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/IPresenterInternal.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/IPresenterInternal.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResultArgs.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResultArgs.cs new file mode 100644 index 0000000..9ed6da1 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResultArgs.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; + +namespace UnityFx.Mvc +{ + internal class PresentResultArgs + { + public IServiceProvider ServiceProvider; + public IViewControllerFactory ControllerFactory; + public IViewFactory ViewFactory; + + public int Id; + public int Layer; + public string PrefabPath; + + public IPresentable Parent; + public Type ControllerType; + public PresentOptions PresentOptions; + public PresentArgs PresentArgs; + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResultArgs.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResultArgs.cs.meta new file mode 100644 index 0000000..d3c33e4 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResultArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 47ae981f6e6aeb94c833b12f80c7c76c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresentResult{TController,TResult}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResult{TController,TResult}.cs similarity index 67% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresentResult{TController,TResult}.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResult{TController,TResult}.cs index 1d26437..f3a8819 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresentResult{TController,TResult}.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResult{TController,TResult}.cs @@ -1,14 +1,13 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Collections; using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; using UnityEngine; +using UnityEngine.Scripting; namespace UnityFx.Mvc { @@ -20,7 +19,8 @@ namespace UnityFx.Mvc /// controller context outside of actual controller. This class manages the controller created, provides its context /// (via interface) and serves as a proxy between the controller and user. /// - internal class PresentResult : TaskCompletionSource, IPresentContext, IPresentResult, IPresentable, IEnumerator where TController : class, IViewController + [Preserve] + internal sealed class PresentResult : TaskCompletionSource, IPresentContext, IPresentResult, IPresentResultOf, IPresentResultOf, IPresentable, IEnumerator where TController : class, IViewController { #region data @@ -41,61 +41,66 @@ private struct TimerData } private readonly IPresenterInternal _presenter; + private readonly IViewControllerFactory _controllerFactory; private readonly Type _controllerType; private readonly PresentArgs _presentArgs; private readonly PresentOptions _presentOptions; private readonly IPresentable _parent; private readonly int _id; + private readonly int _layer; + private readonly string _prefabPath; + private readonly string _deeplinkId; private IServiceProvider _serviceProvider; private IDisposable _scope; private TController _controller; + private IViewControllerEvents _controllerEvents; private IView _view; private LinkedList _timers; private float _timer; private List _exceptions; - private TaskCompletionSource _presentTcs; private State _state; #endregion #region interface - public PresentResult(IPresenterInternal presenter, IPresentable parent, Type controllerType, PresentOptions presentOptions, PresentArgs args) - : base(parent) + public PresentResult(IPresenterInternal presenter, PresentResultArgs context) { Debug.Assert(presenter != null); - Debug.Assert(controllerType != null); - Debug.Assert(args != null); + Debug.Assert(context != null); _presenter = presenter; - _parent = parent; - _serviceProvider = presenter.ServiceProvider; - _controllerType = controllerType; - _presentArgs = args; - _presentOptions = presentOptions; - _id = presenter.GetNextId(); + _id = context.Id; + _layer = context.Layer; + _parent = context.Parent; + _serviceProvider = context.ServiceProvider; + _controllerFactory = context.ControllerFactory; + _controllerType = context.ControllerType; + _presentArgs = context.PresentArgs; + _presentOptions = context.PresentOptions; + _deeplinkId = GetDeeplinkId(_controllerType); + _prefabPath = string.IsNullOrEmpty(context.PrefabPath) ? GetDefaultPrefabName(_controllerType) : context.PrefabPath; } #endregion #region IPresentable + public int Layer => _layer; + public IPresentable Parent => _parent; + public Type ControllerType => _controllerType; + public bool TryActivate() { if (_state == State.Presented) { _state = State.Active; - - if (_controller is IViewControllerEvents c) - { - c.OnActivate(); - } - + _controllerEvents?.OnActivate(); return true; } @@ -107,12 +112,7 @@ public bool TryDeactivate() if (_state == State.Active) { _state = State.Presented; - - if (_controller is IViewControllerEvents c) - { - c.OnDeactivate(); - } - + _controllerEvents?.OnDeactivate(); return true; } @@ -126,7 +126,7 @@ public async Task PresentAsync(IViewFactory viewFactory, int index, Transform pa try { - _view = await viewFactory.CreateViewAsync(_controllerType, index, _presentOptions, parent); + _view = await viewFactory.CreateAsync(_prefabPath, _layer, index, _presentOptions, parent); if (_state == State.Initialized) { @@ -135,30 +135,12 @@ public async Task PresentAsync(IViewFactory viewFactory, int index, Transform pa throw new InvalidOperationException(); } - if (_serviceProvider.GetService(typeof(IViewControllerFactory)) is IViewControllerFactory controllerFactory) - { - _scope = controllerFactory.CreateControllerScope(ref _serviceProvider); - _controller = (TController)controllerFactory.CreateController(_controllerType, this, _presentArgs, _view); - } - else - { - _controller = (TController)ActivatorUtilities.CreateInstance(_serviceProvider, _controllerType, this, _presentArgs, _view); - } - - if (_controller is null) - { - throw new InvalidOperationException(); - } - + _scope = _controllerFactory.CreateScope(ref _serviceProvider); + _controller = (TController)_controllerFactory.Create(_controllerType, this, _presentArgs, _view); + _controllerEvents = _controller as IViewControllerEvents; + _controllerEvents?.OnPresent(); _view.Disposed += OnDismissed; - - if (_controller is IViewControllerEvents c) - { - c.OnPresent(); - } - _state = State.Presented; - _presentTcs?.TrySetResult(_controller); } else { @@ -169,10 +151,9 @@ public async Task PresentAsync(IViewFactory viewFactory, int index, Transform pa } catch (Exception e) { - _presentTcs?.TrySetException(e); - LogException(e); DismissInternal(default, true); + throw; } } @@ -272,11 +253,13 @@ public void Dismiss() public int Id => _id; + public string DeeplinkId => _deeplinkId; + public PresentArgs PresentArgs => _presentArgs; public PresentOptions PresentOptions => _presentOptions; - public float Timer => _timer; + public float PresentTime => _timer; public bool IsActive => _state == State.Active; @@ -284,7 +267,7 @@ public void Dismiss() #region IPresenter - public IPresentResult PresentAsync(Type controllerType, PresentOptions presentOptions, Transform parent, PresentArgs args) + public IPresentResult Present(Type controllerType, PresentArgs args, PresentOptions presentOptions, Transform parent) { ThrowIfDisposed(); return _presenter.PresentAsync(this, controllerType, presentOptions, parent, args); @@ -294,29 +277,7 @@ public IPresentResult PresentAsync(Type controllerType, PresentOptions presentOp #region IPresentResult - IViewController IPresentResult.Controller => _controller; - - Task IPresentResult.DismissTask => Task; - - Task IPresentResult.DismissTask => Task; - - Task IPresentResult.PresentTask - { - get - { - if (_presentTcs is null) - { - if (_state != State.Initialized) - { - return System.Threading.Tasks.Task.CompletedTask; - } - - _presentTcs = new TaskCompletionSource(); - } - - return _presentTcs.Task; - } - } + Task IPresentResult.Task => Task; public TController Controller => _controller; @@ -326,21 +287,14 @@ Task IPresentResult.PresentTask #region ICommandTarget - public bool InvokeCommand(string commandName, object args) + public bool InvokeCommand(TCommand command) { - ThrowIfDisposed(); - - if (commandName is null) + if (_state == State.Presented || _state == State.Active) { - throw new ArgumentNullException(nameof(commandName)); + return _controller.InvokeCommand(command); } - if (_state != State.Presented && _state != State.Active) - { - throw new InvalidOperationException(); - } - - return _controller.InvokeCommand(commandName, args); + return false; } #endregion @@ -409,12 +363,7 @@ private void DismissInternal(TResult result, bool cancelled) if (_state != State.Disposed) { _state = State.Disposed; - - if (_controller is IDisposable d) - { - d.Dispose(); - } - + _controllerFactory.Release(_controller); _view?.Dispose(); _scope?.Dispose(); } @@ -442,49 +391,24 @@ private void DismissInternal(TResult result, bool cancelled) private void UpdateActive(bool isTop) { - try + if (isTop) { - if (isTop) + if (_state == State.Presented) { - if (_state == State.Presented) - { - _state = State.Active; - - if (_controller is IViewControllerEvents c) - { - c.OnActivate(); - } - } - } - else if (_state == State.Active) - { - _state = State.Presented; - - if (_controller is IViewControllerEvents c) - { - c.OnDeactivate(); - } + _state = State.Active; + _controllerEvents?.OnActivate(); } } - catch (Exception e) + else if (_state == State.Active) { - Debug.LogException(e); + _state = State.Presented; + _controllerEvents?.OnDeactivate(); } } private void UpdateController(float frameTime) { - if (_controller is IViewControllerEvents c) - { - try - { - c.OnUpdate(frameTime); - } - catch (Exception e) - { - Debug.LogException(e); - } - } + _controllerEvents?.OnUpdate(frameTime); } private void UpdateTimers(float frameTime) @@ -501,16 +425,8 @@ private void UpdateTimers(float frameTime) if (timerData.Timer >= timerData.Timeout) { - try - { - timerData.Callback(timerData.Timer); - } - catch (Exception e) - { - Debug.LogException(e); - } - _timers.Remove(node); + timerData.Callback(timerData.Timer); } node = node.Next; @@ -520,8 +436,6 @@ private void UpdateTimers(float frameTime) private void LogException(Exception e) { - Debug.LogException(e); - if (!Task.IsCompleted) { if (_exceptions == null) @@ -548,6 +462,30 @@ private void ThrowIfDisposed() } } + private static string GetDeeplinkId(Type controllerType) + { + var deeplinkId = controllerType.Name.ToLower(); + + if (deeplinkId.EndsWith("controller")) + { + deeplinkId = deeplinkId.Substring(0, deeplinkId.Length - 10); + } + + return deeplinkId; + } + + private static string GetDefaultPrefabName(Type controllerType) + { + var deeplinkId = controllerType.Name; + + if (deeplinkId.EndsWith("Controller")) + { + deeplinkId = deeplinkId.Substring(0, deeplinkId.Length - 10); + } + + return deeplinkId; + } + #endregion } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresentResult{TController,TResult}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResult{TController,TResult}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresentResult{TController,TResult}.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresentResult{TController,TResult}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter.cs similarity index 92% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter.cs index 7192ec0..c6c2d60 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresenterBase.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresenterBase.cs similarity index 93% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresenterBase.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresenterBase.cs index a39f0a4..9a71be1 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresenterBase.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresenterBase.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresenterBase.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresenterBase.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/PresenterBase.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/PresenterBase.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter{T}.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter{TController}.cs similarity index 62% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter{T}.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter{TController}.cs index 0c3d5c4..171d3a7 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter{T}.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter{TController}.cs @@ -1,14 +1,13 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Collections; using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; using UnityEngine; +using UnityEngine.Scripting; namespace UnityFx.Mvc { @@ -17,14 +16,15 @@ namespace UnityFx.Mvc /// /// /// - public class Presenter : PresenterBase, IPresenterInternal, IPresenter, ICommandTarget, IDisposable where T : class, IViewController + public class Presenter : PresenterBase, IPresenterInternal, IPresenter, ICommandTarget, IDisposable where TController : class, IViewController { #region data private IServiceProvider _serviceProvider; private IViewFactory _viewFactory; + private IViewControllerFactory _controllerFactory; - private LinkedList> _presentables = new LinkedList>(); + private LinkedList> _presentables = new LinkedList>(); private ViewControllerCollection _controllers; private int _idCounter; @@ -38,11 +38,11 @@ public class Presenter : PresenterBase, IPresenterInternal, IPresenter, IComm /// /// A read-only stack of objects. /// - public class ViewControllerCollection : IReadOnlyCollection + public class ViewControllerCollection : IReadOnlyCollection { - private readonly LinkedList> _presentables; + private readonly LinkedList> _presentables; - internal ViewControllerCollection(LinkedList> presentables) + internal ViewControllerCollection(LinkedList> presentables) { _presentables = presentables; } @@ -51,7 +51,7 @@ internal ViewControllerCollection(LinkedList> presentables) /// Gets top element of the stack. /// /// Thrown if the collection is empty. - public T Peek() + public TController Peek() { if (_presentables.First is null) { @@ -64,7 +64,7 @@ public T Peek() /// /// Attempts to get top controller of the collection. /// - public bool TryPeek(out T controller) + public bool TryPeek(out TController controller) { controller = _presentables.Last?.Value.Controller; return controller != null; @@ -105,7 +105,7 @@ public bool Contains(Type controllerType) /// /// Enumerates all controllers in the collection starting with the top (last) one. /// - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { var node = _presentables.First; @@ -133,7 +133,7 @@ public IEnumerator GetEnumerator() /// /// Gets an active controller (or ). /// - public T ActiveController + public TController ActiveController { get { @@ -159,14 +159,35 @@ public T ActiveController protected bool IsDisposed => _disposed; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. + /// + /// A used to resolve controller dependencies. + /// + public void Initialize(IServiceProvider serviceProvider) + { + if (serviceProvider is null) + { + throw new ArgumentNullException(nameof(serviceProvider)); + } + + var viewFactory = (IViewFactory)serviceProvider.GetService(typeof(IViewFactory)); + var viewControllerFactory = (IViewControllerFactory)(serviceProvider.GetService(typeof(IViewControllerFactory)) ?? new ViewControllerFactory(serviceProvider)); + + Initialize(serviceProvider, viewFactory, viewControllerFactory); + } + + /// + /// Initializes a new instance of the class. /// /// A used to resolve controller dependencies. /// A that is used to create views. - public void Initialize(IServiceProvider serviceProvider, IViewFactory viewFactory) + /// A used to create controller. + /// + public void Initialize(IServiceProvider serviceProvider, IViewFactory viewFactory, IViewControllerFactory controllerFactory) { _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); _viewFactory = viewFactory ?? throw new ArgumentNullException(nameof(viewFactory)); + _controllerFactory = controllerFactory ?? throw new ArgumentNullException(nameof(controllerFactory)); _controllers = new ViewControllerCollection(_presentables); } @@ -195,7 +216,7 @@ public void DismissAllPopups() /// /// Gets top popup controller or . /// - protected IPresentResult GetPresentResult(T controller) + protected IPresentResultOf GetPresentResult(TController controller) { foreach (var p in _presentables) { @@ -221,10 +242,44 @@ protected void ThrowIfDisposed() } } +#if ENABLE_IL2CPP + + /// + /// Call this on AOT platforms to make sure all needed code exists in runtime. + /// + protected static void AotCodegenGuard() + { + new PresentResult(null, null, typeof(TController), PresentOptions.None, PresentArgs.Default); + } + +#endif + #endregion #region virtual interface + /// + /// Called right before presenting a controller. + /// + protected virtual void OnPresent(Type controllerType, PresentOptions presentOptions, PresentArgs args) + { + } + + /// + /// Called right after presenting a controller. + /// + protected virtual void OnPresented(Type controllerType) + { + } + + /// + /// Called right before presenting a controller. + /// + protected virtual void OnPresentError(Type controllerType, Exception e) + { + Debug.LogException(e); + } + /// /// Called on each frame. Default implementation does nothing. /// @@ -333,16 +388,11 @@ void IPresenterInternal.Dismiss(IPresentable presentable) } } - int IPresenterInternal.GetNextId() - { - return ++_idCounter; - } - #endregion #region IPresenter - public IPresentResult PresentAsync(Type controllerType, PresentOptions presentOptions, Transform parent, PresentArgs args) + public IPresentResult Present(Type controllerType, PresentArgs args, PresentOptions presentOptions, Transform parent) { return PresentInternal(null, controllerType, presentOptions, parent, args); } @@ -352,17 +402,13 @@ public IPresentResult PresentAsync(Type controllerType, PresentOptions presentOp #region ICommandTarget /// - /// Invokes a command on the controllers presented. + /// Invokes a command. An implementation might choose to ignore the command, in this case the method should return . /// - /// Name of the command to invoke. - /// Command-specific arguments. - /// Thrown if the controller is disposed. + /// Command to invoke. /// Returns if the command has been handled; otherwise. - public bool InvokeCommand(string commandName, object args) + public bool InvokeCommand(TCommand command) { - ThrowIfDisposed(); - - if (!string.IsNullOrEmpty(commandName)) + if (command != null && !_disposed) { var node = _presentables.Last; @@ -370,7 +416,7 @@ public bool InvokeCommand(string commandName, object args) { var p = node.Value; - if (p.InvokeCommand(commandName, args)) + if (p.InvokeCommand(command)) { return true; } @@ -382,7 +428,6 @@ public bool InvokeCommand(string commandName, object args) node = node.Previous; } - } return false; @@ -424,86 +469,97 @@ private IPresentResult PresentInternal(IPresentable presentable, Type controller return result; } - private void PresentInternal(IPresentable presentable, IPresentable presentableParent, Transform transform) + private async void PresentInternal(IPresentable presentable, IPresentable presentableParent, Transform transform) { - var zIndex = 0; + var zIndex = GetZIndex(presentable); - foreach (var p in _presentables) + try { - if (p == presentable) - { - break; - } + OnPresent(presentable.ControllerType, presentable.PresentOptions, presentable.PresentArgs); - ++zIndex; - } - - presentable.PresentAsync(_viewFactory, zIndex, transform); + await presentable.PresentAsync(_viewFactory, zIndex, transform); - if ((presentable.PresentOptions & PresentOptions.DismissAll) != 0) - { - foreach (var p in _presentables) + if ((presentable.PresentOptions & PresentOptions.DismissAll) != 0) { - if (p != presentable) + foreach (var p in _presentables) { - p.Dispose(); + if (p != presentable) + { + p.Dispose(); + } } } + else if ((presentable.PresentOptions & PresentOptions.DismissCurrent) != 0) + { + presentableParent?.Dispose(); + } + + OnPresented(presentable.ControllerType); } - else if ((presentable.PresentOptions & PresentOptions.DismissCurrent) != 0) + catch (Exception e) { - presentableParent?.Dispose(); + OnPresentError(presentable.ControllerType, e); } } - private IPresentable CreatePresentable(IPresentable parent, Type controllerType, PresentOptions presentOptions, PresentArgs args) + private IPresentable CreatePresentable(IPresentable parent, Type controllerType, PresentOptions presentOptions, PresentArgs args) { Debug.Assert(controllerType != null); Debug.Assert(!_disposed); var resultType = typeof(int); - var controllerAttr = default(ViewControllerAttribute); var attrs = (ViewControllerAttribute[])controllerType.GetCustomAttributes(typeof(ViewControllerAttribute), false); + var presentContext = new PresentResultArgs() + { + Id = ++_idCounter, + ServiceProvider = _serviceProvider, + ControllerFactory = _controllerFactory, + ViewFactory = _viewFactory, + ControllerType = controllerType, + Parent = parent, + PresentOptions = presentOptions, + PresentArgs = args ?? PresentArgs.Default + }; if (attrs != null && attrs.Length > 0) { - controllerAttr = attrs[0]; - presentOptions |= controllerAttr.PresentOptions; + var controllerAttr = attrs[0]; - if (controllerAttr.ResultType != null) - { - resultType = controllerAttr.ResultType; - } + presentContext.PresentOptions |= controllerAttr.PresentOptions; + presentContext.Layer = controllerAttr.Layer; + presentContext.PrefabPath = controllerAttr.PrefabPath; } - // Types inherited from ViewController<,> do not require ViewControllerAttribute. - if (typeof(ViewController<,>).IsAssignableFrom(controllerType)) + // Types inherited from IViewControllerResult<> use specific result values. + if (typeof(IViewControllerResult<>).IsAssignableFrom(controllerType)) { - resultType = controllerType.GenericTypeArguments[1]; + resultType = controllerType.GenericTypeArguments[0]; } - // Make sure args are valid. - if (args is null) + // If parent is going to be dismissed, use its parent instead. + if ((presentOptions & PresentOptions.Child) == 0) { - args = PresentArgs.Default; + presentContext.Parent = null; } - - // If parent is going to be dismissed, use its parent instead. - if ((presentOptions & PresentOptions.DismissCurrent) != 0) + else if ((presentOptions & PresentOptions.DismissAll) != 0) { - parent = parent?.Parent; + presentContext.Parent = null; + } + else if ((presentOptions & PresentOptions.DismissCurrent) != 0) + { + presentContext.Parent = parent?.Parent; } // https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/how-to-examine-and-instantiate-generic-types-with-reflection var presentResultType = typeof(PresentResult<,>).MakeGenericType(controllerType, resultType); - var c = (IPresentable)Activator.CreateInstance(presentResultType, this, parent, controllerType, presentOptions, args); + var c = (IPresentable)Activator.CreateInstance(presentResultType, this, presentContext); AddPresentable(c); return c; } - private void AddPresentable(IPresentable presentable) + private void AddPresentable(IPresentable presentable) { Debug.Assert(presentable != null); Debug.Assert(!_disposed); @@ -555,36 +611,35 @@ private void DisposeInternal() } } - private Type GetControllerResultType(Type controllerType) + private void SetBusy(bool busy) { - // Types inherited from ViewController<> do not require ViewControllerAttribute. - if (typeof(ViewController<,>).IsAssignableFrom(controllerType)) + if (busy) { - return controllerType.GenericTypeArguments[1]; + ++_busyCounter; } else { - var attrs = (ViewControllerAttribute[])controllerType.GetCustomAttributes(typeof(ViewControllerAttribute), false); - - if (attrs != null && attrs.Length > 0) - { - return attrs[0].ResultType; - } + --_busyCounter; } - - return null; } - private void SetBusy(bool busy) + private int GetZIndex(IPresentable presentable) { - if (busy) - { - ++_busyCounter; - } - else + var zIndex = 0; + + foreach (var p in _presentables) { - --_busyCounter; + if (p == presentable) + { + break; + } + else if (p.Layer == presentable.Layer) + { + ++zIndex; + } } + + return zIndex; } private void ThrowIfBusy() @@ -607,12 +662,25 @@ private static void ThrowIfInvalidControllerType(Type controllerType) throw new ArgumentException($"Cannot instantiate abstract type {controllerType.Name}.", nameof(controllerType)); } - if (!typeof(T).IsAssignableFrom(controllerType)) + if (!typeof(TController).IsAssignableFrom(controllerType)) { - throw new ArgumentException($"A view controller is expected to implement {typeof(T).Name}.", nameof(controllerType)); + throw new ArgumentException($"A view controller is expected to implement {typeof(TController).Name}.", nameof(controllerType)); } } +#if ENABLE_IL2CPP + + [Preserve] + private static void AotCodegenHelper() + { + // NOTE: This method is needed for AOT compiler to generate code for PresentResult<,> specializations. + // It should never be executed, it's just here to mark specific type arguments as used. + new PresentResult(null, null, typeof(TController), PresentOptions.None, PresentArgs.Default); + new PresentResult(null, null, typeof(TController), PresentOptions.None, PresentArgs.Default); + } + +#endif + #endregion } } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter{T}.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter{TController}.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Presenters/Presenter{T}.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Presenters/Presenter{TController}.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Core/UnityFx.Mvc.asmdef b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/UnityFx.Mvc.asmdef new file mode 100644 index 0000000..842ed23 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/UnityFx.Mvc.asmdef @@ -0,0 +1,14 @@ +{ + "name": "UnityFx.Mvc", + "references": [ + "UnityFx.Mvc.Abstractions" + ], + "optionalUnityReferences": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/UnityFx.Mvc.asmdef.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/UnityFx.Mvc.asmdef.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/UnityFx.Mvc.asmdef.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/UnityFx.Mvc.asmdef.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewCollection.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewCollection.cs new file mode 100644 index 0000000..5878717 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewCollection.cs @@ -0,0 +1,155 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using UnityEngine; +using UnityEngine.UI; + +namespace UnityFx.Mvc +{ + partial class UGUIViewFactory + { + #region interface + + public class ViewCollection : ICollection, IReadOnlyCollection + { + #region data + + private readonly UGUIViewFactory _factory; + + #endregion + + #region interface + + internal ViewCollection(UGUIViewFactory factory) + { + _factory = factory; + } + + public IView[] ToArray() + { + var result = new IView[Count]; + CopyTo(result, 0); + return result; + } + + #endregion + + #region ICollection + + public int Count + { + get + { + var viewRoots = _factory.ViewRoots; + + if (viewRoots != null) + { + var result = 0; + + foreach (var viewRoot in viewRoots) + { + result += viewRoot.childCount; + } + + return result; + } + + return 0; + } + } + + public bool IsReadOnly => true; + + public void Add(IView view) + { + throw new NotSupportedException(); + } + + public bool Remove(IView item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public bool Contains(IView view) + { + if (view != null) + { + var viewRoots = _factory.ViewRoots; + + if (viewRoots != null) + { + foreach (var viewRoot in viewRoots) + { + for (var i = 0; i < viewRoot.childCount; ++i) + { + var proxy = viewRoot.GetChild(i).GetComponent(); + + if (proxy && proxy.View == view) + { + return true; + } + } + } + } + } + + return false; + } + + public void CopyTo(IView[] array, int arrayIndex) + { + var viewRoots = _factory.ViewRoots; + + if (viewRoots != null) + { + foreach (var viewRoot in viewRoots) + { + for (var i = 0; i < viewRoot.childCount; ++i) + { + array[arrayIndex + i] = viewRoot.GetChild(i).GetComponent()?.View; + } + } + } + } + + #endregion + + #region IEnumerable + + public IEnumerator GetEnumerator() + { + var viewRoots = _factory.ViewRoots; + + if (viewRoots != null) + { + foreach (var viewRoot in viewRoots) + { + for (var i = 0; i < viewRoot.childCount; ++i) + { + var proxy = viewRoot.GetChild(i).GetComponent(); + yield return proxy?.View; + } + } + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + } + + #endregion + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewCollection.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewCollection.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewCollection.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewCollection.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewProxy.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewProxy.cs similarity index 52% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewProxy.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewProxy.cs index 3b82644..de768c1 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewProxy.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewProxy.cs @@ -1,23 +1,21 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; -using System.Collections.Generic; -using System.ComponentModel; using UnityEngine; using UnityEngine.UI; namespace UnityFx.Mvc { - partial class ViewFactory + partial class UGUIViewFactory { #region implementation - internal class ViewProxy : MonoBehaviour, ISite + internal class ViewProxy : MonoBehaviour { #region data - private IComponent _view; + private IView _view; #endregion @@ -27,17 +25,7 @@ internal class ViewProxy : MonoBehaviour, ISite public bool Exclusive { get; set; } public bool Modal { get; set; } - internal void DestroyInternal() - { - _view.Site = null; - Destroy(gameObject); - } - - #endregion - - #region ISite - - public IComponent Component + public IView View { get { @@ -49,14 +37,14 @@ public IComponent Component { if (_view != null) { - _view.Site?.Container?.Remove(_view); + _view.Disposed -= OnViewDisposed; } _view = value; if (_view != null) { - _view.Site = this; + _view.Disposed += OnViewDisposed; if (_view is MonoBehaviour b) { @@ -70,33 +58,30 @@ public IComponent Component } } - public IContainer Container { get; set; } - public bool DesignMode => false; - public string Name { get => name; set => name = value; } - #endregion - #region IServiceProvider + #region MonoBehaviour - public object GetService(Type serviceType) + private void OnDestroy() { - if (serviceType == typeof(ISite)) - { - return this; - } - - if (Container is IServiceProvider sp) + if (_view is MonoBehaviour b && b && b.gameObject) { - return sp.GetService(serviceType); + Destroy(b.gameObject); } - - return null; } - #endregion #region implementation + + private void OnViewDisposed(object sender, EventArgs args) + { + if (gameObject) + { + Destroy(gameObject); + } + } + #endregion } diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewProxy.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewProxy.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewProxy.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.ViewProxy.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.cs similarity index 59% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.cs rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.cs index 06c311d..10d3574 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.cs +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.cs @@ -1,9 +1,8 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; using System.Collections.Generic; -using System.ComponentModel; using System.Threading.Tasks; using UnityEngine; using UnityEngine.UI; @@ -13,58 +12,26 @@ namespace UnityFx.Mvc /// /// Default -based view factory. /// - public partial class ViewFactory : MonoBehaviour, IViewFactory, IContainer + public partial class UGUIViewFactory : MonoBehaviour, IViewFactory { #region data - [SerializeField] - private Transform _viewRootTransform; [SerializeField] private Color _popupBgColor = new Color(0, 0, 0, 0.5f); [SerializeField] + private Transform[] _viewRoots; + [SerializeField] private GameObject[] _viewPrefabs; private Dictionary _viewPrefabCache = new Dictionary(); private Dictionary> _viewPrefabCacheTasks = new Dictionary>(); private ViewCollection _views; - private ComponentCollection _components; private bool _disposed; #endregion #region interface - /// - /// Gets root transform for the created views. - /// - public Transform ViewRootTransform - { - get - { - if (_viewRootTransform is null) - { - _viewRootTransform = transform; - } - - return _viewRootTransform; - } - set - { - ThrowIfDisposed(); - - if (value is null) - { - value = transform; - } - - if (_viewRootTransform != value) - { - DestroyAllViews(); - _viewRootTransform = value; - } - } - } - /// /// Gets background color of the popup views. /// @@ -75,6 +42,11 @@ public Transform ViewRootTransform /// public GameObject[] ViewPrefabs { get => _viewPrefabs; set => _viewPrefabs = value; } + /// + /// Gets or sets list of preloaded view prefabs. + /// + public Transform[] ViewRoots { get => _viewRoots; set => _viewRoots = value; } + /// /// Gets a read-only collection of views. /// @@ -104,6 +76,19 @@ protected void ClearPrefabCache() _viewPrefabCache?.Clear(); } + /// + /// Gets root for a view of the specified controller. + /// + protected virtual Transform GetViewRoot(int layer) + { + if (_viewRoots is null || _viewRoots.Length == 0) + { + return transform; + } + + return _viewRoots[layer]; + } + /// /// Loads view prefab with the specified name. Default implementation searches the prefab in array, returns on any error. /// Overide to implement own mechanism of loading views. @@ -148,6 +133,22 @@ protected virtual void OnDispose() #region MonoBehaviour +#if UNITY_EDITOR + + protected virtual void Reset() + { + var cs = GetComponentsInChildren(); + + _viewRoots = new Transform[cs.Length]; + + for (var i = 0; i < cs.Length; i++) + { + _viewRoots[i] = cs[i].transform; + } + } + +#endif + private void OnDestroy() { Dispose(); @@ -157,41 +158,44 @@ private void OnDestroy() #region IViewFactory - public async Task CreateViewAsync(Type controllerType, int zIndex, PresentOptions options, Transform parent) + public async Task CreateAsync(string prefabPath, int layer, int zIndex, PresentOptions options, Transform parent) { ThrowIfDisposed(); - if (controllerType is null) + if (prefabPath is null) + { + throw new ArgumentNullException(nameof(prefabPath)); + } + + if (string.IsNullOrWhiteSpace(prefabPath)) { - throw new ArgumentNullException(nameof(controllerType)); + throw new ArgumentException("Invalid prefab name.", nameof(prefabPath)); } ViewProxy viewProxy = null; try { - var attrs = (ViewControllerAttribute[])controllerType.GetCustomAttributes(typeof(ViewControllerAttribute), false); - var attr = attrs != null && attrs.Length > 0 ? attrs[0] : null; var exclusive = (options & PresentOptions.Exclusive) != 0; var modal = (options & PresentOptions.Modal) != 0; - var prefabName = GetPrefabName(controllerType, attr); + var viewRoot = GetViewRoot(layer); - viewProxy = CreateViewProxy(prefabName, zIndex, exclusive, modal); + viewProxy = CreateViewProxy(viewRoot, prefabPath, zIndex, exclusive, modal); - if (_viewPrefabCache.TryGetValue(prefabName, out var viewPrefab)) + if (_viewPrefabCache.TryGetValue(prefabPath, out var viewPrefab)) { return CreateView(viewPrefab, viewProxy, parent); } else { - if (_viewPrefabCacheTasks.TryGetValue(prefabName, out var task)) + if (_viewPrefabCacheTasks.TryGetValue(prefabPath, out var task)) { viewPrefab = await task; } else { - task = LoadViewPrefabAsync(prefabName); - _viewPrefabCacheTasks.Add(prefabName, task); + task = LoadViewPrefabAsync(prefabPath); + _viewPrefabCacheTasks.Add(prefabPath, task); try { @@ -199,7 +203,7 @@ public async Task CreateViewAsync(Type controllerType, int zIndex, Presen } finally { - _viewPrefabCacheTasks.Remove(prefabName); + _viewPrefabCacheTasks.Remove(prefabPath); } } @@ -208,7 +212,7 @@ public async Task CreateViewAsync(Type controllerType, int zIndex, Presen throw new OperationCanceledException(); } - _viewPrefabCache.Add(prefabName, viewPrefab); + _viewPrefabCache.Add(prefabPath, viewPrefab); return CreateView(viewPrefab, viewProxy, parent); } } @@ -225,75 +229,6 @@ public async Task CreateViewAsync(Type controllerType, int zIndex, Presen #endregion - #region IContainer - - ComponentCollection IContainer.Components - { - get - { - ThrowIfDisposed(); - - if (_components is null) - { - _components = new ComponentCollection(Views.ToArray()); - } - - return _components; - } - } - - void IContainer.Add(IComponent component) - { - ThrowIfDisposed(); - - if (component is null) - { - throw new ArgumentNullException(nameof(component)); - } - - AddInternal(component, null); - } - - void IContainer.Add(IComponent component, string name) - { - ThrowIfDisposed(); - - if (component is null) - { - throw new ArgumentNullException(nameof(component)); - } - - AddInternal(component, name); - } - - void IContainer.Remove(IComponent component) - { - if (component != null && !_disposed) - { - _components = null; - - if (component.Site != null) - { - if (!ReferenceEquals(component.Site.Container, this)) - { - return; - } - - if (component.Site is ViewProxy p) - { - p.Container = null; - Destroy(p.gameObject); - } - - component.Site = null; - } - - UpdatePopupBackgrounds(); - } - } - - #endregion - #region IDisposable public void Dispose() @@ -301,10 +236,8 @@ public void Dispose() if (!_disposed) { _disposed = true; - _components = null; _viewPrefabCache = null; - DestroyAllViews(); OnDispose(); } } @@ -313,47 +246,6 @@ public void Dispose() #region implementation - private void AddInternal(IComponent component, string name) - { - Debug.Assert(component != null); - - var view = component as IView; - - if (view is null) - { - throw new ArgumentException("The component should implement IView.", nameof(component)); - } - - if (string.IsNullOrEmpty(name)) - { - name = "View"; - } - - var viewProxy = CreateViewProxy(name, ViewRootTransform.childCount, false, false); - viewProxy.Component = component; - } - - private string GetPrefabName(Type controllerType, ViewControllerAttribute attr) - { - Debug.Assert(controllerType != null); - - if (attr != null && !string.IsNullOrEmpty(attr.ViewPrefabName)) - { - return attr.ViewPrefabName; - } - else - { - var viewName = controllerType.Name; - - if (viewName.EndsWith("Controller")) - { - viewName = viewName.Substring(0, viewName.Length - 10); - } - - return viewName; - } - } - private IView CreateView(GameObject viewPrefab, ViewProxy viewProxy, Transform parent) { Debug.Assert(viewProxy); @@ -379,17 +271,16 @@ private IView CreateView(GameObject viewPrefab, ViewProxy viewProxy, Transform p go.transform.SetParent(parent ?? viewProxy.transform); } - viewProxy.Component = view; + viewProxy.View = view; return view; } - private ViewProxy CreateViewProxy(string viewName, int zIndex, bool exclusive, bool modal) + private ViewProxy CreateViewProxy(Transform viewRoot, string viewName, int zIndex, bool exclusive, bool modal) { Debug.Assert(viewName != null); var go = new GameObject(viewName); var viewProxy = go.AddComponent(); - var viewRoot = ViewRootTransform; go.transform.SetParent(viewRoot, false); @@ -427,8 +318,6 @@ private ViewProxy CreateViewProxy(string viewName, int zIndex, bool exclusive, b viewProxy.Modal = modal; viewProxy.Exclusive = exclusive; - viewProxy.Container = this; - viewProxy.Name = viewName; return viewProxy; } @@ -441,7 +330,7 @@ private void UpdatePopupBackgrounds() { var c = transform.GetChild(i).GetComponent(); - if (c && c.Container != null && c.Image) + if (c && c.Image) { if (modalFound) { @@ -456,24 +345,6 @@ private void UpdatePopupBackgrounds() } } - private void DestroyAllViews() - { - var viewRoot = ViewRootTransform; - - if (viewRoot) - { - for (var i = 0; i < viewRoot.childCount; ++i) - { - var p = viewRoot.GetChild(i).GetComponent(); - - if (p) - { - p.DestroyInternal(); - } - } - } - } - private void ThrowIfInvalidPrefab(GameObject prefabGo) { if (!prefabGo) diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Core/Views/UGUIViewFactory.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions.meta similarity index 77% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Extensions.meta index 0b85206..09963b4 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts.meta +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f701ab24a8e696e4f956087496491d01 +guid: 551014dd8977ac54485b2a7f110ae2f9 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/Common.meta similarity index 77% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/Common.meta index 79b0dba..67718ae 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts.meta +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/Common.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b66d996d796b11a4bbdbbb4657a7a51d +guid: cfd0cb4f615b54141869bc960c66ff69 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/Common/AssemblyInfo.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/Common/AssemblyInfo.cs new file mode 100644 index 0000000..4dcbdb2 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/Common/AssemblyInfo.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("UnityFx.Mvc.Extensions")] +[assembly: AssemblyDescription("MVC framework for Unity.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("UnityFx.Mvc")] +[assembly: AssemblyCopyright("Copyright © 2018-2020 Alexander Bogarsukov")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7263C628-4EFC-4841-AF29-E20A46EADABD")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +// Editor assembly should access core internals. +[assembly: InternalsVisibleTo("UnityFx.Mvc.Editor")] diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/Common/AssemblyInfo.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/Common/AssemblyInfo.cs.meta new file mode 100644 index 0000000..b9d4e3f --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/Common/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0437b05dc8b8354ab7c0bac04a3cd79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Attributes.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox.meta similarity index 77% rename from Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Attributes.meta rename to Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox.meta index feb6a5c..1e2ccba 100644 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Attributes.meta +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9f059ac5b3a67154c89aed670d71a0a3 +guid: af3cf08888b10f04094a6e8d6e732aa1 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxArgs.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxArgs.cs new file mode 100644 index 0000000..df55099 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxArgs.cs @@ -0,0 +1,70 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; + +namespace UnityFx.Mvc.Extensions +{ + /// + /// A present arguments. + /// + public class MessageBoxArgs : PresentArgs + { + /// + /// Gets message box title text. + /// + public string Title { get; } + + /// + /// Gets message box text. + /// + public string Text { get; } + + /// + /// Gets OK button text. + /// + public string OkText { get; } + + /// + /// Gets CANCEL button text. + /// + public string CancelText { get; } + + /// + /// Gets the message box options. + /// + public MessageBoxOptions Options { get; } + + /// + /// Initializes a new instance of the class. + /// + public MessageBoxArgs(MessageBoxOptions options, string text) + { + Text = text; + Options = options; + } + + /// + /// Initializes a new instance of the class. + /// + public MessageBoxArgs(MessageBoxOptions options, string text, string title) + { + Text = text; + Title = title; + Options = options; + } + + /// + /// Initializes a new instance of the class. + /// + public MessageBoxArgs(MessageBoxOptions options, string text, string title, string okText, string cancelText) + { + Text = text; + Title = title; + OkText = okText; + CancelText = cancelText; + Options = options; + } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxArgs.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxArgs.cs.meta new file mode 100644 index 0000000..7880452 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73f848c94918e9843aafc0606176b192 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxController.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxController.cs new file mode 100644 index 0000000..2acffc5 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxController.cs @@ -0,0 +1,96 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; + +namespace UnityFx.Mvc.Extensions +{ + /// + /// Controller of a generic message box. + /// + /// + /// + /// + /// + [ViewController(PresentOptions = PresentOptions.Popup | PresentOptions.Modal)] + public class MessageBoxController : IViewController, IViewControllerResult + { + #region data + + private readonly IPresentContext _context; + + #endregion + + #region interface + + /// + /// Enumerates controller-specific commands. + /// + public enum Commands + { + Ok, + Cancel, + Close + } + + /// + /// Initializes a new instance of the class. + /// + public MessageBoxController(IPresentContext context) + { + _context = context; + _context.View.Command += OnCommand; + + if (context.PresentArgs is MessageBoxArgs args && context.View is IConfigurable view) + { + view.Configure(args); + } + } + + #endregion + + #region IViewController + + /// + public IView View => _context.View; + + #endregion + + #region ICommandTarget + + /// + public bool InvokeCommand(TCommand command) + { + if (command != null && !_context.IsDismissed) + { + if (CommandUtilities.TryUnpack(command, out Commands cmd)) + { + if (cmd == Commands.Ok) + { + _context.Dismiss(MessageBoxResult.Ok); + } + else + { + _context.Dismiss(MessageBoxResult.Cancel); + } + + return true; + } + } + + return false; + } + + #endregion + + #region implementation + + private void OnCommand(object sender, CommandEventArgs e) + { + InvokeCommand(e); + } + + #endregion + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxController.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxController.cs.meta new file mode 100644 index 0000000..a659d4b --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 719bdbc427682774582089f4881bb1e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxExtensions.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxExtensions.cs new file mode 100644 index 0000000..471870e --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxExtensions.cs @@ -0,0 +1,65 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using System.ComponentModel; +using System.Threading.Tasks; +using UnityEngine; + +namespace UnityFx.Mvc.Extensions +{ + /// + /// Extensions for -related entities. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class MessageBoxExtensions + { + /// + /// Presents a message box with the specified . + /// + public static IPresentResult PresentMessageBox(this IPresenter presenter, MessageBoxOptions options, string text) + { + return (IPresentResult)presenter.Present(typeof(MessageBoxController), new MessageBoxArgs(options, text)); + } + + /// + /// Presents a message box with the specified . + /// + public static Task PresentMessageBoxAsync(this IPresenter presenter, MessageBoxOptions options, string text) + { + return ((IPresentResult)presenter.Present(typeof(MessageBoxController), new MessageBoxArgs(options, text))).Task; + } + + /// + /// Presents a message box with the specified and . + /// + public static IPresentResult PresentMessageBox(this IPresenter presenter, MessageBoxOptions options, string text, string title) + { + return (IPresentResult)presenter.Present(typeof(MessageBoxController), new MessageBoxArgs(options, text, title)); + } + + /// + /// Presents a message box with the specified and . + /// + public static Task PresentMessageBoxAsync(this IPresenter presenter, MessageBoxOptions options, string text, string title) + { + return ((IPresentResult)presenter.Present(typeof(MessageBoxController), new MessageBoxArgs(options, text, title))).Task; + } + + /// + /// Presents a message box with the specified and . + /// + public static IPresentResult PresentMessageBox(this IPresenter presenter, MessageBoxOptions options, string text, string title, string okText, string cancelText) + { + return (IPresentResult)presenter.Present(typeof(MessageBoxController), new MessageBoxArgs(options, text, title, okText, cancelText)); + } + + /// + /// Presents a message box with the specified and . + /// + public static Task PresentMessageBoxAsync(this IPresenter presenter, MessageBoxOptions options, string text, string title, string okText, string cancelText) + { + return ((IPresentResult)presenter.Present(typeof(MessageBoxController), new MessageBoxArgs(options, text, title, okText, cancelText))).Task; + } + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxExtensions.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxExtensions.cs.meta new file mode 100644 index 0000000..0a9255e --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 24c53ccb8953d2444bb509f85b485748 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxOptions.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxOptions.cs new file mode 100644 index 0000000..e0f19ea --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxOptions.cs @@ -0,0 +1,54 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc.Extensions +{ + /// + /// Enumerates results of a typical message box. + /// + [Flags] + public enum MessageBoxOptions + { + /// + /// No options. + /// + None = 0, + + /// + /// Message box with OK button. + /// + Ok = 1, + + /// + /// Message box with OK button. + /// + Cancel = 2, + + /// + /// Message box with OK and CANCEL buttons. + /// + OkCancel = Ok | Cancel, + + /// + /// Info box style. + /// + Info = 4, + + /// + /// Warning style. + /// + Warning = 8, + + /// + /// Error style. + /// + Error = 16, + + /// + /// Alert style. + /// + Alert = 32 + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxOptions.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxOptions.cs.meta new file mode 100644 index 0000000..6ffe59e --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxOptions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 760ade2ec2c657348aee9cf88014e11f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxResult.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxResult.cs new file mode 100644 index 0000000..d981378 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxResult.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; + +namespace UnityFx.Mvc.Extensions +{ + /// + /// Enumerates results of a typical message box. + /// + public enum MessageBoxResult + { + /// + /// OK button was pressed. + /// + Ok, + + /// + /// CANCEL or CLOSE button was pressed. + /// + Cancel + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxResult.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxResult.cs.meta new file mode 100644 index 0000000..1978077 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41c9397c5ef3c024a867fdadbf0226c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxView.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxView.cs new file mode 100644 index 0000000..0bff31b --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxView.cs @@ -0,0 +1,136 @@ +// Copyright (c) 2018-2020 Alexander Bogarsukov. +// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. + +using System; +using UnityEngine; +using UnityEngine.UI; + +namespace UnityFx.Mvc.Extensions +{ + /// + /// View for the . + /// + /// + public class MessageBoxView : View, IConfigurable + { + #region data + +#pragma warning disable 0649 + + [SerializeField] + private Text _title; + [SerializeField] + private Text _text; + [SerializeField] + private Text _okText; + [SerializeField] + private Button _okButton; + [SerializeField] + private Text _cancelText; + [SerializeField] + private Button _cancelButton; + [SerializeField] + private Button _closeButton; + +#pragma warning restore 0649 + + #endregion + + #region MonoBehaviour + + private void OnEnable() + { + if (_okButton) + { + _okButton.onClick.AddListener(OnOk); + } + + if (_cancelButton) + { + _cancelButton.onClick.AddListener(OnCancel); + } + + if (_closeButton) + { + _closeButton.onClick.AddListener(OnClose); + } + } + + private void OnDisable() + { + if (_okButton) + { + _okButton.onClick.RemoveListener(OnOk); + } + + if (_cancelButton) + { + _cancelButton.onClick.RemoveListener(OnCancel); + } + + if (_closeButton) + { + _closeButton.onClick.RemoveListener(OnClose); + } + } + + #endregion + + #region IConfigurable + + /// + public void Configure(MessageBoxArgs args) + { + if (_title) + { + _title.text = args.Title; + } + + if (_text) + { + _text.text = args.Text; + } + + if (_okText && !string.IsNullOrEmpty(args.OkText)) + { + _okText.text = args.OkText; + } + + if (_cancelText && !string.IsNullOrEmpty(args.CancelText)) + { + _cancelText.text = args.CancelText; + } + + if (_okButton) + { + _okButton.gameObject.SetActive((args.Options & MessageBoxOptions.Ok) != 0); + } + + if (_cancelButton) + { + _cancelButton.gameObject.SetActive((args.Options & MessageBoxOptions.Cancel) != 0); + } + } + + #endregion + + #region implementation + + private void OnOk() + { + NotifyCommand(MessageBoxController.Commands.Ok); + } + + private void OnCancel() + { + NotifyCommand(MessageBoxController.Commands.Cancel); + } + + private void OnClose() + { + NotifyCommand(MessageBoxController.Commands.Close); + } + + #endregion + } +} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxView.cs.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxView.cs.meta new file mode 100644 index 0000000..64282f1 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/MessageBox/MessageBoxView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e91b50bd57198944a85018b38baa4ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/UnityFx.Mvc.Extensions.asmdef b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/UnityFx.Mvc.Extensions.asmdef new file mode 100644 index 0000000..cabab03 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/UnityFx.Mvc.Extensions.asmdef @@ -0,0 +1,14 @@ +{ + "name": "UnityFx.Mvc.Extensions", + "references": [ + "UnityFx.Mvc.Abstractions" + ], + "optionalUnityReferences": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [] +} \ No newline at end of file diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/UnityFx.Mvc.Extensions.asmdef.meta b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/UnityFx.Mvc.Extensions.asmdef.meta new file mode 100644 index 0000000..26de2de --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Runtime/Extensions/UnityFx.Mvc.Extensions.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ce709374c15c52145a084653aacd8279 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/CommandEventArgs.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/CommandEventArgs.cs deleted file mode 100644 index a6f91c3..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Commands/CommandEventArgs.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Alexander Bogarsukov. -// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. - -using System; - -namespace UnityFx.Mvc -{ - /// - /// Event arguments for an arbitraty action. - /// - public class CommandEventArgs : EventArgs - { - /// - /// Gets the command name. - /// - public string CommandName { get; } - - /// - /// Gets the command arguments. - /// - public object CommandArguments { get; } - - /// - /// Initializes a new instance of the class. - /// - public CommandEventArgs(string commandName) - { - CommandName = commandName; - } - - /// - /// Initializes a new instance of the class. - /// - public CommandEventArgs(string commandName, object args) - { - CommandName = commandName; - CommandArguments = args; - } - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/ActivatorUtilities.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/ActivatorUtilities.cs deleted file mode 100644 index e43fe81..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Common/ActivatorUtilities.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) Alexander Bogarsukov. -// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. - -using System; -using System.Diagnostics; -using System.Globalization; -using System.Reflection; -using System.Runtime.ExceptionServices; - -namespace UnityFx.Mvc -{ - /// - /// Defines -related helpers. - /// - public static class ActivatorUtilities - { - #region interface - - /// - /// Creates an object of a specific type matching constructor arguments with values of and specified. - /// - /// A service provider used to match constructor arguments. - /// A type to instantiate. - /// An optional list of the constructor argument values. - /// Thrown if or is . - /// Thrown if the cannot be instantiated. - /// A instance created. - public static object CreateInstance(IServiceProvider serviceProvider, Type type, params object[] args) - { - if (serviceProvider == null) - { - throw new ArgumentNullException(nameof(serviceProvider)); - } - - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - try - { - var constructors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public); - - if (constructors.Length > 0) - { - // Select the first public non-static ctor with matching arguments. - foreach (var ctor in constructors) - { - if (TryGetMethodArguments(ctor, serviceProvider, args, out var argValues)) - { - return ctor.Invoke(argValues); - } - } - - throw new InvalidOperationException($"A suitable constructor for type '{type}' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor."); - } - else - { - return Activator.CreateInstance(type); - } - } - catch (TargetInvocationException e) - { -#if !NET35 - ExceptionDispatchInfo.Capture(e.InnerException).Throw(); -#endif - throw e.InnerException; - } - } - - #endregion - - #region implementation - - private static bool TryGetMethodArguments(MethodBase method, IServiceProvider serviceProvider, object[] args, out object[] argValues) - { - var argInfo = method.GetParameters(); - var argumentsValidated = true; - - argValues = new object[argInfo.Length]; - - for (var i = 0; i < argInfo.Length; ++i) - { - var argType = argInfo[i].ParameterType; - var argValue = default(object); - - // Try to match the argument using args first. - for (var j = 0; j < args.Length; ++j) - { - var arg = args[j]; - - if (arg != null && argType.IsAssignableFrom(arg.GetType())) - { - argValue = arg; - break; - } - } - - // If argument matching failed try to resolve the argument using serviceProvider. - if (argValue == null) - { - argValue = serviceProvider.GetService(argType); - } - - // If the argument is matched/resolved, store the value, otherwise fail the constructor validation. - if (argValue != null) - { - argValues[i] = argValue; - } - else - { - argumentsValidated = false; - break; - } - } - - // If all arguments matched/resolved, use this constructor for activation. - if (argumentsValidated) - { - return true; - } - - return false; - } - - #endregion - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerInfo.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerInfo.cs deleted file mode 100644 index 7bfa060..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Mvc/IViewControllerInfo.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Alexander Bogarsukov. -// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. - -using System; -using System.Net; - -namespace UnityFx.Mvc -{ - /// - /// Read-only view controller info. - /// - /// - public interface IViewControllerInfo - { - /// - /// Gets unique identifier of the controller. - /// - int Id { get; } - - /// - /// Gets the controller present arguments. - /// - PresentArgs PresentArgs { get; } - - /// - /// Gets the present flags used when instantiating the controller. - /// - PresentOptions PresentOptions { get; } - - /// - /// Gets time elapsed since the controller has been created (in seconds). - /// - float Timer { get; } - - /// - /// Gets a value indicating whether the controller is active. - /// - bool IsActive { get; } - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext.cs deleted file mode 100644 index 160aa7f..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentContext.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Alexander Bogarsukov. -// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. - -using System; -using System.Net; - -namespace UnityFx.Mvc -{ - /// - /// Context data for an instance. The class is a link between and its controllers. - /// It is here for the sake of testability/explicit dependencies for implementations. - /// - /// - public interface IPresentContext : IViewControllerInfo, IPresenter, IServiceProvider - { - /// - /// Gets the controller view. - /// - IView View { get; } - - /// - /// Gets a value indicating whether the controller is dismissed. - /// - /// - bool IsDismissed { get; } - - /// - /// Schedules a callback to be called in the specified . - /// - /// The callback to be called when the time is out. - /// Timeout value in seconds. - void Schedule(Action timerCallback, float timeout); - - /// - /// Dismisses the controller. - /// - /// - /// This call also dismisses all controllers presented by the owner. - /// - /// - void Dismiss(); - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult.cs deleted file mode 100644 index 0591082..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResult.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Alexander Bogarsukov. -// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. - -using System; -using System.ComponentModel; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -namespace UnityFx.Mvc -{ - /// - /// Result of a present operation. Can be used very much like . - /// - /// - /// - public interface IPresentResult : IViewControllerInfo, ICommandTarget, IDisposable - { - /// - /// Gets the view controller. - /// - /// - /// - IViewController Controller { get; } - - /// - /// Gets the view. - /// - IView View { get; } - - /// - /// Gets a instance that can be used to await the operation completion (i.e. until the is dismissed). - /// - Task DismissTask { get; } - - /// - /// Gets a instance that can be used to await the operation completion (i.e. until the is presented). - /// - Task PresentTask { get; } - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResultExtensions.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResultExtensions.cs deleted file mode 100644 index 0e96e20..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresentResultExtensions.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Alexander Bogarsukov. -// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. - -using System; -using System.ComponentModel; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using UnityEngine; - -namespace UnityFx.Mvc -{ - /// - /// Extensions of . - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public static class IPresentResultExtensions - { - public struct PresentResultAwaitable - { - private readonly IPresentResult _presentResult; - private readonly bool _awaitPresent; - - internal PresentResultAwaitable(IPresentResult presentResult, bool awaitPresent) - { - _presentResult = presentResult; - _awaitPresent = awaitPresent; - } - - public TaskAwaiter GetAwaiter() - { - if (_awaitPresent) - { - return _presentResult.PresentTask.GetAwaiter(); - } - else - { - return _presentResult.DismissTask.GetAwaiter(); - } - } - } - - /// - /// Gets an awaiter used to await this . - /// - public static PresentResultAwaitable ConfigureAwait(this IPresentResult presentResult, bool awaitPresent) - { - return new PresentResultAwaitable(presentResult, awaitPresent); - } - - /// - /// Gets an awaiter used to await this . - /// - public static TaskAwaiter GetAwaiter(this IPresentResult presentResult) - { - return presentResult.DismissTask.GetAwaiter(); - } - - /// - /// Gets an awaiter used to await this . - /// - public static TaskAwaiter GetAwaiter(this IPresentResult presentResult) where TController : IViewController - { - return presentResult.DismissTask.GetAwaiter(); - } - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenterExtensions.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenterExtensions.cs deleted file mode 100644 index c2af9d6..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Abstractions/Presenters/IPresenterExtensions.cs +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) Alexander Bogarsukov. -// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. - -using System; -using System.ComponentModel; -using UnityEngine; - -namespace UnityFx.Mvc -{ - /// - /// Extensions of interface. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public static class IPresenterExtensions - { - /// - /// Presents a controller of the specified type. - /// - /// The presenter. - /// Type of the view controller to present. - /// An object that can be used to track the operation progress. - /// Thrown if is . - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - /// - public static IPresentResult PresentAsync(this IPresenter presenter, Type controllerType) - { - return presenter.PresentAsync(controllerType, PresentOptions.None, null, null); - } - - /// - /// Presents a controller of the specified type. - /// - /// The presenter. - /// Type of the view controller to present. - /// Parent transform of the controller view. - /// An object that can be used to track the operation progress. - /// Thrown if is . - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - /// - public static IPresentResult PresentAsync(this IPresenter presenter, Type controllerType, Transform transform) - { - return presenter.PresentAsync(controllerType, PresentOptions.Popup, transform, null); - } - - /// - /// Presents a controller of the specified type. - /// - /// The presenter. - /// Type of the view controller to present. - /// Present options. - /// An object that can be used to track the operation progress. - /// Thrown if is . - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - /// - public static IPresentResult PresentAsync(this IPresenter presenter, Type controllerType, PresentOptions options) - { - return presenter.PresentAsync(controllerType, options, null, null); - } - - /// - /// Presents a controller of the specified type. - /// - /// The presenter. - /// Type of the view controller to present. - /// Present options. - /// Controller arguments. - /// An object that can be used to track the operation progress. - /// Thrown if is . - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - /// - public static IPresentResult PresentAsync(this IPresenter presenter, Type controllerType, PresentOptions options, PresentArgs args) - { - return presenter.PresentAsync(controllerType, options, null, args); - } - - /// - /// Presents a controller of the specified type. - /// - /// The presenter. - /// Type of the view controller to present. - /// Controller arguments. - /// An object that can be used to track the operation progress. - /// Thrown if is . - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - /// - public static IPresentResult PresentAsync(this IPresenter presenter, Type controllerType, PresentArgs args) - { - return presenter.PresentAsync(controllerType, PresentOptions.None, null, args); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// The presenter. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), PresentOptions.None, null, null); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// The presenter. - /// Parent transform of the controller view. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, Transform transform) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), PresentOptions.Popup, transform, null); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// The presenter. - /// Present options. - /// Parent transform of the controller view. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, PresentOptions options, Transform transform) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), options, transform, null); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// The presenter. - /// Controller arguments. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, PresentArgs args) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), PresentOptions.None, null, args); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// The presenter. - /// Present options. - /// Controller arguments. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, PresentOptions options, PresentArgs args) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), options, null, args); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// The presenter. - /// Parent transform of the controller view. - /// Controller arguments. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, Transform transform, PresentArgs args) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), PresentOptions.Popup, transform, args); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// The presenter. - /// Present options. - /// Parent transform of the controller view. - /// Controller arguments. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, PresentOptions options, Transform transform, PresentArgs args) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), options, transform, args); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// Type of the controller result value. - /// The presenter. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the does not match result type of the . - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), PresentOptions.None, null, null); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// Type of the controller result value. - /// The presenter. - /// Controller arguments. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the does not match result type of the . - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, PresentArgs args) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), PresentOptions.None, null, args); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// Type of the controller result value. - /// The presenter. - /// Parent transform of the controller view. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the does not match result type of the . - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, Transform transform) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), PresentOptions.Popup, transform, null); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// Type of the controller result value. - /// The presenter. - /// Present options. - /// Parent transform of the controller view. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the does not match result type of the . - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, PresentOptions options, Transform transform) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), options, transform, null); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// Type of the controller result value. - /// The presenter. - /// Parent transform of the controller view. - /// Controller arguments. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the does not match result type of the . - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, Transform transform, PresentArgs args) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), PresentOptions.Popup, transform, args); - } - - /// - /// Presents a controller of the specified type. - /// - /// Type of the controller to instantiate. - /// Type of the controller result value. - /// The presenter. - /// Present options. - /// Parent transform of the controller view. - /// Controller arguments. - /// An object that can be used to track the operation progress. - /// Thrown if cannot be used to instantiate the controller (for instance it is abstract type). - /// Thrown if the does not match result type of the . - /// Thrown if the presenter is disposed. - public static IPresentResult PresentAsync(this IPresenter presenter, PresentOptions options, Transform transform, PresentArgs args) where TController : IViewController - { - return (IPresentResult)presenter.PresentAsync(typeof(TController), options, transform, args); - } - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewControllerFactory.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewControllerFactory.cs deleted file mode 100644 index 7700f8c..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/ViewControllerFactory.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Alexander Bogarsukov. -// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. - -using System; -using System.ComponentModel; -using System.Diagnostics; - -namespace UnityFx.Mvc -{ - /// - /// Default implementation of . - /// - /// - public abstract class ViewControllerFactory : IViewControllerFactory - { - #region data - - private readonly IServiceProvider _serviceProvider; - - #endregion - - #region interface - - /// - /// Initializes a new instance of the class. - /// - /// The instance to use. - protected ViewControllerFactory(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); - } - - #endregion - - #region IViewControllerFactory - - /// - public virtual IDisposable CreateControllerScope(ref IServiceProvider serviceProvider) - { - return null; - } - - /// - public virtual IViewController CreateController(Type controllerType, params object[] args) - { - return (IViewController)ActivatorUtilities.CreateInstance(_serviceProvider, controllerType, args); - } - - #endregion - - #region implementation - #endregion - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewCollection.cs b/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewCollection.cs deleted file mode 100644 index 4999541..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/Scripts/Implementation/Views/ViewFactory.ViewCollection.cs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) Alexander Bogarsukov. -// Licensed under the MIT license. See the LICENSE.md file in the project root for more information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using UnityEngine; -using UnityEngine.UI; - -namespace UnityFx.Mvc -{ - partial class ViewFactory - { - #region interface - - public class ViewCollection : IList, IReadOnlyList - { - #region data - - private readonly ViewFactory _factory; - - #endregion - - #region interface - - internal ViewCollection(ViewFactory factory) - { - _factory = factory; - } - - public IView[] ToArray() - { - var viewRoot = _factory.ViewRootTransform; - var result = new IView[viewRoot.childCount]; - - for (var i = 0; i < result.Length; ++i) - { - result[i] = viewRoot.GetChild(i).GetComponent()?.Component as IView; - } - - return result; - } - - #endregion - - #region IList - - public IView this[int index] - { - get - { - var viewRoot = _factory.ViewRootTransform; - - if (index < 0 || index >= viewRoot.childCount) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - return viewRoot.GetChild(index).GetComponent()?.Component as IView; - } - set - { - throw new NotSupportedException(); - } - } - - public int IndexOf(IView view) - { - if (view != null) - { - var viewRoot = _factory.ViewRootTransform; - - for (var i = 0; i < viewRoot.childCount; ++i) - { - var proxy = viewRoot.GetChild(i).GetComponent(); - - if (proxy && proxy.Component == view) - { - return i; - } - } - } - - return -1; - } - - public void Insert(int index, IView item) - { - throw new NotSupportedException(); - } - - public void RemoveAt(int index) - { - throw new NotSupportedException(); - } - - #endregion - - #region ICollection - - public int Count => _factory.ViewRootTransform.childCount; - - public bool IsReadOnly => true; - - public void Add(IView view) - { - throw new NotSupportedException(); - } - - public bool Remove(IView item) - { - throw new NotSupportedException(); - } - - public void Clear() - { - throw new NotSupportedException(); - } - - public bool Contains(IView view) - { - if (view != null) - { - var viewRoot = _factory.ViewRootTransform; - - for (var i = 0; i < viewRoot.childCount; ++i) - { - var proxy = viewRoot.GetChild(i).GetComponent(); - - if (proxy && proxy.Component == view) - { - return true; - } - } - } - - return false; - } - - public void CopyTo(IView[] array, int arrayIndex) - { - var viewRoot = _factory.ViewRootTransform; - - for (var i = 0; i < viewRoot.childCount; ++i) - { - array[arrayIndex + i] = viewRoot.GetChild(i).GetComponent()?.Component as IView; - } - } - - #endregion - - #region IEnumerable - - public IEnumerator GetEnumerator() - { - var viewRoot = _factory.ViewRootTransform; - - for (var i = 0; i < viewRoot.childCount; ++i) - { - var proxy = viewRoot.GetChild(i).GetComponent(); - yield return proxy?.Component as IView; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - var viewRoot = _factory.ViewRootTransform; - - for (var i = 0; i < viewRoot.childCount; ++i) - { - var proxy = viewRoot.GetChild(i).GetComponent(); - yield return proxy?.Component; - } - } - - #endregion - } - - #endregion - } -} diff --git a/Assets/Plugins/UnityFx.Mvc/Runtime/UnityFx.Mvc.asmdef b/Assets/Plugins/UnityFx.Mvc/Runtime/UnityFx.Mvc.asmdef deleted file mode 100644 index a47822c..0000000 --- a/Assets/Plugins/UnityFx.Mvc/Runtime/UnityFx.Mvc.asmdef +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "UnityFx.Mvc" -} diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/AbstractController.cs b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/AbstractController.cs similarity index 70% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/AbstractController.cs rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/AbstractController.cs index aaa8db3..e2e3bd4 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/AbstractController.cs +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/AbstractController.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -9,7 +9,7 @@ public abstract class AbstractController : IViewController { public IView View => null; - public bool InvokeCommand(string commandName, object args) + public bool InvokeCommand(TCommand command) { return false; } diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/AbstractController.cs.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/AbstractController.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/AbstractController.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/AbstractController.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/InvalidController.cs b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/InvalidController.cs similarity index 77% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/InvalidController.cs rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/InvalidController.cs index 26b4de5..30bf5fd 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/InvalidController.cs +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/InvalidController.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/InvalidController.cs.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/InvalidController.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/InvalidController.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/InvalidController.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/MinimalController.cs b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/MinimalController.cs similarity index 74% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/MinimalController.cs rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/MinimalController.cs index 7e5c283..5e2fd8e 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/MinimalController.cs +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/MinimalController.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -14,7 +14,7 @@ public MinimalController(IView view) View = view; } - public bool InvokeCommand(string commandName, object args) + public bool InvokeCommand(TCommand command) { return false; } diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/MinimalController.cs.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/MinimalController.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/MinimalController.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/MinimalController.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/TimerController.cs b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/TimerController.cs similarity index 82% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/TimerController.cs rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/TimerController.cs index 978caba..c97d02a 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/TimerController.cs +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/TimerController.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -17,7 +17,7 @@ public TimerController(IPresentContext context) _context.Schedule(OnTimer, 0.1f); } - public bool InvokeCommand(string commandName, object args) + public bool InvokeCommand(TCommand command) { return false; } diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/TimerController.cs.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/TimerController.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Controllers/TimerController.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Controllers/TimerController.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultServiceProvider.cs b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultServiceProvider.cs similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultServiceProvider.cs rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultServiceProvider.cs diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultServiceProvider.cs.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultServiceProvider.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultServiceProvider.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultServiceProvider.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultView.cs b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultView.cs similarity index 92% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultView.cs rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultView.cs index 1a367fb..f5bec8c 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultView.cs +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultView.cs @@ -21,7 +21,7 @@ public class DefaultView : IView public void OnCommand() { - Command?.Invoke(this, new CommandEventArgs("Dummy")); + Command?.Invoke(this, new CommandEventArgs()); } public void Dispose() diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultView.cs.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultView.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultView.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultView.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultViewFactory.cs b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultViewFactory.cs similarity index 74% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultViewFactory.cs rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultViewFactory.cs index 8c8fabc..98563cf 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultViewFactory.cs +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultViewFactory.cs @@ -10,7 +10,7 @@ namespace UnityFx.Mvc { public class DefaultViewFactory : IViewFactory { - public async Task CreateViewAsync(Type controllerType, int zIndex, PresentOptions options, Transform parent) + public async Task CreateAsync(string prefabPath, int layer, int zIndex, PresentOptions options, Transform parent) { await Task.Delay(10); return new DefaultView(); diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultViewFactory.cs.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultViewFactory.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/Helpers/DefaultViewFactory.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Helpers/DefaultViewFactory.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests.meta new file mode 100644 index 0000000..9054e36 --- /dev/null +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ef594abf87a823949bc4f366b2b72ec3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/PresenterTests.cs b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/PresenterTests.cs similarity index 72% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/PresenterTests.cs rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/PresenterTests.cs index 455fbc5..05c8142 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/PresenterTests.cs +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/PresenterTests.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. +// Copyright (C) 2019 Alexander Bogarsukov. All rights reserved. // See the LICENSE.md file in the project root for more information. using System; @@ -27,7 +27,7 @@ public void Init() _go = new GameObject("PresenterTest"); _presenter = _go.AddComponent(); - _presenter.Initialize(_serviceProvider, _viewFactory); + _presenter.Initialize(_serviceProvider, _viewFactory, new ViewControllerFactory(_serviceProvider)); } [TearDown] @@ -46,20 +46,20 @@ public void InitialStateIsValid() [Test] public void Present_ThrownOnNullControllerType() { - Assert.Throws(() => _presenter.PresentAsync(null, PresentOptions.None, PresentArgs.Default)); + Assert.Throws(() => _presenter.Present(null)); } [Test] public void Present_ThrownOnInvalidControllerType() { - Assert.Throws(() => _presenter.PresentAsync(typeof(AbstractController), PresentOptions.None, PresentArgs.Default)); - Assert.Throws(() => _presenter.PresentAsync(typeof(InvalidController), PresentOptions.None, PresentArgs.Default)); + Assert.Throws(() => _presenter.Present(typeof(AbstractController))); + Assert.Throws(() => _presenter.Present(typeof(InvalidController))); } [Test] public void Present_PresentsMinimalController() { - var presentResult = _presenter.PresentAsync(); + var presentResult = _presenter.Present(); Assert.NotNull(presentResult); } @@ -67,7 +67,7 @@ public void Present_PresentsMinimalController() [Test] public void PresentResult_CanBeDisposedRightAfterCreation() { - _presenter.PresentAsync().Dispose(); + _presenter.Present().Dispose(); Assert.IsNull(_presenter.ActiveController); Assert.IsEmpty(_presenter.Controllers); diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/PresenterTests.cs.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/PresenterTests.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/PresenterTests.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/PresenterTests.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/ViewFactoryTests.cs b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/ViewFactoryTests.cs similarity index 76% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/ViewFactoryTests.cs rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/ViewFactoryTests.cs index ca7ba76..c81f824 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/ViewFactoryTests.cs +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/ViewFactoryTests.cs @@ -11,17 +11,17 @@ namespace UnityFx.Mvc { - [Category("ViewFactory"), TestOf(typeof(ViewFactory))] + [Category("ViewFactory"), TestOf(typeof(UGUIViewFactory))] public class ViewFactoryTests : IDisposable { private GameObject _go; - private ViewFactory _viewFactory; + private UGUIViewFactory _viewFactory; [SetUp] public void Init() { _go = new GameObject("ViewFactoryTest"); - _viewFactory = _go.AddComponent(); + _viewFactory = _go.AddComponent(); } [TearDown] @@ -35,7 +35,6 @@ public void InitialStateIsValid() { Assert.NotNull(_viewFactory.Views); Assert.IsEmpty(_viewFactory.Views); - Assert.AreEqual(_viewFactory.transform, _viewFactory.ViewRootTransform); } } } diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/ViewFactoryTests.cs.meta b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/ViewFactoryTests.cs.meta similarity index 100% rename from Assets/Plugins/UnityFx.Mvc/Tests/Editor/Scripts/ViewFactoryTests.cs.meta rename to Assets/Plugins/UnityFx.Mvc/Tests/Editor/Tests/ViewFactoryTests.cs.meta diff --git a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/UnityFx.Mvc.Editor.Tests.asmdef b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/UnityFx.Mvc.Editor.Tests.asmdef index 29c3a96..7991cbc 100644 --- a/Assets/Plugins/UnityFx.Mvc/Tests/Editor/UnityFx.Mvc.Editor.Tests.asmdef +++ b/Assets/Plugins/UnityFx.Mvc/Tests/Editor/UnityFx.Mvc.Editor.Tests.asmdef @@ -1,6 +1,7 @@ { "name": "UnityFx.Mvc.Editor.Tests", "references": [ + "UnityFx.Mvc.Abstractions", "UnityFx.Mvc" ], "optionalUnityReferences": [ diff --git a/Assets/Plugins/UnityFx.Mvc/package.json b/Assets/Plugins/UnityFx.Mvc/package.json index 7466b04..9fa9f6f 100644 --- a/Assets/Plugins/UnityFx.Mvc/package.json +++ b/Assets/Plugins/UnityFx.Mvc/package.json @@ -1,6 +1,6 @@ { "name": "com.unityfx.mvc", - "version": "0.1.0", + "version": "0.2.0", "displayName": "MVC framework for Unity.", "description": "", "unity": "2018.4", diff --git a/Assets/Scenes/Test.unity b/Assets/Scenes/Test.unity index 108d41e..5caf80c 100644 --- a/Assets/Scenes/Test.unity +++ b/Assets/Scenes/Test.unity @@ -173,11 +173,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: e3542ea2f6f679240b85aab9ae98b201, type: 3} m_Name: m_EditorClassIdentifier: - _viewRootTransform: {fileID: 1605007611} _popupBgColor: {r: 0, g: 0, b: 0, a: 0.5} + _viewRoots: + - {fileID: 1605007611} _viewPrefabs: - {fileID: 240879178860548289, guid: 3091374f3c0c527468342f660648e692, type: 3} - {fileID: 7846704816992948672, guid: 7fb867d34bbeca048a50534ffe67f80d, type: 3} + - {fileID: 2865599842196110682, guid: 03caa09d8ee99b241a82254be16bc57e, type: 3} --- !u!114 &1385712683 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/App/AppController.cs b/Assets/Scripts/App/AppController.cs index f304549..4798ce5 100644 --- a/Assets/Scripts/App/AppController.cs +++ b/Assets/Scripts/App/AppController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using UnityEngine; using UnityFx.Mvc; @@ -15,13 +15,6 @@ public class AppController : ViewController #region interface - /// - /// Controller-specific commands. - /// - public abstract new class Commands : ViewController.Commands - { - } - /// /// Initializes a new instance of the class. /// @@ -37,10 +30,9 @@ public AppController(IPresentContext context) #region ViewController /// - protected override bool OnCommand(string commandName, object commandArgs) + protected override bool OnCommand(TCommand command) { - // TODO: Process view commands here. See list of commands in Commands. - return false; + return base.OnCommand(command); } #endregion diff --git a/Assets/Scripts/AppRoot.cs b/Assets/Scripts/AppRoot.cs index 0d1f198..527d6bc 100644 --- a/Assets/Scripts/AppRoot.cs +++ b/Assets/Scripts/AppRoot.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; @@ -10,7 +10,7 @@ public class AppRoot : MonoBehaviour, IServiceProvider [SerializeField] private Presenter _presenter; [SerializeField] - private ViewFactory _viewFactory; + private UGUIViewFactory _viewFactory; private void Awake() { @@ -21,19 +21,21 @@ private void Awake() if (_viewFactory is null) { - _viewFactory = gameObject.AddComponent(); + _viewFactory = gameObject.AddComponent(); } - _presenter.Initialize(this, _viewFactory); + _presenter.Initialize(this); } private async void Start() { try { - await _presenter.PresentAsync().ConfigureAwait(true); + _ = _presenter.PresentAsync(); + await _presenter.PresentAsync(); - await _presenter.PresentAsync(); + + _ = _presenter.PresentAsync(); } catch (OperationCanceledException) { diff --git a/Assets/Scripts/Lobby/LobbyController.cs b/Assets/Scripts/Lobby/LobbyController.cs index f1d90c6..505c8af 100644 --- a/Assets/Scripts/Lobby/LobbyController.cs +++ b/Assets/Scripts/Lobby/LobbyController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using UnityEngine; using UnityFx.Mvc; @@ -15,13 +15,6 @@ public class LobbyController : ViewController #region interface - /// - /// Controller-specific commands. - /// - public abstract new class Commands : ViewController.Commands - { - } - /// /// Initializes a new instance of the class. /// @@ -37,10 +30,9 @@ public LobbyController(IPresentContext context) #region ViewController /// - protected override bool OnCommand(string commandName, object commandArgs) + protected override bool OnCommand(TCommand command) { - // TODO: Process view commands here. See list of commands in Commands. - return false; + return base.OnCommand(command); } #endregion diff --git a/Assets/Scripts/Splash/SplashController.cs b/Assets/Scripts/Splash/SplashController.cs index 8ad0fa4..3839f3f 100644 --- a/Assets/Scripts/Splash/SplashController.cs +++ b/Assets/Scripts/Splash/SplashController.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexander Bogarsukov. +// Copyright (c) 2018-2020 Alexander Bogarsukov. // Licensed under the MIT license. See the LICENSE.md file in the project root for more information. using System; diff --git a/CHANGELOG.md b/CHANGELOG.md index efcc5f7..d0ce834 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,28 @@ -# UnityFx.AppStates changelog +# UnityFx.Mvc changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/); this project adheres to [Semantic Versioning](http://semver.org/). +## [0.2.0] - 2020.01.05 + +### Added +- Added support for generic commands. +- Added view layers support (via `ViewControllerAttribute`). +- Added `IViewControllerResult` interface to tag controllers that have a result value. +- Added `IConfigurable` interfaces. +- Added message box extensions. + +### Changed +- Changed the package layout. The code is now splitted into 3 assemblies (`UnityFx.Mvc`, `UnityFx.Mvc.Abstractions` and `UnityFx.Mvc.Extensions`). +- Renamed `IPresenter.PresentAsync` to `Present`. Added a group of `PresentAsync` extension methods returning `Task` instead of `IPresentResult`. +- Renamed `IPresentResult.DismissTask` to `Task`. +- Changed `Present`/`PresentAsync` arguments. +- Changed `IViewFactory` and `IViewControllerFactory` interfaces. +- `IView` now does not inherit `IComponent`. + +### Removed +- Removed `IPresentResult.PresentTask`. + ## [0.1.0] - 2019.11.14 ### Added diff --git a/README.md b/README.md index bc8d4ff..e6f5126 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Channel | UnityFx.Mvc | ---------|---------------| Github | [![GitHub release](https://img.shields.io/github/release/Arvtesh/UnityFx.Mvc.svg?logo=github)](https://github.com/Arvtesh/UnityFx.Mvc/releases) -Unity Asset Store | [![MVC framework for Unity](https://img.shields.io/badge/tools-v0.1.0-green.svg)](https://assetstore.unity.com/packages/tools/TODO) +Unity Asset Store | [![MVC framework for Unity](https://img.shields.io/badge/tools-v0.2.0-green.svg)](https://assetstore.unity.com/packages/tools/TODO) Npm | [![Npm release](https://img.shields.io/npm/v/com.unityfx.mvc.svg)](https://www.npmjs.com/package/com.unityfx.mvc) ![npm](https://img.shields.io/npm/dt/com.unityfx.mvc) ## Synopsis @@ -39,19 +39,96 @@ Npm package is available at [npmjs.com](https://www.npmjs.com/package/com.unityf } ], "dependencies": { - "com.unityfx.mvc": "0.1.0" + "com.unityfx.mvc": "0.2.0" } } ``` +## Understanding the concepts +As outlined in [ASP.NET Core documentation](https://docs.microsoft.com/en-us/aspnet/core/mvc/overview), the Model-View-Controller (MVC) architectural pattern separates an application into three main groups of components: Models, Views, and Controllers. This pattern helps to achieve separation of concerns. Using this pattern, user requests are routed to a Controller which is responsible for working with the Model to perform user actions and/or retrieve results of queries. The Controller chooses the View to display to the user, and provides it with any Model data it requires. + +This delineation of responsibilities helps you scale the application in terms of complexity because it's easier to code, debug, and test something (model, view, or controller) that has a single job. It's more difficult to update, test, and debug code that has dependencies spread across two or more of these three areas. For example, user interface logic tends to change more frequently than business logic. If presentation code and business logic are combined in a single object, an object containing business logic must be modified every time the user interface is changed. This often introduces errors and requires the retesting of business logic after every minimal user interface change. + +Both the view and the controller depend on the model. However, the model depends on neither the view nor the controller. This is one of the key benefits of the separation. This separation allows the model to be built and tested independent of the visual presentation. + +In the same way that MVC takes the position that you should separate model logic from view and controller logic, MVCS takes this notion a step further by advocating for application logic to live in the services. This is the recommended way of sharing pieces of logic between controllers. + +### Model +The Model in an MVC application represents the state of the application and any business logic or operations that should be performed by it. Business logic should be encapsulated in the model, along with any implementation logic for persisting the state of the application. + +### View +Views are responsible for presenting content through the user interface. There should be minimal logic within views, and any logic in them should relate to presenting content. + +### Controller +Controllers are the components that handle user interaction, work with the model. In an MVC application, the view only displays information; the controller handles and responds to user input and interaction. + +### Service +Services usually contian very specialized logic, that is shared between several controllers. Services may on may not depend on Model. Neither model not views should depend on services. Examples of services: `IFileSystem`, `IAssetFactory`, `IAudioService`. + ## Usage Install the package and import the namespace: ```csharp using UnityFx.Mvc; +using UnityFx.Mvc.Extensions; ``` -## Understanding the concepts -TODO +### Presenters +A presenter is an object capable of presenting view controllers. It should implement `IPresenter` interface. There are `MonoBehaviour`-based presenter implementations `Presenter` and `Presenter`. A typical scenario of presenter usage is: +```csharp +presenter.Present(); +``` +The following code presents a message box and awaits its result: +```csharp +var result = await presenter.PresentAsync(); +``` +There are a lot of overloads of the `Present` method accepting additional arguments. In any case it needs a controller type specified to do the work. + +Presenter uses `IServiceProvider` instance to resolve controller dependencies. It also requires `IViewFactory` to create views for the controllers presented. + +### Controllers + +Controller is any class that implements `IViewController` interface. There are several default controller implementations, like `ViewController` and `ViewController`. In most cases users should inherit new controllers from one of these. A controller constructor usually accepts at least an argument of type `IPresentContext`, which provides access to the its context (including the view). + +```csharp +public class SplashController : ViewController +{ + public SplashController(IPresentContext context) + : base(context) + { + context.Schedule(OnTimer, 5); + } + + private void OnTimer(float t) + { + Dismiss(); + } +} +``` + +### Views + +View is a class that implements `IView` interface. There is a default `MonoBehaviour`-based view implementation (`View`). It is recommended to inherit user views from this class. View is supposed to manage presentation-related logic, and send user input to its controller. Please note, that there is no explicit reference to the controller. The preffered way of sending controller notifications is calling one of `NotifyCommand` overloads (which in turn raises `INotifyCommand.Command` event). + +```csharp +public class MinimalView : View +{ + [SerializeField] + private Button _closeButton; + + public void Configure(MinimalViewArgs args) + { + _closeButton.onClick.AddListener(OnCLose); + } + + private OnClose() + { + NotifyCommand("close"); + } +} +``` + +### Dependency injection +*UnityFx.Mvc* controllers request dependencies explicitly via constructors. The framework has built-in support for dependency injection (DI). DI makes apps easier to test and maintain. Services are added as a constructor parameter, and the runtime resolves the service from the service container (via `IServiceProvider`). Services are typically defined using interfaces. ## Motivation The project was initially created to help author with his [Unity3d](https://unity3d.com) projects. Client .NET applications in general (and Unity applications specifically) do not have a standard structure or any kind of architecturing guidelines (like ASP.NET). This is an attempt to create a small yet effective and usable application framework suitable for Unity projects. @@ -63,6 +140,13 @@ Please see the links below for extended information on the product: - [SUPPORT](.github/SUPPORT.md). ## Useful links +- [MVC in Wikipedia](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller). +- [MVC in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/mvc/overview). +- [Dependency injection in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection). +- [Routing in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing). +- [Architectural pronciples in ASP.NET Core](https://docs.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles). +- [Deeplinking in Wikipedia](https://en.wikipedia.org/wiki/Deep_linking). +- [Deeplinking basics](https://www.appsflyer.com/resources/everything-marketer-needs-to-know-deep-linking/deep-linking-basics/). ## Software requirements - [Microsoft Visual Studio](https://www.visualstudio.com/vs/community/)