1461a00f0ccabdacab15c98a2f9f05fd440f0898
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / XamlBinding / Application.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Collections.ObjectModel;
4 using System.Threading;
5 using System.ComponentModel;
6 using System.Threading.Tasks;
7 using Tizen.NUI.Binding.Internals;
8
9 namespace Tizen.NUI.Binding
10 {
11     internal class Application : Element, IResourcesProvider, IApplicationController, IElementConfiguration<Application>
12     {
13         static Application s_current;
14         Task<IDictionary<string, object>> _propertiesTask;
15         readonly Lazy<PlatformConfigurationRegistry<Application>> _platformConfigurationRegistry;
16
17         IAppIndexingProvider _appIndexProvider;
18
19         ReadOnlyCollection<Element> _logicalChildren;
20
21         Page _mainPage;
22
23         static SemaphoreSlim SaveSemaphore = new SemaphoreSlim(1, 1);
24
25         public Application()
26         {
27             // var f = false;
28             // if (f)
29             //  Loader.Load();
30             NavigationProxy = new NavigationImpl(this);
31             SetCurrentApplication(this);
32
33             SystemResources = DependencyService.Get<ISystemResourcesProvider>()?.GetSystemResources();
34             SystemResources.ValuesChanged += OnParentResourcesChanged;
35             _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Application>>(() => new PlatformConfigurationRegistry<Application>(this));
36         }
37
38         public void Quit()
39         {
40             Device.PlatformServices?.QuitApplication();
41         }
42
43         public IAppLinks AppLinks
44         {
45             get
46             {
47                 if (_appIndexProvider == null)
48                     throw new ArgumentException("No IAppIndexingProvider was provided");
49                 if (_appIndexProvider.AppLinks == null)
50                     throw new ArgumentException("No AppLinks implementation was found, if in Android make sure you installed the Tizen.NUI.Binding.AppLinks");
51                 return _appIndexProvider.AppLinks;
52             }
53         }
54
55         [EditorBrowsable(EditorBrowsableState.Never)]
56         public static void SetCurrentApplication(Application value) => Current = value;
57
58         public static Application Current
59         {
60             get { return s_current; }
61             set
62             {
63                 if (s_current == value)
64                     return;
65                 if (value == null)
66                     s_current = null; //Allow to reset current for unittesting
67                 s_current = value;
68             }
69         }
70
71         public Page MainPage
72         {
73             get { return _mainPage; }
74             set
75             {
76                 if (value == null)
77                     throw new ArgumentNullException("value");
78
79                 if (_mainPage == value)
80                     return;
81
82                 OnPropertyChanging();
83                 if (_mainPage != null)
84                 {
85                     InternalChildren.Remove(_mainPage);
86                     _mainPage.Parent = null;
87                 }
88
89                 _mainPage = value;
90
91                 if (_mainPage != null)
92                 {
93                     _mainPage.Parent = this;
94                     _mainPage.NavigationProxy.Inner = NavigationProxy;
95                     InternalChildren.Add(_mainPage);
96                 }
97                 OnPropertyChanged();
98             }
99         }
100
101         public IDictionary<string, object> Properties
102         {
103             get
104             {
105                 if (_propertiesTask == null)
106                 {
107                     _propertiesTask = GetPropertiesAsync();
108                 }
109
110                 return _propertiesTask.Result;
111             }
112         }
113
114         internal override ReadOnlyCollection<Element> LogicalChildrenInternal
115         {
116             get { return _logicalChildren ?? (_logicalChildren = new ReadOnlyCollection<Element>(InternalChildren)); }
117         }
118
119         [EditorBrowsable(EditorBrowsableState.Never)]
120         public NavigationProxy NavigationProxy { get; }
121
122         [EditorBrowsable(EditorBrowsableState.Never)]
123         public int PanGestureId { get; set; }
124
125         internal IResourceDictionary SystemResources { get; }
126
127         ObservableCollection<Element> InternalChildren { get; } = new ObservableCollection<Element>();
128
129         [EditorBrowsable(EditorBrowsableState.Never)]
130         public void SetAppIndexingProvider(IAppIndexingProvider provider)
131         {
132             _appIndexProvider = provider;
133         }
134
135         ResourceDictionary _resources;
136         bool IResourcesProvider.IsResourcesCreated => _resources != null;
137
138         public ResourceDictionary XamlResources
139         {
140             get
141             {
142                 if (_resources != null)
143                     return _resources;
144
145                 _resources = new ResourceDictionary();
146                 ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
147                 return _resources;
148             }
149             set
150             {
151                 if (_resources == value)
152                     return;
153                 OnPropertyChanging();
154                 if (_resources != null)
155                     ((IResourceDictionary)_resources).ValuesChanged -= OnResourcesChanged;
156                 _resources = value;
157                 OnResourcesChanged(value);
158                 if (_resources != null)
159                     ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
160                 OnPropertyChanged();
161             }
162         }
163
164         public event EventHandler<ModalPoppedEventArgs> ModalPopped;
165
166         public event EventHandler<ModalPoppingEventArgs> ModalPopping;
167
168         public event EventHandler<ModalPushedEventArgs> ModalPushed;
169
170         public event EventHandler<ModalPushingEventArgs> ModalPushing;
171
172         public event EventHandler<Page> PageAppearing;
173
174         public event EventHandler<Page> PageDisappearing;
175
176
177         async void SaveProperties()
178         {
179             try
180             {
181                 await SetPropertiesAsync();
182             }
183             catch (Exception exc)
184             {
185                 Console.WriteLine(nameof(Application), $"Exception while saving Application Properties: {exc}");
186             }
187         }
188
189         public async Task SavePropertiesAsync()
190         {
191             if (Device.IsInvokeRequired)
192             {
193                 Device.BeginInvokeOnMainThread(SaveProperties);
194             }
195             else
196             {
197                 await SetPropertiesAsync();
198             }
199         }
200
201         // Don't use this unless there really is no better option
202         internal void SavePropertiesAsFireAndForget()
203         {
204             if (Device.IsInvokeRequired)
205             {
206                 Device.BeginInvokeOnMainThread(SaveProperties);
207             }
208             else
209             {
210                 SaveProperties();
211             }
212         }
213
214         public IPlatformElementConfiguration<T, Application> On<T>() where T : IConfigPlatform
215         {
216             return _platformConfigurationRegistry.Value.On<T>();
217         }
218
219         protected virtual void OnAppLinkRequestReceived(Uri uri)
220         {
221         }
222
223         protected override void OnParentSet()
224         {
225             throw new InvalidOperationException("Setting a Parent on Application is invalid.");
226         }
227
228         protected virtual void OnResume()
229         {
230         }
231
232         protected virtual void OnSleep()
233         {
234         }
235
236         protected virtual void OnStart()
237         {
238         }
239
240         [EditorBrowsable(EditorBrowsableState.Never)]
241         public static void ClearCurrent()
242         {
243             s_current = null;
244         }
245
246         [EditorBrowsable(EditorBrowsableState.Never)]
247         public static bool IsApplicationOrNull(Element element)
248         {
249             return element == null || element is Application;
250         }
251
252         internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
253         {
254             if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0)
255             {
256                 base.OnParentResourcesChanged(values);
257                 return;
258             }
259
260             var innerKeys = new HashSet<string>();
261             var changedResources = new List<KeyValuePair<string, object>>();
262             foreach (KeyValuePair<string, object> c in XamlResources)
263                 innerKeys.Add(c.Key);
264             foreach (KeyValuePair<string, object> value in values)
265             {
266                 if (innerKeys.Add(value.Key))
267                     changedResources.Add(value);
268             }
269             OnResourcesChanged(changedResources);
270         }
271
272         internal event EventHandler PopCanceled;
273
274         [EditorBrowsable(EditorBrowsableState.Never)]
275         public void SendOnAppLinkRequestReceived(Uri uri)
276         {
277             OnAppLinkRequestReceived(uri);
278         }
279
280         [EditorBrowsable(EditorBrowsableState.Never)]
281         public void SendResume()
282         {
283             s_current = this;
284             OnResume();
285         }
286
287         [EditorBrowsable(EditorBrowsableState.Never)]
288         public void SendSleep()
289         {
290             OnSleep();
291             SavePropertiesAsFireAndForget();
292         }
293
294         [EditorBrowsable(EditorBrowsableState.Never)]
295         public Task SendSleepAsync()
296         {
297             OnSleep();
298             return SavePropertiesAsync();
299         }
300
301         [EditorBrowsable(EditorBrowsableState.Never)]
302         public void SendStart()
303         {
304             OnStart();
305         }
306
307         async Task<IDictionary<string, object>> GetPropertiesAsync()
308         {
309             var deserializer = DependencyService.Get<IDeserializer>();
310             if (deserializer == null)
311             {
312                 Console.WriteLine("Startup", "No IDeserialzier was found registered");
313                 return new Dictionary<string, object>(4);
314             }
315
316             IDictionary<string, object> properties = await deserializer.DeserializePropertiesAsync().ConfigureAwait(false);
317             if (properties == null)
318                 properties = new Dictionary<string, object>(4);
319
320             return properties;
321         }
322
323         internal void OnPageAppearing(Page page)
324             => PageAppearing?.Invoke(this, page);
325
326         internal void OnPageDisappearing(Page page)
327             => PageDisappearing?.Invoke(this, page);
328
329         void OnModalPopped(Page modalPage)
330             => ModalPopped?.Invoke(this, new ModalPoppedEventArgs(modalPage));
331
332         bool OnModalPopping(Page modalPage)
333         {
334             var args = new ModalPoppingEventArgs(modalPage);
335             ModalPopping?.Invoke(this, args);
336             return args.Cancel;
337         }
338
339         void OnModalPushed(Page modalPage)
340             => ModalPushed?.Invoke(this, new ModalPushedEventArgs(modalPage));
341
342         void OnModalPushing(Page modalPage)
343             => ModalPushing?.Invoke(this, new ModalPushingEventArgs(modalPage));
344
345         void OnPopCanceled()
346             => PopCanceled?.Invoke(this, EventArgs.Empty);
347
348         async Task SetPropertiesAsync()
349         {
350             await SaveSemaphore.WaitAsync();
351             try
352             {
353                 await DependencyService.Get<IDeserializer>()?.SerializePropertiesAsync(Properties);
354             }
355             finally
356             {
357                 SaveSemaphore.Release();
358             }
359
360         }
361
362         class NavigationImpl : NavigationProxy
363         {
364             readonly Application _owner;
365
366             public NavigationImpl(Application owner)
367             {
368                 _owner = owner;
369             }
370
371             protected override async Task<Page> OnPopModal(bool animated)
372             {
373                 Page modal = ModalStack[ModalStack.Count - 1];
374                 if (_owner.OnModalPopping(modal))
375                 {
376                     _owner.OnPopCanceled();
377                     return null;
378                 }
379                 Page result = await base.OnPopModal(animated);
380                 result.Parent = null;
381                 _owner.OnModalPopped(result);
382                 return result;
383             }
384
385             protected override async Task OnPushModal(Page modal, bool animated)
386             {
387                 _owner.OnModalPushing(modal);
388
389                 modal.Parent = _owner;
390
391                 if (modal.NavigationProxy.ModalStack.Count == 0)
392                 {
393                     modal.NavigationProxy.Inner = this;
394                     await base.OnPushModal(modal, animated);
395                 }
396                 else
397                 {
398                     await base.OnPushModal(modal, animated);
399                     modal.NavigationProxy.Inner = this;
400                 }
401
402                 _owner.OnModalPushed(modal);
403             }
404         }
405     }
406 }