using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
+ using Tizen.NUI.Binding;
+ using Tizen.NUI.Binding.Internals;
/**
* @brief Event arguments that passed via NUIApplicationInit signal
}
}
- internal class Application : BaseHandle
+ /// <summary>
+ /// A class to get resources in current application.
+ /// </summary>
+ public class GetResourcesProvider
{
+ /// <summary>
+ /// Get resources in current application.
+ /// </summary>
+ static public IResourcesProvider Get()
+ {
+ return Tizen.NUI.Application.Current;
+ }
+ }
+
+ internal class Application : BaseHandle, IResourcesProvider, IApplicationController, IElementConfiguration<Application>
+ {
+
+ static Application s_current;
+ Task<IDictionary<string, object>> _propertiesTask;
+ readonly Lazy<PlatformConfigurationRegistry<Application>> _platformConfigurationRegistry;
+
+ IAppIndexingProvider _appIndexProvider;
+
+ ReadOnlyCollection<Element> _logicalChildren;
+
+ Page _mainPage;
+
static SemaphoreSlim SaveSemaphore = new SemaphoreSlim(1, 1);
+ public IAppLinks AppLinks
+ {
+ get
+ {
+ if (_appIndexProvider == null)
+ throw new ArgumentException("No IAppIndexingProvider was provided");
+ if (_appIndexProvider.AppLinks == null)
+ throw new ArgumentException("No AppLinks implementation was found, if in Android make sure you installed the Xamarin.Forms.AppLinks");
+ return _appIndexProvider.AppLinks;
+ }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetCurrentApplication(Application value) => Current = value;
+
+ public static Application Current
+ {
+ get { return s_current; }
+ set
+ {
+ if (s_current == value)
+ return;
+ if (value == null)
+ s_current = null; //Allow to reset current for unittesting
+ s_current = value;
+ }
+ }
+
+ public Page MainPage
+ {
+ get { return _mainPage; }
+ set
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (_mainPage == value)
+ return;
+
+ OnPropertyChanging();
+ if (_mainPage != null)
+ {
+ InternalChildren.Remove(_mainPage);
+ _mainPage.Parent = null;
+ }
+
+ _mainPage = value;
+
+ if (_mainPage != null)
+ {
+ _mainPage.Parent = this;
+ _mainPage.NavigationProxy.Inner = NavigationProxy;
+ InternalChildren.Add(_mainPage);
+ }
+ OnPropertyChanged();
+ }
+ }
+
+ public IDictionary<string, object> Properties
+ {
+ get
+ {
+ if (_propertiesTask == null)
+ {
+ _propertiesTask = GetPropertiesAsync();
+ }
+
+ return _propertiesTask.Result;
+ }
+ }
+
+ internal override ReadOnlyCollection<Element> LogicalChildrenInternal
+ {
+ get { return _logicalChildren ?? (_logicalChildren = new ReadOnlyCollection<Element>(InternalChildren)); }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public new NavigationProxy NavigationProxy { get; }
+
[EditorBrowsable(EditorBrowsableState.Never)]
public int PanGestureId { get; set; }
+ internal IResourceDictionary SystemResources { get; }
+
+ ObservableCollection<Element> InternalChildren { get; } = new ObservableCollection<Element>();
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SetAppIndexingProvider(IAppIndexingProvider provider)
+ {
+ _appIndexProvider = provider;
+ }
+
+ ResourceDictionary _resources;
+ public bool IsResourcesCreated => _resources != null;
+
+ public delegate void resChangeCb(object sender, ResourcesChangedEventArgs e);
+
+ static private Dictionary<object, Dictionary<resChangeCb, int>> resourceChangeCallbackDict = new Dictionary<object, Dictionary<resChangeCb, int>>();
+ static public void AddResourceChangedCallback(object handle, resChangeCb cb)
+ {
+ Dictionary<resChangeCb, int> cbDict;
+ resourceChangeCallbackDict.TryGetValue(handle, out cbDict);
+
+ if (null == cbDict)
+ {
+ cbDict = new Dictionary<resChangeCb, int>();
+ resourceChangeCallbackDict.Add(handle, cbDict);
+ }
+
+ if (false == cbDict.ContainsKey(cb))
+ {
+ cbDict.Add(cb, 0);
+ }
+ }
+
+ internal override void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
+ {
+ base.OnResourcesChanged(sender, e);
+
+ foreach (KeyValuePair<object, Dictionary<resChangeCb, int>> resourcePair in resourceChangeCallbackDict)
+ {
+ foreach (KeyValuePair<resChangeCb, int> cbPair in resourcePair.Value)
+ {
+ cbPair.Key(sender, e);
+ }
+ }
+ }
+
+ public ResourceDictionary XamlResources
+ {
+ get
+ {
+ if (_resources != null)
+ return _resources;
+
+ _resources = new ResourceDictionary();
+ int hashCode = _resources.GetHashCode();
+ ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+ return _resources;
+ }
+ set
+ {
+ if (_resources == value)
+ return;
+ OnPropertyChanging();
+
+ if (_resources != null)
+ ((IResourceDictionary)_resources).ValuesChanged -= OnResourcesChanged;
+ _resources = value;
+ OnResourcesChanged(value);
+ if (_resources != null)
+ ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+
+ OnPropertyChanged();
+ }
+ }
+
+ public event EventHandler<ModalPoppedEventArgs> ModalPopped;
+
+ public event EventHandler<ModalPoppingEventArgs> ModalPopping;
+
+ public event EventHandler<ModalPushedEventArgs> ModalPushed;
+
+ public event EventHandler<ModalPushingEventArgs> ModalPushing;
+
+ public event EventHandler<Page> PageAppearing;
+
+ public event EventHandler<Page> PageDisappearing;
+
+
+ async void SaveProperties()
+ {
+ try
+ {
+ await SetPropertiesAsync();
+ }
+ catch (Exception exc)
+ {
+ Console.WriteLine(nameof(Application), $"Exception while saving Application Properties: {exc}");
+ }
+ }
+
+ public async Task SavePropertiesAsync()
+ {
+ if (Device.IsInvokeRequired)
+ {
+ Device.BeginInvokeOnMainThread(SaveProperties);
+ }
+ else
+ {
+ await SetPropertiesAsync();
+ }
+ }
+
+ // Don't use this unless there really is no better option
+ internal void SavePropertiesAsFireAndForget()
+ {
+ if (Device.IsInvokeRequired)
+ {
+ Device.BeginInvokeOnMainThread(SaveProperties);
+ }
+ else
+ {
+ SaveProperties();
+ }
+ }
+
+ public IPlatformElementConfiguration<T, Application> On<T>() where T : IConfigPlatform
+ {
+ return _platformConfigurationRegistry.Value.On<T>();
+ }
+
+ protected virtual void OnAppLinkRequestReceived(Uri uri)
+ {
+ }
+
+ protected override void OnParentSet()
+ {
+ throw new InvalidOperationException("Setting a Parent on Application is invalid.");
+ }
+
+ protected virtual void OnResume()
+ {
+ }
+
+ protected virtual void OnSleep()
+ {
+ }
+
+ protected virtual void OnStart()
+ {
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void ClearCurrent()
+ {
+ s_current = null;
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static bool IsApplicationOrNull(Element element)
+ {
+ return element == null || element is Application;
+ }
+
+ internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
+ {
+ if (!((IResourcesProvider)this).IsResourcesCreated || XamlResources.Count == 0)
+ {
+ base.OnParentResourcesChanged(values);
+ return;
+ }
+
+ var innerKeys = new HashSet<string>();
+ var changedResources = new List<KeyValuePair<string, object>>();
+ foreach (KeyValuePair<string, object> c in XamlResources)
+ innerKeys.Add(c.Key);
+ foreach (KeyValuePair<string, object> value in values)
+ {
+ if (innerKeys.Add(value.Key))
+ changedResources.Add(value);
+ }
+ OnResourcesChanged(changedResources);
+ }
+
+ internal event EventHandler PopCanceled;
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SendOnAppLinkRequestReceived(Uri uri)
+ {
+ OnAppLinkRequestReceived(uri);
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SendResume()
+ {
+ s_current = this;
+ OnResume();
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SendSleep()
+ {
+ OnSleep();
+ SavePropertiesAsFireAndForget();
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Task SendSleepAsync()
+ {
+ OnSleep();
+ return SavePropertiesAsync();
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SendStart()
+ {
+ OnStart();
+ }
+
+ async Task<IDictionary<string, object>> GetPropertiesAsync()
+ {
+ var deserializer = DependencyService.Get<IDeserializer>();
+ if (deserializer == null)
+ {
+ Console.WriteLine("Startup", "No IDeserialzier was found registered");
+ return new Dictionary<string, object>(4);
+ }
+
+ IDictionary<string, object> properties = await deserializer.DeserializePropertiesAsync().ConfigureAwait(false);
+ if (properties == null)
+ properties = new Dictionary<string, object>(4);
+
+ return properties;
+ }
+
+ internal void OnPageAppearing(Page page)
+ => PageAppearing?.Invoke(this, page);
+
+ internal void OnPageDisappearing(Page page)
+ => PageDisappearing?.Invoke(this, page);
+
+ void OnModalPopped(Page modalPage)
+ => ModalPopped?.Invoke(this, new ModalPoppedEventArgs(modalPage));
+
+ bool OnModalPopping(Page modalPage)
+ {
+ var args = new ModalPoppingEventArgs(modalPage);
+ ModalPopping?.Invoke(this, args);
+ return args.Cancel;
+ }
+
+ void OnModalPushed(Page modalPage)
+ => ModalPushed?.Invoke(this, new ModalPushedEventArgs(modalPage));
+
+ void OnModalPushing(Page modalPage)
+ => ModalPushing?.Invoke(this, new ModalPushingEventArgs(modalPage));
+
+ void OnPopCanceled()
+ => PopCanceled?.Invoke(this, EventArgs.Empty);
+
+ async Task SetPropertiesAsync()
+ {
+ await SaveSemaphore.WaitAsync();
+ try
+ {
+ await DependencyService.Get<IDeserializer>()?.SerializePropertiesAsync(Properties);
+ }
+ finally
+ {
+ SaveSemaphore.Release();
+ }
+
+ }
+
+ class NavigationImpl : NavigationProxy
+ {
+ readonly Application _owner;
+
+ public NavigationImpl(Application owner)
+ {
+ _owner = owner;
+ }
+
+ protected override async Task<Page> OnPopModal(bool animated)
+ {
+ Page modal = ModalStack[ModalStack.Count - 1];
+ if (_owner.OnModalPopping(modal))
+ {
+ _owner.OnPopCanceled();
+ return null;
+ }
+ Page result = await base.OnPopModal(animated);
+ result.Parent = null;
+ _owner.OnModalPopped(result);
+ return result;
+ }
+
+ protected override async Task OnPushModal(Page modal, bool animated)
+ {
+ _owner.OnModalPushing(modal);
+
+ modal.Parent = _owner;
+
+ if (modal.NavigationProxy.ModalStack.Count == 0)
+ {
+ modal.NavigationProxy.Inner = this;
+ await base.OnPushModal(modal, animated);
+ }
+ else
+ {
+ await base.OnPushModal(modal, animated);
+ modal.NavigationProxy.Inner = this;
+ }
+
+ _owner.OnModalPushed(modal);
+ }
+ }
+
private global::System.Runtime.InteropServices.HandleRef swigCPtr;
internal Application(global::System.IntPtr cPtr, bool cMemoryOwn) : base(NDalicPINVOKE.Application_SWIGUpcast(cPtr), cMemoryOwn)
{
+ NavigationProxy = new NavigationImpl(this);
+ SetCurrentApplication(this);
+
+ _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Application>>(() => new PlatformConfigurationRegistry<Application>(this));
swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
+
+ SendResume();
}
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Application obj)
{
Application ret = new Application(Interop.Application.Application_New__SWIG_3(argc, stylesheet, (int)windowMode), true);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ ret.SendResume();
return ret;
}