[NUI] Split NUI Assemblies (#865)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Xaml / src / internal / XamlBinding / NavigationProxy.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Threading.Tasks;
5 using Tizen.NUI.Xaml;
6
7 namespace Tizen.NUI.XamlBinding
8 {
9     /// <summary>
10     /// For internal use.
11     /// </summary>
12     internal class NavigationProxy : INavigation
13     {
14         INavigation _inner;
15         Lazy<List<Page>> _modalStack = new Lazy<List<Page>>(() => new List<Page>());
16
17         Lazy<List<Page>> _pushStack = new Lazy<List<Page>>(() => new List<Page>());
18
19         internal INavigation Inner
20         {
21             get { return _inner; }
22             set
23             {
24                 if (_inner == value)
25                     return;
26                 _inner = value;
27                 // reverse so that things go into the new stack in the same order
28                 // null out to release memory that will likely never be needed again
29
30                 if (ReferenceEquals(_inner, null))
31                 {
32                     _pushStack = new Lazy<List<Page>>(() => new List<Page>());
33                     _modalStack = new Lazy<List<Page>>(() => new List<Page>());
34                 }
35                 else
36                 {
37                     if (_pushStack != null && _pushStack.IsValueCreated)
38                     {
39                         foreach (Page page in _pushStack.Value)
40                         {
41                             _inner.PushAsync(page);
42                         }
43                     }
44
45                     if (_modalStack != null && _modalStack.IsValueCreated)
46                     {
47                         foreach (Page page in _modalStack.Value)
48                         {
49                             _inner.PushModalAsync(page);
50                         }
51                     }
52
53                     _pushStack = null;
54                     _modalStack = null;
55                 }
56             }
57         }
58
59         /// <summary>
60         /// Inserts a page in the navigation stack before an existing page in the stack.
61         /// </summary>
62         /// <param name="page">The page to add.</param>
63         /// <param name="before">The existing page, before which page will be inserted.</param>
64         public void InsertPageBefore(Page page, Page before)
65         {
66             OnInsertPageBefore(page, before);
67         }
68
69         /// <summary>
70         /// Gets the modal navigation stack.
71         /// </summary>
72         public IReadOnlyList<Page> ModalStack
73         {
74             get { return GetModalStack(); }
75         }
76
77         /// <summary>
78         /// Gets the stack of pages in the navigation.
79         /// </summary>
80         public IReadOnlyList<Page> NavigationStack
81         {
82             get { return GetNavigationStack(); }
83         }
84
85         /// <summary>
86         /// Asynchronously removes the most recent Page from the navigation stack.
87         /// </summary>
88         /// <returns>The Page that had been at the top of the navigation stack.</returns>
89         public Task<Page> PopAsync()
90         {
91             return OnPopAsync(true);
92         }
93
94         /// <summary>
95         /// Asynchronously removes the top Page from the navigation stack, with optional animation.
96         /// </summary>
97         /// <param name="animated">Whether to animate the pop.</param>
98         /// <returns>The Page that had been at the top of the navigation stack.</returns>
99         public Task<Page> PopAsync(bool animated)
100         {
101             return OnPopAsync(animated);
102         }
103
104         /// <summary>
105         /// Asynchronously dismisses the most recent modally presented Page.
106         /// </summary>
107         /// <returns>An awaitable instance, indicating the PopModalAsync completion. The Task.Result is the Page that has been popped.</returns>
108         public Task<Page> PopModalAsync()
109         {
110             return OnPopModal(true);
111         }
112
113         /// <summary>
114         /// Asynchronously removes the top Page from the navigation stack, with optional animation.
115         /// </summary>
116         /// <param name="animated">Whether to animate the pop.</param>
117         /// <returns>The Page that had been at the top of the navigation stack.</returns>
118         public Task<Page> PopModalAsync(bool animated)
119         {
120             return OnPopModal(animated);
121         }
122
123         /// <summary>
124         /// Pops all but the root Page off the navigation stack.
125         /// </summary>
126         /// <returns>A task representing the asynchronous dismiss operation.</returns>
127         public Task PopToRootAsync()
128         {
129             return OnPopToRootAsync(true);
130         }
131
132         /// <summary>
133         /// Pops all but the root Page off the navigation stack, with optional animation.
134         /// </summary>
135         /// <param name="animated">Whether to animate the pop.</param>
136         /// <returns>A task representing the asynchronous dismiss operation.</returns>
137         public Task PopToRootAsync(bool animated)
138         {
139             return OnPopToRootAsync(animated);
140         }
141
142         /// <summary>
143         /// Asynchronously adds a Page to the top of the navigation stack.
144         /// </summary>
145         /// <param name="root">The Page to be pushed on top of the navigation stack.</param>
146         /// <returns>A task that represents the asynchronous push operation.</returns>
147         public Task PushAsync(Page root)
148         {
149             return PushAsync(root, true);
150         }
151
152         /// <summary>
153         /// Asynchronously adds a Page to the top of the navigation stack, with optional animation.
154         /// </summary>
155         /// <param name="root">The page to push.</param>
156         /// <param name="animated">Whether to animate the push.</param>
157         /// <returns>A task that represents the asynchronous push operation.</returns>
158         public Task PushAsync(Page root, bool animated)
159         {
160             if (root.RealParent != null)
161                 throw new InvalidOperationException("Page must not already have a parent.");
162             return OnPushAsync(root, animated);
163         }
164
165         /// <summary>
166         /// Presents a Page modally.
167         /// </summary>
168         /// <param name="modal">The Page to present modally.</param>
169         /// <returns>An awaitable Task, indicating the PushModal completion.</returns>
170         public Task PushModalAsync(Page modal)
171         {
172             return PushModalAsync(modal, true);
173         }
174
175         /// <summary>
176         /// Presents a Page modally, with optional animation.
177         /// </summary>
178         /// <param name="modal">The page to push.</param>
179         /// <param name="animated">Whether to animate the push.</param>
180         /// <returns>An awaitable Task, indicating the PushModal completion.</returns>
181         public Task PushModalAsync(Page modal, bool animated)
182         {
183             if (modal.RealParent != null)
184                 throw new InvalidOperationException("Page must not already have a parent.");
185             return OnPushModal(modal, animated);
186         }
187
188         /// <summary>
189         /// Removes the specified page from the navigation stack.
190         /// </summary>
191         /// <param name="page">The page to remove.</param>
192         public void RemovePage(Page page)
193         {
194             OnRemovePage(page);
195         }
196
197         /// <summary>
198         /// For internal use. Returns the modal navigation stack.
199         /// </summary>
200         /// <returns>The modal navigation stack.</returns>
201         protected virtual IReadOnlyList<Page> GetModalStack()
202         {
203             INavigation currentInner = Inner;
204             return currentInner == null ? _modalStack.Value : currentInner.ModalStack;
205         }
206
207         /// <summary>
208         /// For internal use. Returns the stack of pages in the navigation.
209         /// </summary>
210         /// <returns>The stack of pages in the navigation.</returns>
211         protected virtual IReadOnlyList<Page> GetNavigationStack()
212         {
213             INavigation currentInner = Inner;
214             return currentInner == null ? _pushStack.Value : currentInner.NavigationStack;
215         }
216
217         /// <summary>
218         /// The method called when insert a page in the navigation stack before an existing page in the stack.
219         /// </summary>
220         /// <param name="page">The page to add.</param>
221         /// <param name="before">The existing page, before which page will be inserted.</param>
222         protected virtual void OnInsertPageBefore(Page page, Page before)
223         {
224             INavigation currentInner = Inner;
225             if (currentInner == null)
226             {
227                 int index = _pushStack.Value.IndexOf(before);
228                 if (index == -1)
229                     throw new ArgumentException("before must be in the pushed stack of the current context");
230                 _pushStack.Value.Insert(index, page);
231             }
232             else
233             {
234                 currentInner.InsertPageBefore(page, before);
235             }
236         }
237
238         /// <summary>
239         /// This method calls when removes the top Page from the navigation stack
240         /// </summary>
241         /// <param name="animated">Whether to animate the pop.</param>
242         /// <returns></returns>
243         protected virtual Task<Page> OnPopAsync(bool animated)
244         {
245             INavigation inner = Inner;
246             return inner == null ? Task.FromResult(Pop()) : inner.PopAsync(animated);
247         }
248
249         /// <summary>
250         /// This method calls when removes the top Page from the navigation stack
251         /// </summary>
252         /// <param name="animated">Whether to animate the pop.</param>
253         /// <returns>An awaitable instance, indicating the PopModalAsync completion</returns>
254         protected virtual Task<Page> OnPopModal(bool animated)
255         {
256             INavigation innerNav = Inner;
257             return innerNav == null ? Task.FromResult(PopModal()) : innerNav.PopModalAsync(animated);
258         }
259
260         /// <summary>
261         /// This method calls when Pops all but the root Page off the navigation stack.
262         /// </summary>
263         /// <param name="animated">Whether to animate the pop.</param>
264         /// <returns>A task representing the asynchronous dismiss operation.</returns>
265         protected virtual Task OnPopToRootAsync(bool animated)
266         {
267             INavigation currentInner = Inner;
268             if (currentInner == null)
269             {
270                 Page root = _pushStack.Value.Last();
271                 _pushStack.Value.Clear();
272                 _pushStack.Value.Add(root);
273                 return Task.FromResult(root);
274             }
275             return currentInner.PopToRootAsync(animated);
276         }
277
278         /// <summary>
279         /// This method calls when adds a Page to the top of the navigation stack, with optional animation.
280         /// </summary>
281         /// <param name="page">The page to add</param>
282         /// <param name="animated">Whether to animate the pop.</param>
283         /// <returns>A task that represents the asynchronous push operation.</returns>
284         protected virtual Task OnPushAsync(Page page, bool animated)
285         {
286             INavigation currentInner = Inner;
287             if (currentInner == null)
288             {
289                 _pushStack.Value.Add(page);
290                 return Task.FromResult(page);
291             }
292             return currentInner.PushAsync(page, animated);
293         }
294
295         /// <summary>
296         /// This method calls when Presents a Page modally, with optional animation.
297         /// </summary>
298         /// <param name="modal">The page to push.</param>
299         /// <param name="animated">Whether to animate the pop.</param>
300         /// <returns>An awaitable Task, indicating the PushModal completion.</returns>
301         protected virtual Task OnPushModal(Page modal, bool animated)
302         {
303             INavigation currentInner = Inner;
304             if (currentInner == null)
305             {
306                 _modalStack.Value.Add(modal);
307                 return Task.FromResult<object>(null);
308             }
309             return currentInner.PushModalAsync(modal, animated);
310         }
311
312         /// <summary>
313         /// This method calls when Removes the specified page from the navigation stack.
314         /// </summary>
315         /// <param name="page">The page to add.</param>
316         protected virtual void OnRemovePage(Page page)
317         {
318             INavigation currentInner = Inner;
319             if (currentInner == null)
320             {
321                 _pushStack.Value.Remove(page);
322             }
323             else
324             {
325                 currentInner.RemovePage(page);
326             }
327         }
328
329         Page Pop()
330         {
331             List<Page> list = _pushStack.Value;
332             Page result = list[list.Count - 1];
333             list.RemoveAt(list.Count - 1);
334             return result;
335         }
336
337         Page PopModal()
338         {
339             List<Page> list = _modalStack.Value;
340             Page result = list[list.Count - 1];
341             list.RemoveAt(list.Count - 1);
342             return result;
343         }
344     }
345 }