Support new features of Tizen.CircularUI (#188)
[platform/core/csapi/xsf.git] / src / XSF / Tizen.Wearable.CircularUI.Forms.Renderer / Shell / ShellRenderer.cs
1 using ElmSharp;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using Xamarin.Forms;
6 using Xamarin.Forms.Platform.Tizen;
7 using XForms = Xamarin.Forms.Forms;
8 using XShell = Xamarin.Forms.Shell;
9 using Tizen.Wearable.CircularUI.Forms;
10
11 [assembly: ExportRenderer(typeof(CircularShell), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.ShellRenderer))]
12 namespace Tizen.Wearable.CircularUI.Forms.Renderer
13 {
14     public class ShellRenderer : VisualElementRenderer<XShell>
15     {
16         NavigationDrawer _drawer;
17         NavigationView _navigationView;
18
19         Dictionary<BaseShellItem, IShellItemRenderer> _rendererCache = new Dictionary<BaseShellItem, IShellItemRenderer>();
20
21         public ShellRenderer()
22         {
23             RegisterPropertyHandler(XShell.CurrentItemProperty, UpdateCurrentItem);
24             RegisterPropertyHandler(XShell.FlyoutIsPresentedProperty, UpdateFlyoutIsPresented);
25             RegisterPropertyHandler(XShell.FlyoutBehaviorProperty, UpdateFlyoutBehavior);
26             RegisterPropertyHandler(XShell.FlyoutIconProperty, UpdateFlyoutIcon);
27             RegisterPropertyHandler(XShell.FlyoutBackgroundColorProperty, UpdateFlyoutBackgroundColor);
28             RegisterPropertyHandler(CircularShell.FlyoutIconBackgroundColorProperty, UpdateFlyoutIconBackgroundColor);
29             RegisterPropertyHandler(CircularShell.FlyoutForegroundColorProperty, UpdateFlyoutForegroundColor);
30         }
31
32         protected override void OnElementChanged(ElementChangedEventArgs<XShell> e)
33         {
34             InitializeComponent();
35             base.OnElementChanged(e);
36         }
37
38         protected override void OnElementReady()
39         {
40             base.OnElementReady();
41             UpdateFlyoutMenu();
42             (Element as IShellController).StructureChanged += OnNavigationStructureChanged;
43         }
44
45         protected override void Dispose(bool disposing)
46         {
47             if (disposing)
48             {
49                 foreach (var renderer in _rendererCache.Values)
50                 {
51                     renderer.Dispose();
52                 }
53                 (Element as IShellController).StructureChanged -= OnNavigationStructureChanged;
54             }
55             base.Dispose(disposing);
56         }
57
58         void InitializeComponent()
59         {
60             if (_drawer == null)
61             {
62                 _drawer = new NavigationDrawer(XForms.NativeParent);
63                 _drawer.IsOpen = Element.FlyoutIsPresented;
64                 _drawer.Toggled += OnNavigationDrawerToggled;
65                 SetNativeView(_drawer);
66             }
67         }
68
69         void OnNavigationStructureChanged(object sender, EventArgs e)
70         {
71             UpdateFlyoutMenu();
72         }
73
74         void UpdateFlyoutMenu()
75         {
76             if (Element.FlyoutBehavior == FlyoutBehavior.Disabled)
77                 return;
78
79             var flyoutItems = (Element as IShellController).GenerateFlyoutGrouping();
80             int itemCount = 0;
81             foreach (var item in flyoutItems)
82             {
83                 itemCount += item.Count;
84             }
85
86             if (itemCount > 1)
87             {
88                 InitializeNavigationDrawer();
89                 _navigationView.Build(flyoutItems);
90             }
91             else
92             {
93                 DeinitializeNavigationView();
94             }
95         }
96
97         void InitializeNavigationDrawer()
98         {
99             if (_navigationView != null)
100             {
101                 return;
102             }
103
104             _navigationView = new NavigationView(XForms.NativeParent)
105             {
106                 AlignmentX = -1,
107                 AlignmentY = -1,
108                 WeightX = 1,
109                 WeightY = 1,
110             };
111             _navigationView.Show();
112             _navigationView.ItemSelected += OnMenuItemSelected;
113
114             _drawer.SetDrawerContent(_navigationView);
115         }
116
117         void OnNavigationDrawerToggled(object sender, EventArgs e)
118         {
119             if (_drawer.IsOpen)
120             {
121                 _navigationView.Activate();
122             }
123             else
124             {
125                 _navigationView.Deactivate();
126
127                 var stack = (Element.CurrentItem.CurrentItem as ShellSection)?.Stack;
128                 var currentPage = stack?.LastOrDefault<Page>();
129
130                 if (currentPage == null)
131                 {
132                    currentPage = (Element.CurrentItem.CurrentItem.CurrentItem as IShellContentController)?.Page;
133                 }
134
135                 if (currentPage != null)
136                 {
137                     var renderer = Platform.GetOrCreateRenderer(currentPage);
138                     (renderer as CirclePageRenderer)?.UpdateRotaryFocusObject();
139                 }
140             }
141
142             Element.SetValueFromRenderer(XShell.FlyoutIsPresentedProperty, _drawer.IsOpen);
143         }
144
145         void DeinitializeNavigationView()
146         {
147             if (_navigationView == null)
148                 return;
149             _drawer.SetDrawerContent(null);
150             _navigationView.Unrealize();
151             _navigationView = null;
152         }
153
154         void OnMenuItemSelected(object sender, SelectedItemChangedEventArgs e)
155         {
156             ((IShellController)Element).OnFlyoutItemSelected(e.SelectedItem as Element);
157         }
158
159         void UpdateCurrentItem()
160         {
161             ResetCurrentItem();
162             if (Element.CurrentItem != null)
163             {
164                 if (!_rendererCache.TryGetValue(Element.CurrentItem, out IShellItemRenderer renderer))
165                 {
166                     renderer = ShellRendererFactory.Default.CreateItemRenderer(Element.CurrentItem);
167                     _rendererCache[Element.CurrentItem] = renderer;
168                 }
169                 SetCurrentItem(renderer.NativeView);
170             }
171         }
172
173         void UpdateFlyoutBehavior(bool init)
174         {
175             if (init)
176                 return;
177
178             if (Element.FlyoutBehavior == FlyoutBehavior.Disabled)
179             {
180                 DeinitializeNavigationView();
181             }
182             else if (Element.FlyoutBehavior == FlyoutBehavior.Flyout)
183             {
184                 UpdateFlyoutMenu();
185             }
186             else if (Element.FlyoutBehavior == FlyoutBehavior.Locked)
187             {
188                 // Locked behavior is not supported on circularshell
189             }
190         }
191
192         void UpdateFlyoutIcon(bool init)
193         {
194             if (init && Element.FlyoutIcon == null)
195                 return;
196
197             _drawer.UpdateDrawerIcon(Element.FlyoutIcon);
198         }
199
200         void UpdateFlyoutBackgroundColor(bool init)
201         {
202             if (init && Element.FlyoutBackgroundColor.IsDefault)
203                 return;
204
205             if (_navigationView != null)
206             {
207                 _navigationView.BackgroundColor = Element.FlyoutBackgroundColor.ToNative();
208             }
209         }
210
211         void UpdateFlyoutForegroundColor(bool init)
212         {
213             if (init && CircularShell.GetFlyoutForegroundColor(Element).IsDefault)
214                 return;
215
216             if (_navigationView != null)
217             {
218                 _navigationView.ForegroundColor = CircularShell.GetFlyoutForegroundColor(Element).ToNative();
219             }
220         }
221
222         void UpdateFlyoutIconBackgroundColor()
223         {
224             _drawer.HandlerBackgroundColor = CircularShell.GetFlyoutIconBackgroundColor(Element).ToNative();
225         }
226
227         void UpdateFlyoutIsPresented()
228         {
229             _drawer.IsOpen = Element.FlyoutIsPresented;
230         }
231
232         void SetCurrentItem(EvasObject item)
233         {
234             _drawer.SetMainContent(item);
235         }
236
237         void ResetCurrentItem()
238         {
239             _drawer.SetMainContent(null);
240         }
241     }
242 }