summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Core/NavigationProxy.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Core/NavigationProxy.cs')
-rw-r--r--Xamarin.Forms.Core/NavigationProxy.cs233
1 files changed, 233 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core/NavigationProxy.cs b/Xamarin.Forms.Core/NavigationProxy.cs
new file mode 100644
index 00000000..65e2fee9
--- /dev/null
+++ b/Xamarin.Forms.Core/NavigationProxy.cs
@@ -0,0 +1,233 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Xamarin.Forms
+{
+ internal class NavigationProxy : INavigation
+ {
+ INavigation _inner;
+ Lazy<List<Page>> _modalStack = new Lazy<List<Page>>(() => new List<Page>());
+
+ Lazy<List<Page>> _pushStack = new Lazy<List<Page>>(() => new List<Page>());
+
+ public INavigation Inner
+ {
+ get { return _inner; }
+ set
+ {
+ if (_inner == value)
+ return;
+ _inner = value;
+ // reverse so that things go into the new stack in the same order
+ // null out to release memory that will likely never be needed again
+
+ if (ReferenceEquals(_inner, null))
+ {
+ _pushStack = new Lazy<List<Page>>(() => new List<Page>());
+ _modalStack = new Lazy<List<Page>>(() => new List<Page>());
+ }
+ else
+ {
+ if (_pushStack != null && _pushStack.IsValueCreated)
+ {
+ foreach (Page page in _pushStack.Value)
+ {
+ _inner.PushAsync(page);
+ }
+ }
+
+ if (_modalStack != null && _modalStack.IsValueCreated)
+ {
+ foreach (Page page in _modalStack.Value)
+ {
+ _inner.PushModalAsync(page);
+ }
+ }
+
+ _pushStack = null;
+ _modalStack = null;
+ }
+ }
+ }
+
+ public void InsertPageBefore(Page page, Page before)
+ {
+ OnInsertPageBefore(page, before);
+ }
+
+ public IReadOnlyList<Page> ModalStack
+ {
+ get { return GetModalStack(); }
+ }
+
+ public IReadOnlyList<Page> NavigationStack
+ {
+ get { return GetNavigationStack(); }
+ }
+
+ public Task<Page> PopAsync()
+ {
+ return OnPopAsync(true);
+ }
+
+ public Task<Page> PopAsync(bool animated)
+ {
+ return OnPopAsync(animated);
+ }
+
+ public Task<Page> PopModalAsync()
+ {
+ return OnPopModal(true);
+ }
+
+ public Task<Page> PopModalAsync(bool animated)
+ {
+ return OnPopModal(animated);
+ }
+
+ public Task PopToRootAsync()
+ {
+ return OnPopToRootAsync(true);
+ }
+
+ public Task PopToRootAsync(bool animated)
+ {
+ return OnPopToRootAsync(animated);
+ }
+
+ public Task PushAsync(Page root)
+ {
+ return PushAsync(root, true);
+ }
+
+ public Task PushAsync(Page root, bool animated)
+ {
+ if (root.RealParent != null)
+ throw new InvalidOperationException("Page must not already have a parent.");
+ return OnPushAsync(root, animated);
+ }
+
+ public Task PushModalAsync(Page modal)
+ {
+ return PushModalAsync(modal, true);
+ }
+
+ public Task PushModalAsync(Page modal, bool animated)
+ {
+ if (modal.RealParent != null)
+ throw new InvalidOperationException("Page must not already have a parent.");
+ return OnPushModal(modal, animated);
+ }
+
+ public void RemovePage(Page page)
+ {
+ OnRemovePage(page);
+ }
+
+ protected virtual IReadOnlyList<Page> GetModalStack()
+ {
+ INavigation currentInner = Inner;
+ return currentInner == null ? _modalStack.Value : currentInner.ModalStack;
+ }
+
+ protected virtual IReadOnlyList<Page> GetNavigationStack()
+ {
+ INavigation currentInner = Inner;
+ return currentInner == null ? _pushStack.Value : currentInner.NavigationStack;
+ }
+
+ protected virtual void OnInsertPageBefore(Page page, Page before)
+ {
+ INavigation currentInner = Inner;
+ if (currentInner == null)
+ {
+ int index = _pushStack.Value.IndexOf(before);
+ if (index == -1)
+ throw new ArgumentException("before must be in the pushed stack of the current context");
+ _pushStack.Value.Insert(index, page);
+ }
+ else
+ {
+ currentInner.InsertPageBefore(page, before);
+ }
+ }
+
+ protected virtual Task<Page> OnPopAsync(bool animated)
+ {
+ INavigation inner = Inner;
+ return inner == null ? Task.FromResult(Pop()) : inner.PopAsync(animated);
+ }
+
+ protected virtual Task<Page> OnPopModal(bool animated)
+ {
+ INavigation innerNav = Inner;
+ return innerNav == null ? Task.FromResult(PopModal()) : innerNav.PopModalAsync(animated);
+ }
+
+ protected virtual Task OnPopToRootAsync(bool animated)
+ {
+ INavigation currentInner = Inner;
+ if (currentInner == null)
+ {
+ Page root = _pushStack.Value.Last();
+ _pushStack.Value.Clear();
+ _pushStack.Value.Add(root);
+ return Task.FromResult(root);
+ }
+ return currentInner.PopToRootAsync(animated);
+ }
+
+ protected virtual Task OnPushAsync(Page page, bool animated)
+ {
+ INavigation currentInner = Inner;
+ if (currentInner == null)
+ {
+ _pushStack.Value.Add(page);
+ return Task.FromResult(page);
+ }
+ return currentInner.PushAsync(page, animated);
+ }
+
+ protected virtual Task OnPushModal(Page modal, bool animated)
+ {
+ INavigation currentInner = Inner;
+ if (currentInner == null)
+ {
+ _modalStack.Value.Add(modal);
+ return Task.FromResult<object>(null);
+ }
+ return currentInner.PushModalAsync(modal, animated);
+ }
+
+ protected virtual void OnRemovePage(Page page)
+ {
+ INavigation currentInner = Inner;
+ if (currentInner == null)
+ {
+ _pushStack.Value.Remove(page);
+ }
+ else
+ {
+ currentInner.RemovePage(page);
+ }
+ }
+
+ Page Pop()
+ {
+ List<Page> list = _pushStack.Value;
+ Page result = list[list.Count - 1];
+ list.RemoveAt(list.Count - 1);
+ return result;
+ }
+
+ Page PopModal()
+ {
+ List<Page> list = _modalStack.Value;
+ Page result = list[list.Count - 1];
+ list.RemoveAt(list.Count - 1);
+ return result;
+ }
+ }
+} \ No newline at end of file