[NUI] Fix Navigator to support Page with Transitions
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Navigation / Navigator.cs
index f5f65e2..9d5dd83 100755 (executable)
@@ -155,13 +155,19 @@ namespace Tizen.NUI.Components
         private void OnAddedToWindow(object sender, EventArgs e)
         {
             parentWindow = Window.Get(this);
-            parentWindow.KeyEvent += OnWindowKeyEvent;
+            if (null != parentWindow)
+            {
+                parentWindow.KeyEvent += OnWindowKeyEvent;
+            }
         }
 
         private void OnRemovedFromWindow(object sender, EventArgs e)
         {
-            parentWindow.KeyEvent -= OnWindowKeyEvent;
-            parentWindow = null;
+            if (null != parentWindow)
+            {
+                parentWindow.KeyEvent -= OnWindowKeyEvent;
+                parentWindow = null;
+            }
         }
 
         private void Initialize()
@@ -182,6 +188,16 @@ namespace Tizen.NUI.Components
         }
 
         /// <summary>
+        /// Creates a new instance of Navigator with style.
+        /// </summary>
+        /// <param name="style">Creates Navigator by special style defined in UX.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Navigator(string style) : base(style)
+        {
+            Initialize();
+        }
+
+        /// <summary>
         /// Creates a new instance of a Navigator with style.
         /// </summary>
         /// <param name="style">A style applied to the newly created Navigator.</param>
@@ -393,6 +409,9 @@ namespace Tizen.NUI.Components
             //Duplicate page is not pushed.
             if (navigationPages.Contains(page)) return;
 
+            //TODO: The following transition codes will be replaced with view transition.
+            InitializeAnimation();
+
             var curTop = Peek();
 
             if (!curTop)
@@ -411,9 +430,6 @@ namespace Tizen.NUI.Components
 
             curTop.SaveKeyFocus();
 
-            //TODO: The following transition codes will be replaced with view transition.
-            InitializeAnimation();
-
             if (page is DialogPage == false)
             {
                 curAnimation = new Animation(DefaultTransitionDuration);
@@ -475,6 +491,9 @@ namespace Tizen.NUI.Components
                 throw new InvalidOperationException("There is no page in Navigator.");
             }
 
+            //TODO: The following transition codes will be replaced with view transition.
+            InitializeAnimation();
+
             var curTop = Peek();
 
             if (navigationPages.Count == 1)
@@ -494,9 +513,6 @@ namespace Tizen.NUI.Components
             curTop.InvokeDisappearing();
             curTop.SaveKeyFocus();
 
-            //TODO: The following transition codes will be replaced with view transition.
-            InitializeAnimation();
-
             if (curTop is DialogPage == false)
             {
                 curAnimation = new Animation(DefaultTransitionDuration);
@@ -749,7 +765,9 @@ namespace Tizen.NUI.Components
         }
 
         /// <summary>
-        /// Gets or sets if Navigator pops the peek page when back button or back key is pressed and released.
+        /// Gets or sets if Navigator proceeds back navigation when back button or back key is pressed and released.
+        /// Back navigation pops the peek page if Navigator has more than one page.
+        /// If Navigator has only one page, then the current program is exited.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public bool EnableBackNavigation
@@ -841,7 +859,46 @@ namespace Tizen.NUI.Components
         }
 
         /// <summary>
+        /// Sets the default navigator of the given window.
+        /// SetDefaultNavigator does not remove the previous default navigator from the window.
+        /// Therefore, if a user does not want to show the previous default navigator, then it should be removed from the window manually.
+        /// </summary>
+        /// <exception cref="ArgumentNullException">Thrown when the argument window is null.</exception>
+        /// <exception cref="ArgumentNullException">Thrown when the argument newNavigator is null.</exception>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public static void SetDefaultNavigator(Window window, Navigator newNavigator)
+        {
+            if (window == null)
+            {
+                throw new ArgumentNullException(nameof(window), "window should not be null.");
+            }
+
+            if (newNavigator == null)
+            {
+                throw new ArgumentNullException(nameof(newNavigator), "newNavigator should not be null.");
+            }
+
+            if (windowNavigator.ContainsKey(window) == true)
+            {
+                var oldNavigator = windowNavigator[window];
+                if (oldNavigator == newNavigator)
+                {
+                    return;
+                }
+
+                navigatorWindow.Remove(oldNavigator);
+                windowNavigator.Remove(window);
+            }
+
+            window.Add(newNavigator);
+            windowNavigator.Add(window, newNavigator);
+            navigatorWindow.Add(newNavigator, window);
+        }
+
+        /// <summary>
         /// Called when the back navigation is started.
