diff options
Diffstat (limited to 'Xamarin.Forms.Platform.Tizen/Renderers/NavigationPageRenderer.cs')
-rw-r--r-- | Xamarin.Forms.Platform.Tizen/Renderers/NavigationPageRenderer.cs | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/NavigationPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/NavigationPageRenderer.cs new file mode 100644 index 00000000..0d2ee2ed --- /dev/null +++ b/Xamarin.Forms.Platform.Tizen/Renderers/NavigationPageRenderer.cs @@ -0,0 +1,390 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using System.Collections.Generic; +using Xamarin.Forms.Internals; +using ElmSharp; +using EButton = ElmSharp.Button; + +namespace Xamarin.Forms.Platform.Tizen +{ + public class NavigationPageRenderer : VisualElementRenderer<NavigationPage>, IDisposable, IVisualElementRenderer + { + Naviframe _naviFrame = null; + Page _previousPage = null; + TaskCompletionSource<bool> _currentTaskSource = null; + const string _partBackButton = "elm.swallow.prev_btn"; + const string _leftToolbar = "title_left_btn"; + const string _rightToolbar = "title_right_btn"; + const string _defaultToolbarIcon = "naviframe/drawers"; + const string _partTitle = "default"; + const string _styleBackButton = "naviframe/back_btn/default"; + readonly List<Widget> _naviItemContentPartList = new List<Widget>(); + ToolbarTracker _toolbarTracker = null; + + public NavigationPageRenderer() + { + } + + protected override void Dispose(bool disposing) + { + _naviFrame.AnimationFinished -= AnimationFinishedHandler; + base.Dispose(disposing); + } + + protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e) + { + if (_naviFrame == null) + { + _naviFrame = new Naviframe(Forms.Context.MainWindow); + _naviFrame.PreserveContentOnPop = true; + _naviFrame.DefaultBackButtonEnabled = true; + _naviFrame.AnimationFinished += AnimationFinishedHandler; + + SetNativeControl(_naviFrame); + } + + if (_toolbarTracker == null) + { + _toolbarTracker = new ToolbarTracker(); + _toolbarTracker.CollectionChanged += ToolbarTrackerOnCollectionChanged; + } + + if (e.OldElement != null) + { + var navigation = e.OldElement as INavigationPageController; + navigation.PopRequested -= PopRequestedHandler; + navigation.PopToRootRequested -= PopToRootRequestedHandler; + navigation.PushRequested -= PushRequestedHandler; + navigation.RemovePageRequested -= RemovePageRequestedHandler; + navigation.InsertPageBeforeRequested -= InsertPageBeforeRequestedHandler; + + var pageController = e.OldElement as IPageController; + pageController.InternalChildren.CollectionChanged -= PageCollectionChangedHandler; + } + + if (e.NewElement != null) + { + var navigation = e.NewElement as INavigationPageController; + navigation.PopRequested += PopRequestedHandler; + navigation.PopToRootRequested += PopToRootRequestedHandler; + navigation.PushRequested += PushRequestedHandler; + navigation.RemovePageRequested += RemovePageRequestedHandler; + navigation.InsertPageBeforeRequested += InsertPageBeforeRequestedHandler; + + var pageController = e.NewElement as IPageController; + pageController.InternalChildren.CollectionChanged += PageCollectionChangedHandler; + + foreach (Page page in pageController.InternalChildren) + { + _naviFrame.Push(Platform.GetOrCreateRenderer(page).NativeView, SpanTitle(page.Title)); + page.PropertyChanged += NavigationBarPropertyChangedHandler; + + UpdateHasNavigationBar(page); + } + + _toolbarTracker.Target = e.NewElement; + _previousPage = e.NewElement.CurrentPage; + } + base.OnElementChanged(e); + } + + protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + base.OnElementPropertyChanged(sender, e); + + if (e.PropertyName == NavigationPage.CurrentPageProperty.PropertyName) + { + (_previousPage as IPageController)?.SendDisappearing(); + _previousPage = Element.CurrentPage; + (_previousPage as IPageController)?.SendAppearing(); + } + } + + void PageCollectionChangedHandler(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.OldItems != null) + foreach (Page page in e.OldItems) + page.PropertyChanged -= NavigationBarPropertyChangedHandler; + if (e.NewItems != null) + foreach (Page page in e.NewItems) + page.PropertyChanged += NavigationBarPropertyChangedHandler; + } + + void ToolbarTrackerOnCollectionChanged(object sender, EventArgs eventArgs) + { + UpdateToolbarItem(Element.CurrentPage); + } + + void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + // this handler is invoked only for child pages (contained on a navigation stack) + if (e.PropertyName == NavigationPage.HasNavigationBarProperty.PropertyName) + UpdateHasNavigationBar(sender as Page); + else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName || + e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) + UpdateHasBackButton(sender as Page); + else if (e.PropertyName == Page.TitleProperty.PropertyName || + e.PropertyName == NavigationPage.BarBackgroundColorProperty.PropertyName || + e.PropertyName == NavigationPage.BarTextColorProperty.PropertyName || + e.PropertyName == NavigationPage.TintProperty.PropertyName) + UpdateTitle(sender as Page); + } + + void UpdateHasNavigationBar(Page page) + { + NaviItem item = GetNaviItemForPage(page); + item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty); + UpdateToolbarItem(page, item); + } + + void UpdateToolbarItem(Page page, NaviItem item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + if (_naviFrame.NavigationStack.Count == 0 || item == null || item != _naviFrame.NavigationStack.Last()) + return; + + item.SetPartContent(_leftToolbar, null, false); + item.SetPartContent(_rightToolbar, null, false); + + Native.Button rightButton = GetToolbarButtonIfExists(ToolbarItemOrder.Primary); + item.SetPartContent(_rightToolbar, rightButton); + + Native.Button leftButton = GetToolbarButtonIfExists(ToolbarItemOrder.Secondary); + if (leftButton == null) + UpdateHasBackButton(page, item); + else + item.SetPartContent(_leftToolbar, leftButton); + } + + void UpdateHasBackButton(Page page, NaviItem item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + EButton button = null; + + if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty)) + button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty)); + item.SetPartContent(_partBackButton, button); + } + + void UpdateTitle(Page page) + { + NaviItem item = GetNaviItemForPage(page); + item.SetPartText(_partTitle, SpanTitle(page.Title)); + } + + string SpanTitle(string Title) + { + Native.Span span = new Native.Span { Text = Title }; + if (Element.BarTextColor != Color.Default) + { + span.ForegroundColor = Element.BarTextColor.ToNative(); + } + //TODO: changes only background of title not all bar + if (Element.BarBackgroundColor != Color.Default) + { + span.BackgroundColor = Element.BarBackgroundColor.ToNative(); + } + else if (Element.Tint != Color.Default) + { + //TODO: This is only for backward compatibility + //- remove when Tint is no longer in Xamarin API + span.BackgroundColor = Element.Tint.ToNative(); + } + return span.GetMarkupText(); + } + + EButton CreateNavigationButton(string text) + { + EButton button = new EButton(Forms.Context.MainWindow); + button.Clicked += (sender, e) => + { + if (!Element.SendBackButtonPressed()) + Forms.Context.Exit(); + }; + + button.Style = _styleBackButton; + button.Text = text; + + _naviItemContentPartList.Add(button); + button.Deleted += NaviItemPartContentDeletedHandler; + + return button; + } + + void NaviItemPartContentDeletedHandler(object sender, EventArgs e) + { + _naviItemContentPartList.Remove(sender as Widget); + } + + NaviItem GetNaviItemForPage(Page page) + { + NaviItem item = null; + + if (page != null) + { + IVisualElementRenderer renderer = Platform.GetRenderer(page); + if (renderer != null) + { + EvasObject content = renderer.NativeView; + + for (int i = _naviFrame.NavigationStack.Count - 1; i >= 0; --i) + if (_naviFrame.NavigationStack[i].Content == content) + { + item = _naviFrame.NavigationStack[i]; + break; + } + } + } + return item; + } + + Native.Button GetToolbarButtonIfExists(ToolbarItemOrder order) + { + ToolbarItem item = _toolbarTracker.ToolbarItems.Where( + (i => i.Order == order || + (order == ToolbarItemOrder.Primary && i.Order == ToolbarItemOrder.Default))) + .OrderBy(i => i.Priority) + .FirstOrDefault(); + + if (item != default(ToolbarItem)) + { + return GetToolbarButton(item); + } + return null; + } + + Native.Button GetToolbarButton(ToolbarItem item) + { + Native.Button button = new Native.Button(Forms.Context.MainWindow); + button.Clicked += (s, e) => + { + IMenuItemController control = item; + control.Activate(); + }; + button.Text = item.Text; + button.BackgroundColor = Xamarin.Forms.Color.Transparent.ToNative(); + + if (String.IsNullOrEmpty(item.Icon) && String.IsNullOrEmpty(item.Text)) + { + button.Style = _defaultToolbarIcon; + } + else + { + Native.Image iconImage = new Native.Image(Forms.Context.MainWindow); + iconImage.LoadFromImageSourceAsync(item.Icon); + button.Image = iconImage; + } + + return button; + } + + void PopRequestedHandler(object sender, NavigationRequestedEventArgs nre) + { + if ((Element as IPageController).InternalChildren.Count == _naviFrame.NavigationStack.Count) + { + if (nre.Animated) + { + _naviFrame.Pop(); + + _currentTaskSource = new TaskCompletionSource<bool>(); + nre.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after Pop the last page + if (_naviFrame.NavigationStack.Count == 0) + CompleteCurrentNavigationTask(); + } + else + _naviFrame.NavigationStack.Last().Delete(); + } + } + + void PopToRootRequestedHandler(object sender, NavigationRequestedEventArgs nre) + { + List<NaviItem> copyOfStack = new List<NaviItem>(_naviFrame.NavigationStack); + copyOfStack.Reverse(); + NaviItem topItem = copyOfStack.FirstOrDefault(); + NaviItem rootItem = copyOfStack.LastOrDefault(); + + foreach (NaviItem naviItem in copyOfStack) + if (naviItem != rootItem && naviItem != topItem) + naviItem.Delete(); + + if (topItem != rootItem) + { + if (nre.Animated) + { + _naviFrame.Pop(); + + _currentTaskSource = new TaskCompletionSource<bool>(); + nre.Task = _currentTaskSource.Task; + } + else + topItem.Delete(); + } + } + + void PushRequestedHandler(object sender, NavigationRequestedEventArgs nre) + { + if (nre.Animated || _naviFrame.NavigationStack.Count == 0) + { + _naviFrame.Push(Platform.GetOrCreateRenderer(nre.Page).NativeView, SpanTitle(nre.Page.Title)); + _currentTaskSource = new TaskCompletionSource<bool>(); + nre.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after the first Push + if (_naviFrame.NavigationStack.Count == 1) + CompleteCurrentNavigationTask(); + } + else + _naviFrame.InsertAfter(_naviFrame.NavigationStack.Last(), Platform.GetOrCreateRenderer(nre.Page).NativeView, SpanTitle(nre.Page.Title)); + + UpdateHasNavigationBar(nre.Page); + } + + void RemovePageRequestedHandler(object sender, NavigationRequestedEventArgs nre) + { + GetNaviItemForPage(nre.Page).Delete(); + } + + async void InsertPageBeforeRequestedHandler(object sender, NavigationRequestedEventArgs nre) + { + TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); + if (Element.CurrentNavigationTask != null && !Element.CurrentNavigationTask.IsCompleted) + { + await Element.CurrentNavigationTask; + } + Element.CurrentNavigationTask = tcs.Task; + + Device.StartTimer(TimeSpan.FromMilliseconds(0), () => + { + EvasObject page = Platform.GetOrCreateRenderer(nre.Page).NativeView; + _naviFrame.InsertBefore(GetNaviItemForPage(nre.BeforePage), page, SpanTitle(nre.Page.Title)); + tcs.SetResult(true); + + UpdateHasNavigationBar(nre.Page); + + return false; + }); + } + + void AnimationFinishedHandler(object sender, EventArgs e) + { + CompleteCurrentNavigationTask(); + } + + void CompleteCurrentNavigationTask() + { + if (_currentTaskSource != null) + { + var tmp = _currentTaskSource; + _currentTaskSource = null; + tmp.SetResult(true); + } + } + } +} |