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