+        /// Back navigation pops the peek page if Navigator has more than one page.
+        /// If Navigator has only one page, then the current program is exited.
         /// </summary>
         /// <param name="eventArgs">The back navigation information.</param>
         [EditorBrowsable(EditorBrowsableState.Never)]
@@ -849,8 +906,14 @@ namespace Tizen.NUI.Components
         {
             if (PageCount >= 1)
             {
-                Tizen.Log.Info("NUI", $"Navigator pops the peek page.\n");
-                Pop();
+                if (Peek().EnableBackNavigation)
+                {
+                    Peek().NavigateBack();
+                }
+            }
+            else
+            {
+                NUIApplication.Current?.Exit();
             }
         }
 
@@ -935,7 +998,16 @@ namespace Tizen.NUI.Components
 
             if (!pushTransition || newTopPage is DialogPage == false)
             {
-                View transitionView = (currentTopPage is ContentPage) ? (currentTopPage as ContentPage).Content : (currentTopPage as DialogPage).Content;
+                View transitionView = currentTopPage;
+                if (currentTopPage is ContentPage)
+                {
+                    transitionView = (currentTopPage as ContentPage).Content;
+                }
+                else if (currentTopPage is DialogPage)
+                {
+                    transitionView = (currentTopPage as DialogPage).Content;
+                }
+
                 if (currentTopPage.DisappearingTransition != null && transitionView != null)
                 {
                     TransitionItemBase disappearingTransition = currentTopPage.DisappearingTransition.CreateTransition(transitionView, false);
@@ -949,7 +1021,16 @@ namespace Tizen.NUI.Components
             }
             if (pushTransition || currentTopPage is DialogPage == false)
             {
-                View transitionView = (newTopPage is ContentPage) ? (newTopPage as ContentPage).Content : (newTopPage as DialogPage).Content;
+                View transitionView = newTopPage;
+                if (newTopPage is ContentPage)
+                {
+                    transitionView = (newTopPage as ContentPage).Content;
+                }
+                else if (newTopPage is DialogPage)
+                {
+                    transitionView = (newTopPage as DialogPage).Content;
+                }
+
                 if (newTopPage.AppearingTransition != null && transitionView != null)
                 {
                     TransitionItemBase appearingTransition = newTopPage.AppearingTransition.CreateTransition(transitionView, true);
@@ -1024,17 +1105,50 @@ namespace Tizen.NUI.Components
         //TODO: The following transition codes will be replaced with view transition.
         private void InitializeAnimation()
         {
+            bool isCurAnimPlaying = false;
+            bool isNewAnimPlaying = false;
+
             if (curAnimation != null)
             {
-                curAnimation.Stop();
+                if (curAnimation.State == Animation.States.Playing)
+                {
+                    isCurAnimPlaying = true;
+                    curAnimation.Stop();
+                }
+            }
+
+            if (newAnimation != null)
+            {
+                if (newAnimation.State == Animation.States.Playing)
+                {
+                    isNewAnimPlaying = true;
+                    newAnimation.Stop();
+                }
+            }
+
+            if (isCurAnimPlaying)
+            {
+                // To enable multiple Pop(), animation's Finished callback is required.
+                // To call animation's Finished callback, FinishedSignal is emitted.
+                curAnimation.FinishedSignal().Emit(curAnimation);
                 curAnimation.Clear();
+
+                // InitializeAnimation() can be called by FinishedSignal().Emit().
+                // Not to cause null pointer dereference by calling InitializeAnimation() in InitializeAnimation(),
+                // animation handle is assigned to be null only if the animation is playing.
                 curAnimation = null;
             }
 
-            if (newAnimation != null)
+            if (isNewAnimPlaying)
             {
-                newAnimation.Stop();
+                // To enable multiple Pop(), animation's Finished callback is required.
+                // To call animation's Finished callback, FinishedSignal is emitted.
+                newAnimation.FinishedSignal().Emit(newAnimation);
                 newAnimation.Clear();
+
+                // InitializeAnimation() can be called by FinishedSignal().Emit().
+                // Not to cause null pointer dereference by calling InitializeAnimation() in InitializeAnimation(),
+                // animation handle is assigned to be null only if the animation is playing.
                 newAnimation = null;
             }
         }