/* * Copyright (c) 2018 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; using System.Threading; using System.Threading.Tasks; using Tizen.NUI.Binding.Internals; using Tizen.NUI.Binding; namespace Tizen.NUI { /// /// A BaseHandle that occupies the entire screen. /// // [RenderWith(typeof(_PageRenderer))] [EditorBrowsable(EditorBrowsableState.Never)] public class Page : BaseHandle, IPageController, IElementConfiguration { /// /// For internal use. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public const string BusySetSignalName = "NUI.BusySet"; /// /// For internal use. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public const string AlertSignalName = "NUI.SendAlert"; /// /// For internal use. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public const string ActionSheetSignalName = "NUI.ShowActionSheet"; internal static readonly BindableProperty IgnoresContainerAreaProperty = BindableProperty.Create(nameof(IgnoresContainerArea), typeof(bool), typeof(Page), false); /// /// Identifies the IsBusy property. /// internal static readonly BindableProperty IsBusyProperty = BindableProperty.Create(nameof(IsBusy), typeof(bool), typeof(Page), false, propertyChanged: (bo, o, n) => ((Page)bo).OnPageBusyChanged()); Rectangle _containerArea; bool _hasAppeared; ReadOnlyCollection _logicalChildren; /// /// Creates a new Page element with default values. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public Page() { // ToolbarItems = toolbarItems; InternalChildren.CollectionChanged += InternalChildrenOnCollectionChanged; } /// /// Marks the Page as busy. This will cause the platform specific global activity indicator to show a busy state. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public bool IsBusy { get { return (bool)GetValue(IsBusyProperty); } set { SetValue(IsBusyProperty, value); } } /// /// For internal use. /// [EditorBrowsable(EditorBrowsableState.Never)] public Rectangle ContainerArea { get { return _containerArea; } set { if (_containerArea == value) return; _containerArea = value; ForceLayout(); } } /// /// For internal use. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool IgnoresContainerArea { get { return (bool)GetValue(IgnoresContainerAreaProperty); } set { SetValue(IgnoresContainerAreaProperty, value); } } /// /// For internal use. /// [EditorBrowsable(EditorBrowsableState.Never)] public ObservableCollection InternalChildren { get; } = new ObservableCollection(); internal override ReadOnlyCollection LogicalChildrenInternal => _logicalChildren ?? (_logicalChildren = new ReadOnlyCollection(InternalChildren)); /// /// ndicates that the Page is about to appear. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public event EventHandler Appearing; /// /// Indicates that the Page is about to cease displaying. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public event EventHandler Disappearing; /// /// Displays a native platform action sheet, allowing the application user to choose from several buttons. /// /// Title of the displayed action sheet. Must not be null. /// Text to be displayed in the 'Cancel' button. Can be null to hide the cancel action. /// Text to be displayed in the 'Destruct' button. Can be null to hide the destructive option. /// Text labels for additional buttons. Must not be null. /// An awaitable Task that displays an action sheet and returns the Text of the button pressed by the user. /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public Task DisplayActionSheet(string title, string cancel, string destruction, params string[] buttons) { var args = new ActionSheetArguments(title, cancel, destruction, buttons); MessagingCenter.Send(this, ActionSheetSignalName, args); return args.Result.Task; } /// /// Presents an alert dialog to the application user with a single cancel button. /// /// The title of the alert dialog. /// The body text of the alert dialog. /// Text to be displayed on the 'Cancel' button. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public Task DisplayAlert(string title, string message, string cancel) { return DisplayAlert(title, message, null, cancel); } /// /// resents an alert dialog to the application user with an accept and a cancel button. /// /// The title of the alert dialog. /// The body text of the alert dialog. /// Text to be displayed on the 'Accept' button. /// Text to be displayed on the 'Cancel' button. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public Task DisplayAlert(string title, string message, string accept, string cancel) { if (string.IsNullOrEmpty(cancel)) throw new ArgumentNullException(nameof(cancel)); var args = new AlertArguments(title, message, accept, cancel); MessagingCenter.Send(this, AlertSignalName, args); return args.Result.Task; } /// /// Forces the Page to perform a layout pass. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public void ForceLayout() { } /// /// Calls OnBackButtonPressed(). /// /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] public bool SendBackButtonPressed() { return OnBackButtonPressed(); } /// /// When overridden, allows application developers to customize behavior immediately prior to the Page becoming visible. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual void OnAppearing() { } /// /// Application developers can override this method to provide behavior when the back button is pressed. /// /// true if consumed /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool OnBackButtonPressed() { var application = RealParent as Application; var canceled = false; EventHandler handler = (sender, args) => { canceled = true; }; return !canceled; } /// /// Invoked whenever the binding context of the Page changes. Override this method to add class handling for this event. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] protected override void OnBindingContextChanged() { base.OnBindingContextChanged(); } /// /// Indicates that the preferred size of a child Element has changed. /// /// The object that raised the event. /// The event arguments. /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual void OnChildMeasureInvalidated(object sender, EventArgs e) { InvalidationTrigger trigger = (e as InvalidationEventArgs)?.Trigger ?? InvalidationTrigger.Undefined; OnChildMeasureInvalidated((BaseHandle)sender, trigger); } /// /// When overridden, allows the application developer to customize behavior as the Page disappears. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] protected virtual void OnDisappearing() { } /// /// Called when the Page's Parent property has changed. /// /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] protected override void OnParentSet() { base.OnParentSet(); } internal virtual void OnChildMeasureInvalidated(BaseHandle child, InvalidationTrigger trigger) { var container = this as IPageContainer; if (container != null) { Page page = container.CurrentPage; if (page != null) { return; } } else { for (var i = 0; i < LogicalChildren.Count; i++) { var v = LogicalChildren[i] as BaseHandle; if (v != null) { return; } } } } /// /// For intarnal use. /// [EditorBrowsable(EditorBrowsableState.Never)] public void SendAppearing() { if (_hasAppeared) return; _hasAppeared = true; if (IsBusy) MessagingCenter.Send(this, BusySetSignalName, true); OnAppearing(); Appearing?.Invoke(this, EventArgs.Empty); var pageContainer = this as IPageContainer; pageContainer?.CurrentPage?.SendAppearing(); } /// /// For intarnal use. /// [EditorBrowsable(EditorBrowsableState.Never)] public void SendDisappearing() { if (!_hasAppeared) return; _hasAppeared = false; if (IsBusy) MessagingCenter.Send(this, BusySetSignalName, false); var pageContainer = this as IPageContainer; pageContainer?.CurrentPage?.SendDisappearing(); OnDisappearing(); Disappearing?.Invoke(this, EventArgs.Empty); } Application FindApplication(Element element) { if (element == null) return null; return (element.Parent is Application app) ? app : FindApplication(element.Parent); } void InternalChildrenOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (BaseHandle item in e.OldItems.OfType()) { OnInternalRemoved(item); } } if (e.NewItems != null) { foreach (BaseHandle item in e.NewItems.OfType()) { OnInternalAdded(item); } } } private void OnInternalAdded(BaseHandle view) { OnChildAdded(view); } private void OnInternalRemoved(BaseHandle view) { OnChildRemoved(view); } void OnPageBusyChanged() { if (!_hasAppeared) return; MessagingCenter.Send(this, BusySetSignalName, IsBusy); } void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) { if (null != args) { if (args.Action != NotifyCollectionChangedAction.Add) return; if (args.NewItems != null) { foreach (IElement item in args.NewItems) item.Parent = this; } } } bool ShouldLayoutChildren() { if (!LogicalChildren.Any()) { return false; } var container = this as IPageContainer; if (container?.CurrentPage != null) { return true; } var any = false; for (var i = 0; i < LogicalChildren.Count; i++) { var v = LogicalChildren[i] as BaseHandle; if (v != null) { any = true; break; } } return !any; } } }