├── .gitignore
├── LICENSE
├── LICENSE.meta
├── README.md
├── README.md.meta
├── README_RU.md
├── README_RU.md.meta
├── Scripts.meta
├── Scripts
├── Editor.meta
├── Editor
│ ├── Laphed.UIFramework.UnityBridge.Editor.asmdef
│ ├── Laphed.UIFramework.UnityBridge.Editor.asmdef.meta
│ ├── WindowCustomInspector.cs
│ └── WindowCustomInspector.cs.meta
├── Runtime.meta
└── Runtime
│ ├── MVP.meta
│ ├── MVP
│ ├── CollectionPresenter.cs
│ ├── CollectionPresenter.cs.meta
│ ├── DictionaryPresenter.cs
│ ├── DictionaryPresenter.cs.meta
│ ├── IPresenter.cs
│ ├── IPresenter.cs.meta
│ ├── IView.cs
│ ├── IView.cs.meta
│ ├── Laphed.MVP.asmdef
│ ├── Laphed.MVP.asmdef.meta
│ ├── MonoBehaviourViews.meta
│ ├── MonoBehaviourViews
│ │ ├── MonoSpriteView.cs
│ │ ├── MonoSpriteView.cs.meta
│ │ ├── MonoTextView.cs
│ │ ├── MonoTextView.cs.meta
│ │ ├── MonoView.cs
│ │ └── MonoView.cs.meta
│ ├── PresenterBase.cs
│ ├── PresenterBase.cs.meta
│ ├── PropertyPresenter.cs
│ ├── PropertyPresenter.cs.meta
│ ├── ReactivePresenterBase.cs
│ └── ReactivePresenterBase.cs.meta
│ ├── UIFramework.meta
│ └── UIFramework
│ ├── IUiBinder.cs
│ ├── IUiBinder.cs.meta
│ ├── IWindow.cs
│ ├── IWindow.cs.meta
│ ├── Laphed.UIFramework.asmdef
│ ├── Laphed.UIFramework.asmdef.meta
│ ├── UiBinder.cs
│ ├── UiBinder.cs.meta
│ ├── UnityMonoBridge.meta
│ ├── UnityMonoBridge
│ ├── MonoBinder.cs
│ ├── MonoBinder.cs.meta
│ ├── MonoWindow.cs
│ └── MonoWindow.cs.meta
│ ├── Window.cs
│ └── Window.cs.meta
├── package.json
└── package.json.meta
/.gitignore:
--------------------------------------------------------------------------------
1 | # This .gitignore file should be placed at the root of your Unity project directory
2 | #
3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
4 | #
5 | /[Ll]ibrary/
6 | /ios/
7 | /[Tt]emp/
8 | /[Oo]bj/
9 | /[Bb]uild/
10 | /[Bb]uilds/
11 | /[Ll]ogs/
12 | /[Uu]ser[Ss]ettings/
13 | /[Rr]ecordings
14 |
15 | # MemoryCaptures can get excessive in size.
16 | # They also could contain extremely sensitive data
17 | /[Mm]emoryCaptures/
18 |
19 | # Asset meta data should only be ignored when the corresponding asset is also ignored
20 | !/[Aa]ssets/**/*.meta
21 |
22 | # Uncomment this line if you wish to ignore the asset store tools plugin
23 | # /[Aa]ssets/AssetStoreTools*
24 |
25 | # Autogenerated Jetbrains Rider plugin
26 | /[Aa]ssets/Plugins/Editor/JetBrains*
27 |
28 | # Visual Studio cache directory
29 | .vs/
30 | .idea
31 | .git
32 |
33 | # Gradle cache directory
34 | .gradle/
35 |
36 | # Autogenerated VS/MD/Consulo solution and project files
37 | ExportedObj/
38 | .consulo/
39 | *.csproj
40 | *.unityproj
41 | *.sln
42 | *.suo
43 | *.tmp
44 | *.user
45 | *.userprefs
46 | *.pidb
47 | *.booproj
48 | *.svd
49 | *.pdb
50 | *.mdb
51 | *.opendb
52 | *.VC.db
53 |
54 | # Unity3D generated meta files
55 | *.pidb.meta
56 | *.pdb.meta
57 | *.mdb.meta
58 |
59 | # Unity3D generated file on crash reports
60 | sysinfo.txt
61 |
62 | # Builds
63 | *.apk
64 | *.unitypackage
65 | /[Aa]ssets/[Ss]treaming[Aa]ssets/build_inf*
66 |
67 | # Crashlytics generated file
68 | crashlytics-build.properties
69 |
70 | # Packed Addressables
71 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
72 |
73 | # Temporary auto-generated Android Assets
74 | /[Aa]ssets/[Ss]treamingAssets/aa.meta
75 | /[Aa]ssets/[Ss]treamingAssets/aa/*
76 |
77 | # Exceptions
78 | !*.dll
79 | !*.obj
80 |
81 | #Other files
82 | /[Aa]ssets/[Ss]cenes/currentScenePath*
83 |
84 | #Mac metafiles
85 | ._*
86 | Assets/Plugins/Zenject/Source/Zenject.csproj.meta
87 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Alexander Gavrilushkin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9e1a3d49c37f6914da7931c168e872a2
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UI Framework
2 | [Документация на русском языке](https://github.com/laphedhendad/UI-Framework/blob/main/README_RU.md)
3 |
4 |
5 | UI Framework for Unity based on reactivity and Model-View-Presenter pattern.
6 |
7 | ## Table of Contents
8 |
9 | - [Installation](#installation)
10 | - [Reactivity](#reactivity)
11 | - [Model-View-Presenter](#model-view-presenter)
12 | - [Model](#model)
13 | - [View](#view)
14 | - [Presenter](#presenter)
15 | - [Simple Presenter](#simple-presenter)
16 | - [UI Architecture](#ui-architecture)
17 | - [Example Project](#example-project)
18 |
19 | # Installation
20 |
21 | $${\color{orange}IMPORTANT!}$$
22 |
23 | The framework depends on the custom [lightweight reactivity package](https://github.com/laphedhendad/Lightweight-Reactivity). You need to install this before installing the UI Framework.
24 |
25 |
26 | * Via .unitypackage file:
27 |
28 | Download package from [releases page](https://github.com/laphedhendad/UI-Framework/releases).
29 | Add to project with Assets/Import Package/Custom Package...
30 |
31 | * Via git URL:
32 |
33 | Open Window/Package Manager and choose +/Add package from git URL...
34 |
35 | Set `https://github.com/laphedhendad/UI-Framework.git` as URL.
36 |
37 | If you want to set a target version, UI Framework uses the \*.\*.\* release tag so you can specify a version like #1.0.0. For example `https://github.com/laphedhendad/UI-Framework.git#1.0.0`.
38 |
39 | # Reactivity
40 |
41 | The interaction between interface and data is built on a reactive approach. The package implements reactive property, collection and dictionary. They are lightweight versions of the corresponding classes from the [UniRx](https://github.com/neuecc/UniRx) plugin.
42 |
43 | ## ReactiveProperty
44 |
45 | Reactive Property - a simple wrapper around data types. Triggers the OnChanged event when its value changes.
46 |
47 | ```csharp
48 | public class ReactiveProperty: IReactiveProperty
49 | {
50 | public event Action OnChanged;
51 | private T currentValue;
52 |
53 | public T Value
54 | {
55 | get => currentValue;
56 | set
57 | {
58 | if (EqualityComparer.Default.Equals(value, currentValue)) return;
59 | currentValue = value;
60 | OnChanged?.Invoke();
61 | }
62 | }
63 | }
64 | ```
65 |
66 | ## ReactiveCollection
67 |
68 | Reactive Collection - a wrapper around a type [Collection](https://learn.microsoft.com/ru-ru/dotnet/api/system.collections.objectmodel.collection-1). Triggers events:
69 |
70 | * OnChanged
71 | * OnAdd
72 | * OnRemove
73 | * OnReplace
74 | * OnCleared
75 |
76 | The events pass the index of the changed element as parameters.
77 |
78 | ## ReactiveDictionary
79 |
80 | Reactive Dictionary - a wrapper around a type [Dictionary](https://learn.microsoft.com/ru-ru/dotnet/api/system.collections.generic.dictionary-2). Triggers events:
81 |
82 | * OnChanged
83 | * OnAdd
84 | * OnRemove
85 | * OnReplace
86 | * OnCleared
87 |
88 | The events pass the key of the changed element as parameters.
89 |
90 | ## Example
91 |
92 | ```csharp
93 | //booster class with reactive property
94 | public class Booster: IBooster
95 | {
96 | public IReactiveProperty Amount { get; } = new ReactiveProperty();
97 | }
98 |
99 | ...
100 |
101 | //subscribing to a reactive property
102 | public override void SubscribeModel(TReactive model)
103 | {
104 | if (model == null) return;
105 | this.model = model;
106 | model.OnChanged += HandleModelUpdate;
107 | }
108 |
109 | ...
110 |
111 | //changing value of a reactive property
112 | private void BuyBooster()
113 | {
114 | booster.Amount.Value++;
115 | }
116 | ```
117 |
118 | # Model-View-Presenter
119 |
120 | The MVP pattern involves breaking the connection between Model and View with the help of an additional Presenter class.
121 |
122 | Presenter:
123 | * Subscribes to model events and can directly modify data
124 | * Holds a reference to View and updates it through the interface
125 | * Subscribes to View events and processes them
126 | * Has the same lifetime as View and is associated with only one view
127 |
128 | 
129 |
130 | ## Model
131 |
132 | Reactive property/collection/dictionary acts as the model. View implements the IView interface:
133 |
134 | ```csharp
135 | public interface IView
136 | {
137 | event Action OnDispose;
138 | void UpdateView(T value);
139 | }
140 | ```
141 |
142 | ## View
143 |
144 | For MonoBehaviour views in the package, there is an abstract class MonoView and its descendants for specific data types:
145 |
146 | ```csharp
147 | //base class for MonoBehaviour Views
148 | public abstract class MonoView: MonoBehaviour, IView
149 | {
150 | public event Action OnDispose;
151 | public abstract void UpdateView(T value);
152 | protected virtual void OnDestroy() => OnDispose?.Invoke();
153 | }
154 |
155 | //MonoView for concrete data type
156 | public abstract class MonoTextView: MonoView
157 | {
158 | protected abstract string Text { set; }
159 | public override void UpdateView(string value) => Text = value;
160 | }
161 |
162 | //concrete View realization
163 | public class SpeakerNameView : MonoTextView
164 | {
165 | [SerializeField] private TMP_Text speakerNameText;
166 | protected override string Text
167 | {
168 | set => speakerNameText.text = value;
169 | }
170 | }
171 | ```
172 |
173 | You can create MonoView for your own data types. Existing solutions in the package cover only the most common types.
174 |
175 | ## Presenter
176 |
177 | Presenter implements the IPresenter interface:
178 |
179 | ```csharp
180 | public interface IPresenter: IDisposable
181 | {
182 | void SubscribeModel(TModel model);
183 | }
184 | ```
185 |
186 | Interaction with different reactive models involves using the corresponding presenter. The package includes:
187 |
188 | * PropertryPresenter for properties
189 | * CollectionPresenter for collections
190 | * DictionaryPresenter for dictionaries
191 |
192 | For each of the above classes, there is a paired class for situations where type conversion is not required for display.
193 |
194 | * PropertyPresenter
195 | * CollectionPresenter
196 | * DictionaryPresenter
197 |
198 | Creating your own Presenter involves inheriting from these six classes and overriding the SubscribeModel and HandleModelUpdate methods if necessary.
199 |
200 | ```csharp
201 | //example presenter for displaying the number of boosters and
202 | //handling the booster button click
203 | public class BoosterPresenter: PropertyPresenter
204 | {
205 | //specify data type of the View to
206 | //handle user input events
207 | private new readonly BoosterButton view;
208 |
209 | private readonly ModalWindowView buyBoosterWindow;
210 |
211 | public BoosterPresenter(BoosterButton view, ModalWindowView buyBoosterWindow) : base(view)
212 | {
213 | this.view = view;
214 | this.buyBoosterWindow = buyBoosterWindow;
215 | this.view.OnClicked += HandleClick;
216 | }
217 |
218 | private void HandleClick()
219 | {
220 | if (model == null) return;
221 | if (model.Value == 0)
222 | {
223 | buyBoosterWindow.Open();
224 | return;
225 | }
226 | model.Value--;
227 | }
228 |
229 | public override void Dispose()
230 | {
231 | view.OnClicked -= HandleClick;
232 | base.Dispose();
233 | }
234 | }
235 |
236 | ...
237 |
238 | //subscribing Presenter to Model
239 | public override void Bind()
240 | {
241 | boosterPresenter = new BoosterPresenter(boosterButton, buyBoosterWindow);
242 | boosterPresenter.SubscribeModel(booster.Amount);
243 | }
244 | ```
245 |
246 | ## Simple Presenter
247 |
248 | There are situations where the presentation only needs to display the model's value without extra logic. In such cases, instances of PropertyPresenter, CollectionPresenter, DictionaryPresenter are created.
249 |
250 | ```csharp
251 | public void Bind()
252 | {
253 | //creating of PropertyPresenter instance
254 | var speakerNamePresenter = new PropertyPresenter(speakerNameView);
255 |
256 | //subscribing Presenter to Model
257 | speakerNamePresenter.SubscribeModel(reactivePassage.SpeakerName);
258 | }
259 | ```
260 |
261 | # UI Architecture
262 |
263 | The entire UI in the package is divided into Windows and elements. A Window is a container for elements, including nested windows. A Window can refer to either the entire application screen or a separate modal window. Windows have only two responsibilities: determining the order of binder initialization (see below) and invoking resource cleanup upon destruction.
264 |
265 | The UI is connected to the rest of the application code through binders. References to components are passed to the binder, and their interaction with child UI elements is described. Each window should have its corresponding binder, and a binder can reference elements from windows located hierarchically at any position relative to its window.
266 |
267 | Creating a window involves creating a GameObject with the MonoWindow component and a specific implementation of MonoBinder.
268 |
269 | 
270 |
271 | References to its child windows are passed to the MonoWindow component. Doing this manually is not mandatory. It is sufficient to press the "Find subwindows automatically" button on the root MonoWindow component before testing the application. All windows in the hierarchy will automatically set references to their child windows.
272 |
273 | ```csharp
274 | //example of Binder realization for booster activating window
275 | public class BoostersBinder : MonoBinder
276 | {
277 | [SerializeField] private BoosterButton boosterButton;
278 | [SerializeField] private ModalWindowView buyBoosterWindow;
279 |
280 | private IBooster booster;
281 | private BoosterPresenter boosterPresenter;
282 |
283 | [Inject]
284 | private void Construct(IBooster booster)
285 | {
286 | this.booster = booster;
287 | }
288 |
289 | public override void Bind()
290 | {
291 | boosterPresenter = new BoosterPresenter(boosterButton, buyBoosterWindow);
292 | boosterPresenter.SubscribeModel(booster.Amount);
293 | }
294 |
295 | protected override void Unbind()
296 | {
297 | boosterPresenter?.Dispose();
298 | }
299 | }
300 | ```
301 |
302 | # Example Project
303 |
304 | [The example project](https://github.com/laphedhendad/UI-Framework-Example) can be downloaded as an archive from GitHub. The project uses [Zenject](https://github.com/modesttree/Zenject) and [UniTask](https://github.com/Cysharp/UniTask) in a relatively small amount to not distract attention from the package.
305 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f61b6ad80009cdf4b9f166f826227b2d
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/README_RU.md:
--------------------------------------------------------------------------------
1 | # UI Framework
2 |
3 | Фреймворк для создания гибкого интерфейса на движке Unity, основанный на реактивности и паттерне Model-View-Presenter.
4 |
5 | ## Содержание
6 |
7 | - [Установка](#установка)
8 | - [Реактивность](#реактивность)
9 | - [Model-View-Presenter](#model-view-presenter)
10 | - [Model](#model)
11 | - [View](#view)
12 | - [Presenter](#presenter)
13 | - [Простой Presenter](#простой-presenter)
14 | - [Архитектура UI](#архитектура-ui)
15 | - [Обучающий проект](#обучающий-проект)
16 |
17 | # Установка
18 |
19 | $${\color{orange}ВАЖНО!}$$
20 |
21 | Фреймворк использует в качестве зависимости другой пакет [Lightweight Reactivity Package](https://github.com/laphedhendad/Lightweight-Reactivity). Установите его перед установкой UI Framework.
22 |
23 |
24 | * Через .unitypackage файл:
25 |
26 | Скачайте пакет со [страницы релизов](https://github.com/laphedhendad/UI-Framework/releases).
27 | Добавьте его в свой проект с помощью Assets/Import Package/Custom Package...
28 | * Через ссылку на git:
29 |
30 | Откройте Window/Package Manager, выберите +/Add package from git URL...
31 |
32 | Укажите ссылку на пакет: `https://github.com/laphedhendad/UI-Framework.git`
33 |
34 | Можно выбрать конкретную версию пакета, указав её в ссылке: `https://github.com/laphedhendad/UI-Framework.git#1.0.0`
35 |
36 | # Реактивность
37 |
38 | Взаимодействие интерфейса и данных построено на реактивном подходе. В пакете реализовано реактивное свойство, коллекция и словарь. Они представляют собой облегченные версии соответствующих классов из плагина [UniRx](https://github.com/neuecc/UniRx).
39 |
40 | ## ReactiveProperty
41 |
42 | Реактивное свойство - простая обертка над типами данных. Вызывает событие OnChanged, когда меняется его значение.
43 |
44 | ```csharp
45 | public class ReactiveProperty: IReactiveProperty
46 | {
47 | public event Action OnChanged;
48 | private T currentValue;
49 |
50 | public T Value
51 | {
52 | get => currentValue;
53 | set
54 | {
55 | if (EqualityComparer.Default.Equals(value, currentValue)) return;
56 | currentValue = value;
57 | OnChanged?.Invoke();
58 | }
59 | }
60 | }
61 | ```
62 |
63 | ## ReactiveCollection
64 |
65 | Реактивная коллекция - обертка над типом [Collection](https://learn.microsoft.com/ru-ru/dotnet/api/system.collections.objectmodel.collection-1). Вызывает события:
66 |
67 | * OnChanged
68 | * OnAdd
69 | * OnRemove
70 | * OnReplace
71 | * OnCleared
72 |
73 | В параметрах событий передает индекс элемента, подвергшегося изменениям.
74 |
75 | ## ReactiveDictionary
76 |
77 | Реактивный словарь - обертка над типом [Dictionary](https://learn.microsoft.com/ru-ru/dotnet/api/system.collections.generic.dictionary-2). Вызывает события:
78 |
79 | * OnChanged
80 | * OnAdd
81 | * OnRemove
82 | * OnReplace
83 | * OnCleared
84 |
85 | В параметрах событий передает ключ элемента, подвергшегося изменениям.
86 |
87 | ## Пример использования
88 |
89 | ```csharp
90 | //класс бустера с реактивным свойством
91 | public class Booster: IBooster
92 | {
93 | public IReactiveProperty Amount { get; } = new ReactiveProperty();
94 | }
95 |
96 | ...
97 |
98 | //подписка на реактивное свойство
99 | public override void SubscribeModel(TReactive model)
100 | {
101 | if (model == null) return;
102 | this.model = model;
103 | model.OnChanged += HandleModelUpdate;
104 | }
105 |
106 | ...
107 |
108 | //изменение значения реактивного свойства
109 | private void BuyBooster()
110 | {
111 | booster.Amount.Value++;
112 | }
113 | ```
114 |
115 | # Model-View-Presenter
116 |
117 | Паттерн MVP предполагает разбитие связи между Model(модель данных) и View(отображение) с помощью дополнительного класса Presenter(представитель).
118 |
119 | Presenter:
120 | * Подписывается на события модели и может напрямую менять данные
121 | * Хранит ссылку на View и обновляет его через интерфейс
122 | * Подписывается на события View и обрабатывает их
123 | * Имеет одинаковое с View время жизни и связан только с одним отображением
124 |
125 | 
126 |
127 | ## Model
128 |
129 | В роли модели выступает реактивное свойство/коллекция/словарь. View реализует интерфейс IView:
130 |
131 | ```csharp
132 | public interface IView
133 | {
134 | event Action OnDispose;
135 | void UpdateView(T value);
136 | }
137 | ```
138 |
139 | ## View
140 |
141 | Для MonoBehaviour отображений в пакете присутствует абстрактный класс MonoView и его наследники для конкретных типов данных:
142 |
143 | ```csharp
144 | //базовый класс для MonoBehaviour отображений
145 | public abstract class MonoView: MonoBehaviour, IView
146 | {
147 | public event Action OnDispose;
148 | public abstract void UpdateView(T value);
149 | protected virtual void OnDestroy() => OnDispose?.Invoke();
150 | }
151 |
152 | //MonoView для конкретного типа данных
153 | public abstract class MonoTextView: MonoView
154 | {
155 | protected abstract string Text { set; }
156 | public override void UpdateView(string value) => Text = value;
157 | }
158 |
159 | //конкретная реализация View
160 | public class SpeakerNameView : MonoTextView
161 | {
162 | [SerializeField] private TMP_Text speakerNameText;
163 | protected override string Text
164 | {
165 | set => speakerNameText.text = value;
166 | }
167 | }
168 | ```
169 |
170 | Вы можете сами создавать MonoView для собственных типов данных. Существующие в пакете решения покрывают только самые частые типы.
171 |
172 | ## Presenter
173 |
174 | Presenter реализует интерфейс IPresenter:
175 |
176 | ```csharp
177 | public interface IPresenter: IDisposable
178 | {
179 | void SubscribeModel(TModel model);
180 | }
181 | ```
182 |
183 | Взаимодействие с разными реактивными моделями предполагает использование соответствующего представителя. В пакете представлены:
184 |
185 | * PropertryPresenter для свойств
186 | * CollectionPresenter для коллекций
187 | * DictionaryPresenter для словарей
188 |
189 | Для каждого из вышеперечисленных классов существует парный класс для ситуаций, в которых не требуется конвертация типов данных для отображения.
190 |
191 | * PropertyPresenter
192 | * CollectionPresenter
193 | * DictionaryPresenter
194 |
195 | Создание собственного Presenter'а предполагает наследование от этих 6 классов и переопределение методов SubscribeModel и HandleModelUpdate при необходимости.
196 |
197 | ```csharp
198 | //пример представителя для отображения количества бустеров
199 | //и обработки нажатия на кнопку бустера
200 | public class BoosterPresenter: PropertyPresenter
201 | {
202 | //конкретизируем тип данных отображения
203 | //для обработки событий пользовательского ввода
204 | private new readonly BoosterButton view;
205 |
206 | private readonly ModalWindowView buyBoosterWindow;
207 |
208 | public BoosterPresenter(BoosterButton view, ModalWindowView buyBoosterWindow) : base(view)
209 | {
210 | this.view = view;
211 | this.buyBoosterWindow = buyBoosterWindow;
212 | this.view.OnClicked += HandleClick;
213 | }
214 |
215 | private void HandleClick()
216 | {
217 | if (model == null) return;
218 | if (model.Value == 0)
219 | {
220 | buyBoosterWindow.Open();
221 | return;
222 | }
223 | model.Value--;
224 | }
225 |
226 | public override void Dispose()
227 | {
228 | view.OnClicked -= HandleClick;
229 | base.Dispose();
230 | }
231 | }
232 |
233 | ...
234 |
235 | //подписка презентера на модель
236 | public override void Bind()
237 | {
238 | boosterPresenter = new BoosterPresenter(boosterButton, buyBoosterWindow);
239 | boosterPresenter.SubscribeModel(booster.Amount);
240 | }
241 | ```
242 |
243 | ## Простой Presenter
244 |
245 | Часто возникают ситуации, когда отображению необходимо только показывать значение модели без лишней логики. В таких кейсах создаются экземпляры классов PropertyPresenter, CollectionPresenter, DictionaryPresenter.
246 |
247 | ```csharp
248 | public void Bind()
249 | {
250 | //создание PropertyPresenter без наследования
251 | var speakerNamePresenter = new PropertyPresenter(speakerNameView);
252 |
253 | //подписка представителя на модель
254 | speakerNamePresenter.SubscribeModel(reactivePassage.SpeakerName);
255 | }
256 | ```
257 |
258 | # Архитектура UI
259 |
260 | Весь UI в пакете делится на Окна (Window) и элементы. Окно - это контейнер для элементов (включая вложенные окна). Окном может называться как весь экран приложения, так и отдельное модальное окно. У окон только две ответственности: определять порядок инициализации binder'ов (см. ниже) и вызывать очистку ресурсов при уничтожении.
261 |
262 | UI связывается с остальным кодом приложения через binder. В binder прокидываются ссылки на компоненты и описывается их взаимодействие с дочерними ему элементами UI. Каждому окну должен соответствовать свой binder, при этом binder может ссылаться на элементы из окон, находящихся в иерархии на любой позиции относительно его окна.
263 |
264 | Создание окна предполагает создание GameObject'а с компонентом MonoWindow и конкретной реализацией MonoBinder.
265 |
266 | 
267 |
268 | В компонент MonoWindow прокидываются ссылки на его дочерние окна. Делать это руками не обязательно. Достаточно перед тестом приложения нажать кнопку "Find subwindows automatically" на корневом компоненте MonoWindow. Все окна в иерархии сами установят ссылки на дочерние окна.
269 |
270 | ```csharp
271 | //пример реализации Binder'а для окна использования бустера
272 | public class BoostersBinder : MonoBinder
273 | {
274 | [SerializeField] private BoosterButton boosterButton;
275 | [SerializeField] private ModalWindowView buyBoosterWindow;
276 |
277 | private IBooster booster;
278 | private BoosterPresenter boosterPresenter;
279 |
280 | [Inject]
281 | private void Construct(IBooster booster)
282 | {
283 | this.booster = booster;
284 | }
285 |
286 | public override void Bind()
287 | {
288 | boosterPresenter = new BoosterPresenter(boosterButton, buyBoosterWindow);
289 | boosterPresenter.SubscribeModel(booster.Amount);
290 | }
291 |
292 | protected override void Unbind()
293 | {
294 | boosterPresenter?.Dispose();
295 | }
296 | }
297 | ```
298 |
299 | # Обучающий проект
300 |
301 | [Обучающий проект](https://github.com/laphedhendad/UI-Framework-Example) можно скачать архивом с GitHub. Проект использует [Zenject](https://github.com/modesttree/Zenject) и [UniTask](https://github.com/Cysharp/UniTask) в достаточно небольшом количестве, чтобы не отрывать внимание от пакета.
302 |
--------------------------------------------------------------------------------
/README_RU.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 96a31cdcd9d27e443b8c6c0cacdba122
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Scripts.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6a6cc77c7ff932d4b863773a168dbbd1
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Scripts/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 925d78ab36a66f04f92a6301481c9bcd
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Scripts/Editor/Laphed.UIFramework.UnityBridge.Editor.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Laphed.UIFramework.Editor",
3 | "rootNamespace": "",
4 | "references": [
5 | "GUID:38531a8a6cccc1e40929c5761ceb76a9"
6 | ],
7 | "includePlatforms": [
8 | "Editor"
9 | ],
10 | "excludePlatforms": [],
11 | "allowUnsafeCode": false,
12 | "overrideReferences": false,
13 | "precompiledReferences": [],
14 | "autoReferenced": true,
15 | "defineConstraints": [],
16 | "versionDefines": [],
17 | "noEngineReferences": false
18 | }
--------------------------------------------------------------------------------
/Scripts/Editor/Laphed.UIFramework.UnityBridge.Editor.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 164e0e3a6c2ae5f4e8651beb1ec40c8e
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Scripts/Editor/WindowCustomInspector.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using UnityEditor;
4 | using UnityEngine;
5 |
6 | namespace UIFramework.Editor
7 | {
8 | [CustomEditor(typeof(MonoWindow))]
9 | public class WindowCustomInspector: UnityEditor.Editor
10 | {
11 | public override void OnInspectorGUI()
12 | {
13 | DrawDefaultInspector();
14 |
15 | MonoWindow window = (MonoWindow)target;
16 |
17 | GUILayout.Space(10);
18 |
19 | if (GUILayout.Button("Find subwindows automatically"))
20 | {
21 | FindSubwindows(window);
22 | GUIUtility.ExitGUI();
23 | }
24 | }
25 |
26 | private void FindSubwindows(MonoWindow window)
27 | {
28 | List subwindows = window.GetComponentsInChildren(true).ToList();
29 | subwindows.RemoveAt(0);
30 | foreach (MonoWindow subwindow in subwindows)
31 | {
32 | FindSubwindows(subwindow);
33 | }
34 | window.SetSubwindows(subwindows.ToArray());
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/Scripts/Editor/WindowCustomInspector.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f30b03a379b544f498af871983902a6a
3 | timeCreated: 1705389824
--------------------------------------------------------------------------------
/Scripts/Runtime.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7653890c0f9128d4b9b0bd192e0546ff
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 574fae0da5d9a6d449d2b6e52ef9a84b
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/CollectionPresenter.cs:
--------------------------------------------------------------------------------
1 | using Laphed.Rx;
2 |
3 | namespace Laphed.MVP
4 | {
5 | public abstract class CollectionPresenter: ReactivePresenterBase>
6 | {
7 | protected CollectionPresenter(IView view): base(view)
8 | {
9 | }
10 |
11 | public override void SubscribeModel(IReadonlyReactiveCollection model)
12 | {
13 | base.SubscribeModel(model);
14 | UpdateView(model);
15 | }
16 |
17 | protected override void HandleModelUpdate() => UpdateView(model);
18 | protected abstract void UpdateView(IReadonlyReactiveCollection model);
19 | }
20 |
21 | public class CollectionPresenter: CollectionPresenter>
22 | {
23 | protected CollectionPresenter(IView> view): base(view)
24 | {
25 | }
26 |
27 | protected override void UpdateView(IReadonlyReactiveCollection model) => view.UpdateView(model);
28 | }
29 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/CollectionPresenter.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 7bb02344b9e14aea8d01755018060655
3 | timeCreated: 1703237882
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/DictionaryPresenter.cs:
--------------------------------------------------------------------------------
1 | using Laphed.Rx.Dictionary;
2 |
3 | namespace Laphed.MVP
4 | {
5 | public abstract class DictionaryPresenter: ReactivePresenterBase>
6 | {
7 | protected DictionaryPresenter(IView view) : base(view)
8 | {
9 | }
10 |
11 | public override void SubscribeModel(IReadOnlyReactiveDictionary model)
12 | {
13 | base.SubscribeModel(model);
14 | UpdateView(model);
15 | }
16 |
17 | protected override void HandleModelUpdate() => UpdateView(model);
18 |
19 | protected abstract void UpdateView(IReadOnlyReactiveDictionary model);
20 | }
21 |
22 | public class DictionaryPresenter: DictionaryPresenter>
23 | {
24 | protected DictionaryPresenter(IView> view) : base(view)
25 | {
26 | }
27 |
28 | protected override void HandleModelUpdate() => UpdateView(model);
29 |
30 | protected override void UpdateView(IReadOnlyReactiveDictionary model) => view.UpdateView(model);
31 | }
32 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/DictionaryPresenter.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4e5bc65ef6b24fd0a1219034472bff12
3 | timeCreated: 1704888174
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/IPresenter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Laphed.MVP
4 | {
5 | public interface IPresenter: IDisposable
6 | {
7 | void SubscribeModel(TModel model);
8 | }
9 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/IPresenter.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 123cdd37e4164bb0aa97ce250ae9d279
3 | timeCreated: 1704269146
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/IView.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Laphed.MVP
4 | {
5 | public interface IView
6 | {
7 | event Action OnDispose;
8 | void UpdateView(T value);
9 | }
10 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/IView.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8a1b1ee46a8b4bc6846f5c68367f7f2d
3 | timeCreated: 1696392261
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/Laphed.MVP.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Laphed.MVP",
3 | "rootNamespace": "Laphed.MVP",
4 | "references": [
5 | "GUID:cdda196ad70c47f40ae7a6aff190a032"
6 | ],
7 | "includePlatforms": [],
8 | "excludePlatforms": [],
9 | "allowUnsafeCode": false,
10 | "overrideReferences": false,
11 | "precompiledReferences": [],
12 | "autoReferenced": true,
13 | "defineConstraints": [],
14 | "versionDefines": [],
15 | "noEngineReferences": false
16 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/Laphed.MVP.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 849c4a899d48346459c9f919a37f6310
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/MonoBehaviourViews.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 27eb687adee141d5b22fd7f8f32e3150
3 | timeCreated: 1703076227
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/MonoBehaviourViews/MonoSpriteView.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace Laphed.MVP.MonoViews
4 | {
5 | public abstract class MonoSpriteView: MonoView
6 | {
7 | protected abstract Sprite Sprite { set; }
8 | public override void UpdateView(Sprite value) => Sprite = value;
9 | }
10 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/MonoBehaviourViews/MonoSpriteView.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5c6e676cb7ec40a48e5ffb5c65d27d3f
3 | timeCreated: 1703075808
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/MonoBehaviourViews/MonoTextView.cs:
--------------------------------------------------------------------------------
1 | namespace Laphed.MVP.MonoViews
2 | {
3 | public abstract class MonoTextView: MonoView
4 | {
5 | protected abstract string Text { set; }
6 | public override void UpdateView(string value) => Text = value;
7 | }
8 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/MonoBehaviourViews/MonoTextView.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 334eb62891774959a4683e1670a55575
3 | timeCreated: 1703076332
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/MonoBehaviourViews/MonoView.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | namespace Laphed.MVP.MonoViews
5 | {
6 | public abstract class MonoView: MonoBehaviour, IView
7 | {
8 | public event Action OnDispose;
9 | public abstract void UpdateView(T value);
10 | protected virtual void OnDestroy() => OnDispose?.Invoke();
11 | }
12 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/MonoBehaviourViews/MonoView.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ff4039f459ed463dae7252ebdea5044d
3 | timeCreated: 1703076348
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/PresenterBase.cs:
--------------------------------------------------------------------------------
1 | using Laphed.Rx;
2 |
3 | namespace Laphed.MVP
4 | {
5 | public abstract class PresenterBase: IPresenter where TReactive: IReactive
6 | {
7 | protected IView view;
8 | protected TReactive model;
9 |
10 | protected PresenterBase(IView view)
11 | {
12 | this.view = view;
13 | view.OnDispose += Dispose;
14 | }
15 |
16 | public abstract void SubscribeModel(TReactive model);
17 |
18 | protected abstract void HandleModelUpdate();
19 |
20 | public virtual void Dispose()
21 | {
22 | view.OnDispose -= Dispose;
23 | UnsubscribeModel();
24 | }
25 |
26 | protected abstract void UnsubscribeModel();
27 | }
28 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/PresenterBase.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8fe54c57f47a45148d4c396d3cad4da9
3 | timeCreated: 1704268821
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/PropertyPresenter.cs:
--------------------------------------------------------------------------------
1 | using Laphed.Rx;
2 |
3 | namespace Laphed.MVP
4 | {
5 | public abstract class PropertyPresenter: ReactivePresenterBase>
6 | {
7 | protected PropertyPresenter(IView view): base(view)
8 | {
9 | }
10 |
11 | public override void SubscribeModel(IReactiveProperty model)
12 | {
13 | base.SubscribeModel(model);
14 | UpdateView(model.Value);
15 | }
16 |
17 | protected override void HandleModelUpdate() => UpdateView(model.Value);
18 |
19 | protected abstract void UpdateView(TModelData value);
20 | }
21 |
22 | public class PropertyPresenter: PropertyPresenter
23 | {
24 | public PropertyPresenter(IView view) : base(view)
25 | {
26 | }
27 |
28 | protected override void UpdateView(TData value) => view.UpdateView(value);
29 | }
30 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/PropertyPresenter.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1600b1c4df3947e5a15c6aef7eea6d65
3 | timeCreated: 1696392796
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/ReactivePresenterBase.cs:
--------------------------------------------------------------------------------
1 | using Laphed.Rx;
2 |
3 | namespace Laphed.MVP
4 | {
5 | public abstract class ReactivePresenterBase: PresenterBase where TReactive: IReactive
6 | {
7 | protected ReactivePresenterBase(IView view): base(view)
8 | {
9 | view.OnDispose += Dispose;
10 | }
11 |
12 | public override void SubscribeModel(TReactive model)
13 | {
14 | if (model == null) return;
15 | this.model = model;
16 | model.OnChanged += HandleModelUpdate;
17 | }
18 |
19 | protected override void UnsubscribeModel()
20 | {
21 | if (model == null) return;
22 | model.OnChanged -= HandleModelUpdate;
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/MVP/ReactivePresenterBase.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 588b3e088a6548e489ad64c7922a23e3
3 | timeCreated: 1703239369
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 56d02f3bfbfe8ba409227b458c8285c7
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/IUiBinder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UIFramework
4 | {
5 | public interface IUiBinder: IDisposable
6 | {
7 | void Bind();
8 | }
9 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/IUiBinder.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 385775f80dd842ea8ac0785cae433329
3 | timeCreated: 1704907891
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/IWindow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UIFramework
4 | {
5 | public interface IWindow: IDisposable
6 | {
7 | void Initialize();
8 | }
9 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/IWindow.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: dbd03902cf6c40f09104f683612027dd
3 | timeCreated: 1704970286
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/Laphed.UIFramework.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Laphed.UIFramework",
3 | "rootNamespace": "Laphed.UIFramework",
4 | "references": [
5 | "GUID:cdda196ad70c47f40ae7a6aff190a032"
6 | ],
7 | "includePlatforms": [],
8 | "excludePlatforms": [],
9 | "allowUnsafeCode": false,
10 | "overrideReferences": false,
11 | "precompiledReferences": [],
12 | "autoReferenced": true,
13 | "defineConstraints": [],
14 | "versionDefines": [],
15 | "noEngineReferences": false
16 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/Laphed.UIFramework.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 38531a8a6cccc1e40929c5761ceb76a9
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/UiBinder.cs:
--------------------------------------------------------------------------------
1 | namespace UIFramework
2 | {
3 | public abstract class UiBinder: IUiBinder
4 | {
5 | private bool disposed;
6 |
7 | public abstract void Bind();
8 |
9 | protected abstract void Unbind();
10 |
11 | public void Dispose() => Dispose(true);
12 |
13 | protected virtual void Dispose(bool disposing)
14 | {
15 | if (disposed) return;
16 | Unbind();
17 | disposed = true;
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/UiBinder.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a2ddc999069d482b9707ac8ecb577dfb
3 | timeCreated: 1704907881
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/UnityMonoBridge.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 69a80367b379466ba6c6c33202ee643e
3 | timeCreated: 1704914255
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/UnityMonoBridge/MonoBinder.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UIFramework
4 | {
5 | public abstract class MonoBinder: MonoBehaviour, IUiBinder
6 | {
7 | private bool disposed;
8 |
9 | public abstract void Bind();
10 |
11 | protected abstract void Unbind();
12 |
13 | public void Dispose() => Dispose(true);
14 |
15 | protected virtual void Dispose(bool disposing)
16 | {
17 | if (disposed) return;
18 | Unbind();
19 | disposed = true;
20 | }
21 |
22 | protected virtual void OnDestroy()
23 | {
24 | Dispose(false);
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/UnityMonoBridge/MonoBinder.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 15969e50146c49c5be9b23a973f389b1
3 | timeCreated: 1705388700
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/UnityMonoBridge/MonoWindow.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UIFramework
4 | {
5 | public class MonoWindow: MonoBehaviour, IWindow
6 | {
7 | [SerializeField] private MonoBinder binder;
8 | [SerializeField] private MonoWindow[] subwindows;
9 |
10 | private bool isInitialized;
11 |
12 | public void Initialize()
13 | {
14 | if (isInitialized) return;
15 |
16 | isInitialized = true;
17 | binder.Bind();
18 |
19 | foreach (MonoWindow window in subwindows)
20 | {
21 | window.Initialize();
22 | }
23 | }
24 |
25 | public void SetSubwindows(MonoWindow[] subwindows) => this.subwindows = subwindows;
26 |
27 | #region Dispose Pattern
28 | private bool disposed;
29 |
30 | public void Dispose()
31 | {
32 | Dispose(true);
33 | Destroy(this);
34 | }
35 |
36 | private void Dispose(bool disposing)
37 | {
38 | if (disposed) return;
39 |
40 | if (disposing)
41 | {
42 | foreach (MonoWindow window in subwindows)
43 | {
44 | window.Dispose();
45 | }
46 |
47 | subwindows = null;
48 | }
49 |
50 | binder.Dispose();
51 | binder = null;
52 | disposed = true;
53 | }
54 |
55 | private void OnDestroy()
56 | {
57 | Dispose(false);
58 | }
59 | #endregion
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/UnityMonoBridge/MonoWindow.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 252b19f9ceca498188168532dbf453fa
3 | timeCreated: 1705389027
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/Window.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace UIFramework
4 | {
5 | public class Window: IWindow
6 | {
7 | private IUiBinder binder;
8 | private IWindow[] subwindows;
9 | private bool isInitialized;
10 |
11 | public Window(IUiBinder binder)
12 | {
13 | this.binder = binder;
14 | subwindows = Array.Empty();
15 | }
16 |
17 | public Window(IUiBinder binder, IWindow[] subwindows): this(binder)
18 | {
19 | this.subwindows = subwindows;
20 | }
21 |
22 | public void Initialize()
23 | {
24 | if (isInitialized) return;
25 |
26 | isInitialized = true;
27 | binder.Bind();
28 |
29 | foreach (IWindow window in subwindows)
30 | {
31 | window.Initialize();
32 | }
33 | }
34 |
35 | #region Dispose Pattern
36 | private bool disposed;
37 |
38 | public void Dispose()
39 | {
40 | Dispose(true);
41 | GC.SuppressFinalize(this);
42 | }
43 |
44 | protected virtual void Dispose(bool disposing)
45 | {
46 | if (disposed) return;
47 |
48 | if (disposing)
49 | {
50 | foreach (IWindow window in subwindows)
51 | {
52 | window.Dispose();
53 | }
54 |
55 | subwindows = null;
56 | }
57 |
58 | binder.Dispose();
59 | binder = null;
60 | disposed = true;
61 | }
62 |
63 | ~Window()
64 | {
65 | Dispose(false);
66 | }
67 | #endregion
68 | }
69 | }
--------------------------------------------------------------------------------
/Scripts/Runtime/UIFramework/Window.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0f205c2d67ac4d03a426165f34901ad9
3 | timeCreated: 1704894519
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "com.laphed.ui-framework",
3 | "displayName": "UI Framework",
4 | "author": { "name": "Laphed Hendad", "url": "https://github.com/laphedhendad" },
5 | "version": "1.0.1",
6 | "unity": "2020.1",
7 | "description": "UI Framework for Unity based on reactivity and MVP pattern.",
8 | "keywords": [ "ui", "mvp"],
9 | "license": "MIT",
10 | "category": "UI",
11 | "dependencies": {
12 | }
13 | }
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1c10364fa4544ee3939370684ec4b7b2
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------