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;
9 namespace Tizen.NUI.Binding
11 internal class Application : Element, IResourcesProvider, IApplicationController, IElementConfiguration<Application>
13 static Application s_current;
14 Task<IDictionary<string, object>> _propertiesTask;
15 readonly Lazy<PlatformConfigurationRegistry<Application>> _platformConfigurationRegistry;
17 IAppIndexingProvider _appIndexProvider;
19 ReadOnlyCollection<Element> _logicalChildren;
23 static SemaphoreSlim SaveSemaphore = new SemaphoreSlim(1, 1);
30 NavigationProxy = new NavigationImpl(this);
31 SetCurrentApplication(this);
33 SystemResources = DependencyService.Get<ISystemResourcesProvider>()?.GetSystemResources();
34 SystemResources.ValuesChanged += OnParentResourcesChanged;
35 _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Application>>(() => new PlatformConfigurationRegistry<Application>(this));
40 Device.PlatformServices?.QuitApplication();
43 public IAppLinks AppLinks
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;
55 [EditorBrowsable(EditorBrowsableState.Never)]
56 public static void SetCurrentApplication(Application value) => Current = value;
58 public static Application Current
60 get { return s_current; }
63 if (s_current == value)
66 s_current = null; //Allow to reset current for unittesting
73 get { return _mainPage; }
77 throw new ArgumentNullException("value");
79 if (_mainPage == value)
83 if (_mainPage != null)
85 InternalChildren.Remove(_mainPage);
86 _mainPage.Parent = null;
91 if (_mainPage != null)
93 _mainPage.Parent = this;
94 _mainPage.NavigationProxy.Inner = NavigationProxy;
95 InternalChildren.Add(_mainPage);
101 public IDictionary<string, object> Properties
105 if (_propertiesTask == null)
107 _propertiesTask = GetPropertiesAsync();
110 return _propertiesTask.Result;
114 internal override ReadOnlyCollection<Element> LogicalChildrenInternal
116 get { return _logicalChildren ?? (_logicalChildren = new ReadOnlyCollection<Element>(InternalChildren)); }
119 [EditorBrowsable(EditorBrowsableState.Never)]
120 public NavigationProxy NavigationProxy { get; }
122 [EditorBrowsable(EditorBrowsableState.Never)]
123 public int PanGestureId { get; set; }
125 internal IResourceDictionary SystemResources { get; }
127 ObservableCollection<Element> InternalChildren { get; } = new ObservableCollection<Element>();
129 [EditorBrowsable(EditorBrowsableState.Never)]
130 public void SetAppIndexingProvider(IAppIndexingProvider provider)
132 _appIndexProvider = provider;
135 ResourceDictionary _resources;
136 bool IResourcesProvider.IsResourcesCreated => _resources != null;
138 public ResourceDictionary XamlResources
142 if (_resources != null)
145 _resources = new ResourceDictionary();
146 ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
151 if (_resources == value)
153 OnPropertyChanging();
154 if (_resources != null)
155 ((IResourceDictionary)_resources).ValuesChanged -= OnResourcesChanged;
157 OnResourcesChanged(value);
158 if (_resources != null)
159 ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
164 public event EventHandler<ModalPoppedEventArgs> ModalPopped;
166 public event EventHandler<ModalPoppingEventArgs> ModalPopping;
168 public event EventHandler<ModalPushedEventArgs> ModalPushed;
170 public event EventHandler<ModalPushingEventArgs> ModalPushing;
172 public event EventHandler<Page> PageAppearing;
174 public event EventHandler<Page> PageDisappearing;
177 async void SaveProperties()
181 await SetPropertiesAsync();
183 catch (Exception exc)
185 Console.WriteLine(nameof(Application), $"Exception while saving Application Properties: {exc}");
189 public async Task SavePropertiesAsync()
191 if (Device.IsInvokeRequired)
193 Device.BeginInvokeOnMainThread(SaveProperties);
197 await SetPropertiesAsync();
201 // Don't use this unless there really is no better option
202 internal void SavePropertiesAsFireAndForget()
204 if (Device.IsInvokeRequired)
206 Device.BeginInvokeOnMainThread(SaveProperties);
214 public IPlatformElementConfiguration<T, Application> On<T>() where T : IConfigPlatform
216 return _platformConfigurationRegistry.Value.On<T>();
219 protected virtual void OnAppLinkRequestReceived(Uri uri)
223 protected override void OnParentSet()
225 throw new InvalidOperationException("Setting a Parent on Application is invalid.");
228 protected virtual void OnResume()
232 protected virtual void OnSleep()
236 protected virtual void OnStart()
240 [EditorBrowsable(EditorBrowsableState.Never)]
241 public static void ClearCurrent()
246 [EditorBrowsable(EditorBrowsableState.Never)]
247 public static bool IsApplicationOrNull(Element element)
249 return element == null || element is Application;
252 internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
254 if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0)
256 base.OnParentResourcesChanged(values);
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)
266 if (innerKeys.Add(value.Key))
267 changedResources.Add(value);
269 OnResourcesChanged(changedResources);
272 internal event EventHandler PopCanceled;
274 [EditorBrowsable(EditorBrowsableState.Never)]
275 public void SendOnAppLinkRequestReceived(Uri uri)
277 OnAppLinkRequestReceived(uri);
280 [EditorBrowsable(EditorBrowsableState.Never)]
281 public void SendResume()
287 [EditorBrowsable(EditorBrowsableState.Never)]
288 public void SendSleep()
291 SavePropertiesAsFireAndForget();
294 [EditorBrowsable(EditorBrowsableState.Never)]
295 public Task SendSleepAsync()
298 return SavePropertiesAsync();
301 [EditorBrowsable(EditorBrowsableState.Never)]
302 public void SendStart()
307 async Task<IDictionary<string, object>> GetPropertiesAsync()
309 var deserializer = DependencyService.Get<IDeserializer>();
310 if (deserializer == null)
312 Console.WriteLine("Startup", "No IDeserialzier was found registered");
313 return new Dictionary<string, object>(4);
316 IDictionary<string, object> properties = await deserializer.DeserializePropertiesAsync().ConfigureAwait(false);
317 if (properties == null)
318 properties = new Dictionary<string, object>(4);
323 internal void OnPageAppearing(Page page)
324 => PageAppearing?.Invoke(this, page);
326 internal void OnPageDisappearing(Page page)
327 => PageDisappearing?.Invoke(this, page);
329 void OnModalPopped(Page modalPage)
330 => ModalPopped?.Invoke(this, new ModalPoppedEventArgs(modalPage));
332 bool OnModalPopping(Page modalPage)
334 var args = new ModalPoppingEventArgs(modalPage);
335 ModalPopping?.Invoke(this, args);
339 void OnModalPushed(Page modalPage)
340 => ModalPushed?.Invoke(this, new ModalPushedEventArgs(modalPage));
342 void OnModalPushing(Page modalPage)
343 => ModalPushing?.Invoke(this, new ModalPushingEventArgs(modalPage));
346 => PopCanceled?.Invoke(this, EventArgs.Empty);
348 async Task SetPropertiesAsync()
350 await SaveSemaphore.WaitAsync();
353 await DependencyService.Get<IDeserializer>()?.SerializePropertiesAsync(Properties);
357 SaveSemaphore.Release();
362 class NavigationImpl : NavigationProxy
364 readonly Application _owner;
366 public NavigationImpl(Application owner)
371 protected override async Task<Page> OnPopModal(bool animated)
373 Page modal = ModalStack[ModalStack.Count - 1];
374 if (_owner.OnModalPopping(modal))
376 _owner.OnPopCanceled();
379 Page result = await base.OnPopModal(animated);
380 result.Parent = null;
381 _owner.OnModalPopped(result);
385 protected override async Task OnPushModal(Page modal, bool animated)
387 _owner.OnModalPushing(modal);
389 modal.Parent = _owner;
391 if (modal.NavigationProxy.ModalStack.Count == 0)
393 modal.NavigationProxy.Inner = this;
394 await base.OnPushModal(modal, animated);
398 await base.OnPushModal(modal, animated);
399 modal.NavigationProxy.Inner = this;
402 _owner.OnModalPushed(modal);