From d66053d5ed9157111fe3998d05b07dd33d310bfe Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EC=9C=A0=EB=A6=AC=EB=82=98/Common=20Platform=20Lab=28SR=29?= =?utf8?q?/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 14 May 2020 08:37:12 -0400 Subject: [PATCH] Support new features of CircularUI based on 1.5.0 branch (#225) * Fix SVACE issues (#274) * Fix SVACE issues * Add guard for null exceptions * Make PageRenderer even better (#279) * Add WheelAppeared and WheelDisappeared events in CircleStepper (#282) * Fix IndexPage CurrentPage issue (#285) * Fix rotary event activation issue (#286) * Fix rotary event issue * Add TC * Add BezelInteractionPage (#298) * Add BezelInteractionPage * Apply code review * Deprecate the legacy APIs * Refactoring CircularShell Renderer * Update bezel interaction behavior (#299) * Refactoring CircularShell Renderer * Update bezel interaction behavior * Update OnMoreOptionOpened/Closed * Update CircleScrollViewRenderer (#300) * Update CircleScrollViewRenderer * Obsolete BarColor property in CircleScrollView * Update the CircleScrollViewRenderer (#301) * Update CircleStepperRenderer and CircleDateTimeSelectorRenderer (#296) * Update ActiveBezelInteractionElement on Activate bezel interaction (#302) * Update CircleListViewRenderer (#303) * Update CircleListViewRenderer * Apply Review comment * Remove unused ListViewCache * Update Bezel Intercation behavior on closing dialog (#304) * Merge 1.5.0 branch of CircularUI * Update Renderer to use disable rotary event on IBezelInteractionRoutor (#305) * Fix ExportRenderer (#306) * Meets alignment for all cs files --- .../BezelInteractionPageRenderer.cs | 207 ++++++++ .../CircleDateTimeSelectorRenderer.cs | 76 ++- .../CircleImageRenderer.cs | 11 +- .../CircleListView.cs | 457 ----------------- .../CircleListViewRenderer.cs | 227 +-------- .../CirclePageRenderer.cs | 414 ++++++++++++---- .../CircleScrollViewRenderer.cs | 241 +-------- .../CircleStepperRenderer.cs | 118 +---- .../CircleSurfaceViewRenderer.cs | 12 +- .../CircularUI.cs | 2 + .../CircularUIForms.cs | 2 +- .../CollectionViewRenderer.cs | 51 ++ .../DatePickerRenderer.cs | 25 + .../GoogleMapViewRenderer.cs | 8 +- .../IBezelInteractionController.cs | 26 + .../ICircleSurfaceItemRenderer.cs | 9 + .../IndexPageRenderer.cs | 7 +- .../InformationPopupImplementation.cs | 4 +- .../LayoutCanvas.cs | 10 +- .../ListViewCache.cs | 112 ----- .../ListViewRenderer.cs | 34 ++ .../NativeCirclePage.cs | 6 +- .../NativeFactory.cs | 36 +- .../ObservableBox.cs | 6 +- .../PageRenderer.cs | 38 ++ .../PopupEntryRenderer.cs | 1 + .../RadioRenderer.cs | 2 + .../ScrollViewRenderer.cs | 34 ++ .../Shell/CircularShellRenderer.cs | 78 +++ .../Shell/CircularShellRendererFactory.cs | 22 + .../Shell/CircularShellSectionItemsRenderer.cs | 34 ++ .../Shell/IShellItemRenderer.cs | 12 - .../Shell/NavigationDrawer.cs | 543 --------------------- .../Shell/NavigationView.cs | 365 -------------- .../Shell/ShellContentRenderer.cs | 40 -- .../Shell/ShellItemRenderer.cs | 97 ---- .../Shell/ShellRenderer.cs | 242 --------- .../Shell/ShellRendererFactory.cs | 53 -- .../Shell/ShellSectionItemsRenderer.cs | 290 ----------- .../Shell/ShellSectionNavigationRenderer.cs | 208 -------- .../StepperRenderer.cs | 34 ++ .../ThemeLoader.cs | 26 +- .../TimePickerRenderer.cs | 25 + .../TizenCircleSurfaceEffect.cs | 0 .../TwoButtonPopupImplementation.cs | 4 +- .../WatchListView.cs | 65 +++ .../BezelInteractionPage.cs | 56 +++ src/XSF/Tizen.Wearable.CircularUI.Forms/Check.cs | 1 + .../Tizen.Wearable.CircularUI.Forms/CirclePage.cs | 4 +- .../CircleScrollView.cs | 3 +- .../CircleStepper.cs | 31 ++ .../CircleSurfaceView.cs | 14 +- .../ContextPopupEffectBehavior.cs | 2 +- .../IBezelInteractionRouter.cs | 24 + .../Tizen.Wearable.CircularUI.Forms/IndexPage.cs | 2 + .../Tizen.Wearable.CircularUI.Forms/MediaPlayer.cs | 1 - .../Tizen.Wearable.CircularUI.Forms/MediaView.cs | 1 - src/XSF/Tizen.Wearable.CircularUI.Forms/Radio.cs | 1 + src/XSF/Xamarin.Forms.Core/Expander.cs | 2 +- src/XSF/Xamarin.Forms.Core/ExperimentalFlags.cs | 2 +- src/XSF/Xamarin.Forms.Core/OnAppTheme.cs | 2 +- .../Renderers/StepperRenderer.cs | 2 +- 62 files changed, 1293 insertions(+), 3169 deletions(-) create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/BezelInteractionPageRenderer.cs mode change 100755 => 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleImageRenderer.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListView.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CollectionViewRenderer.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/DatePickerRenderer.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/IBezelInteractionController.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ICircleSurfaceItemRenderer.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ListViewCache.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ListViewRenderer.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/PageRenderer.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ScrollViewRenderer.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellRenderer.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellRendererFactory.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellSectionItemsRenderer.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/IShellItemRenderer.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationDrawer.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationView.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellContentRenderer.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellItemRenderer.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRenderer.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRendererFactory.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionItemsRenderer.cs delete mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionNavigationRenderer.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/StepperRenderer.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TimePickerRenderer.cs mode change 100755 => 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TizenCircleSurfaceEffect.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/WatchListView.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms/BezelInteractionPage.cs create mode 100644 src/XSF/Tizen.Wearable.CircularUI.Forms/IBezelInteractionRouter.cs diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/BezelInteractionPageRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/BezelInteractionPageRenderer.cs new file mode 100644 index 0000000..88f03a1 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/BezelInteractionPageRenderer.cs @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using ElmSharp.Wearable; +using System; +using Tizen.Wearable.CircularUI.Forms; +using Xamarin.Forms; +using Xamarin.Forms.Platform.Tizen; +using ERotaryEventManager = ElmSharp.Wearable.RotaryEventManager; +using AppSpecific = Xamarin.Forms.PlatformConfiguration.TizenSpecific.Application; + +[assembly: ExportRenderer(typeof(BezelInteractionPage), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.BezelInteractionPageRenderer))] + +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class BezelInteractionPageRenderer : PageRenderer, IBezelInteractionController + { + IRotaryFocusable _currentRotaryFocusObject; + + new IBezelInteractionRouter Element => base.Element as IBezelInteractionRouter; + + public BezelInteractionPageRenderer() + { + RegisterPropertyHandler(BezelInteractionPage.RotaryFocusObjectProperty, UpdateRotaryFocusObject); + } + + IRotaryFocusable IBezelInteractionController.RotaryFocusObject => _currentRotaryFocusObject; + + void IBezelInteractionController.Activate() + { + ActivateRotaryWidget(); + } + + void IBezelInteractionController.Deactivate() + { + DeactivateRotaryWidget(); + } + + protected override void OnElementChanged(ElementChangedEventArgs e) + { + base.OnElementChanged(e); + e.NewElement.Appearing += OnPageAppearing; + e.NewElement.Disappearing += OnPageDisappearing; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + base.Element.Appearing -= OnPageAppearing; + base.Element.Disappearing -= OnPageDisappearing; + } + base.Dispose(disposing); + } + + protected override void OnElementReady() + { + base.OnElementReady(); + // A Page created by with ContentTemplate of ShellContent, was appered before create a renderer + // So need to call ActivateRotaryWidget() if page already appeared + if (Element.Appeared) + { + ActivateRotaryWidget(); + } + } + + protected override void OnMoreOptionClosed() + { + DeactivateRotaryWidget(); + } + + protected override void OnMoreOptionOpened() + { + ActivateRotaryWidget(); + } + + void UpdateRotaryFocusObject(bool initialize) + { + if (initialize) + { + _currentRotaryFocusObject = Element.RotaryFocusObject; + } + else + { + DeactivateRotaryWidget(); + _currentRotaryFocusObject = Element.RotaryFocusObject; + ActivateRotaryWidget(); + } + } + + void ActivateRotaryWidget() + { + if (!Element.Appeared) + return; + + if (_currentRotaryFocusObject is IRotaryEventReceiver) + { + ERotaryEventManager.Rotated += OnRotaryEventChanged; + } + else + { + GetRotaryWidget(_currentRotaryFocusObject)?.Activate(); + } + AppSpecific.SetActiveBezelInteractionElement(Application.Current, base.Element); + } + + void DeactivateRotaryWidget() + { + if (_currentRotaryFocusObject is IRotaryEventReceiver) + { + ERotaryEventManager.Rotated -= OnRotaryEventChanged; + } + else if (_currentRotaryFocusObject is IRotaryFocusable) + { + GetRotaryWidget(_currentRotaryFocusObject)?.Deactivate(); + } + if (AppSpecific.GetActiveBezelInteractionElement(Application.Current) == base.Element) + AppSpecific.SetActiveBezelInteractionElement(Application.Current, null); + } + + void OnPageDisappearing(object sender, EventArgs e) + { + DeactivateRotaryWidget(); + } + + void OnPageAppearing(object sender, EventArgs e) + { + ActivateRotaryWidget(); + } + + void OnRotaryEventChanged(ElmSharp.Wearable.RotaryEventArgs e) + { + if (_currentRotaryFocusObject is IRotaryEventReceiver receiver) + { + receiver.Rotate(new RotaryEventArgs { IsClockwise = e.IsClockwise }); + } + } + + IRotaryActionWidget GetRotaryWidget(IRotaryFocusable focusable) + { + IRotaryActionWidget rotaryWidget = null; + if (focusable is BindableObject consumer) + { + if (consumer is CircleSurfaceItem circleSlider) + { + rotaryWidget = GetCircleWidget(circleSlider) as IRotaryActionWidget; + } + else + { + rotaryWidget = Platform.GetRenderer(consumer)?.NativeView as IRotaryActionWidget; + } + } + return rotaryWidget; + } + + ICircleWidget GetCircleWidget(CircleSurfaceItem item) + { + if (item.Parent == null) + return null; + return (Platform.GetRenderer(item.Parent) as ICircleSurfaceItemRenderer)?.GetCircleWidget(item); + } + } + + public static class BezelInteractionExtension + { + public static IBezelInteractionRouter FindBezelRouter(this Element element) + { + while (element != null) + { + if (element is IBezelInteractionRouter router) + { + return router; + } + element = element.Parent; + } + return null; + } + + public static IBezelInteractionController FindBezelController(this Element element) + { + while (element != null) + { + if (element is IBezelInteractionRouter router) + { + return Platform.GetRenderer(element) as IBezelInteractionController; + } + element = element.Parent; + } + return null; + } + + } + +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleDateTimeSelectorRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleDateTimeSelectorRenderer.cs index 461ae10..c28a5ff 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleDateTimeSelectorRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleDateTimeSelectorRenderer.cs @@ -17,16 +17,17 @@ using System; using Xamarin.Forms; using Xamarin.Forms.Platform.Tizen; +using Xamarin.Forms.Platform.Tizen.Native; +using Xamarin.Forms.Platform.Tizen.Native.Watch; using XForms = Xamarin.Forms.Forms; -using ECircleDateTimeSelector = ElmSharp.Wearable.CircleDateTimeSelector; using EDateTimeFieldType = ElmSharp.DateTimeFieldType; -[assembly: ExportRenderer(typeof(Tizen.Wearable.CircularUI.Forms.CircleDateTimeSelector), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CircleDateTimeSelectorRenderer))] +[assembly: ExportRenderer(typeof(Tizen.Wearable.CircularUI.Forms.CircleDateTimeSelector), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CircleDateTimeSelectorRenderer))] namespace Tizen.Wearable.CircularUI.Forms.Renderer { - public class CircleDateTimeSelectorRenderer : ViewRenderer + public class CircleDateTimeSelectorRenderer : ViewRenderer { public CircleDateTimeSelectorRenderer() { @@ -53,7 +54,7 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer var surface = this.GetSurface(); if (null != surface) { - SetNativeControl(new ECircleDateTimeSelector(XForms.NativeParent, surface)); + SetNativeControl(new WatchDateTimePicker(XForms.NativeParent, surface)); Control.DateTimeChanged += OnDateTimeChanged; } else @@ -74,25 +75,27 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer return new ElmSharp.Size(300, 290); } - void UpdateMinimum() + protected override void UpdateRotaryInteraction(bool enable) { - if (null != Control && null != Element) + if (Element.FindBezelRouter() == null) { - Control.MinimumDateTime = Element.MinimumDate; + base.UpdateRotaryInteraction(enable); } } + void UpdateMinimum() + { + Control.MinimumDateTime = Element.MinimumDate; + } + void UpdateMaximum() { - if (null != Control && null != Element) - { Control.MaximumDateTime = Element.MaximumDate; } - } void UpdateDateTime() { - if (null != Control && null != Element && Element.DateTime != Control.DateTime) + if (Element.DateTime != Control.DateTime) { Control.DateTime = Element.DateTime; } @@ -100,25 +103,13 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer void UpdateValueType() { - if (null != Control && null != Element) - { - if (Element.ValueType == DateTimeType.Date) - { - Control.Style = "datepicker/circle"; - Control.Format = "%d/%b/%Y"; - } - else if (Element.ValueType == DateTimeType.Time) - { - Control.Style = "timepicker/circle"; - Control.Format = "%d/%b/%Y%I:%M%p"; - } - } + Control.Mode = Element.ValueType.ToNative(); } void UpdateMarkerColor() { #pragma warning disable CS0618 // MarkerColor is obsolete - if (null != Control && null != Element && Element.MarkerColor != Xamarin.Forms.Color.Default) + if (Element.MarkerColor != Xamarin.Forms.Color.Default) { Control.MarkerColor = Element.MarkerColor.ToNative(); } @@ -127,57 +118,52 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer void OnDateTimeChanged(object sender, EventArgs e) { - if (null != Control && null != Element) - { Element.DateTime = Control.DateTime; } - } void UpdateFieldVisibilityOfYear() { - if (null != Control && null != Element) - { Control.SetFieldVisible(EDateTimeFieldType.Year, Element.IsVisibleOfYear); } - } void UpdateFieldVisibilityOfMonth() { - if (null != Control && null != Element) - { Control.SetFieldVisible(EDateTimeFieldType.Month, Element.IsVisibleOfMonth); } - } void UpdateFieldVisibilityOfDate() { - if (null != Control && null != Element) - { Control.SetFieldVisible(EDateTimeFieldType.Date, Element.IsVisibleOfDate); } - } void UpdateFieldVisibilityOfHour() { - if (null != Control && null != Element) - { Control.SetFieldVisible(EDateTimeFieldType.Hour, Element.IsVisibleOfHour); } - } void UpdateFieldVisibilityOfMinute() { - if (null != Control && null != Element) + Control.SetFieldVisible(EDateTimeFieldType.Minute, Element.IsVisibleOfMinute); + } + + void UpdateFieldVisibilityOfAmPm() { - Control.SetFieldVisible(EDateTimeFieldType.Minute, Element.IsVisibleOfMinute); + Control.SetFieldVisible(EDateTimeFieldType.AmPm, Element.IsVisibleOfAmPm); } } - void UpdateFieldVisibilityOfAmPm() + internal static class DateTimeTypeEntensions + { + internal static DateTimePickerMode ToNative(this DateTimeType type) { - if (null != Control && null != Element) + switch (type) { - Control.SetFieldVisible(EDateTimeFieldType.AmPm, Element.IsVisibleOfAmPm); + case DateTimeType.Date: + return DateTimePickerMode.Date; + case DateTimeType.Time: + return DateTimePickerMode.Time; + default: + throw new NotImplementedException($"DateTimeType {type} not supported"); } } } diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleImageRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleImageRenderer.cs old mode 100755 new mode 100644 index aed0ebf..440bcfe --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleImageRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleImageRenderer.cs @@ -23,6 +23,7 @@ using Tizen.Wearable.CircularUI.Forms.Renderer; using Xamarin.Forms; using TLog = Tizen.Log; using FormsCircularUI = Tizen.Wearable.CircularUI.Forms.Renderer.FormsCircularUI; +using XForms = Xamarin.Forms.Forms; [assembly: ExportRenderer(typeof(CircleImage), typeof(CircleImageRenderer))] namespace Tizen.Wearable.CircularUI.Forms.Renderer @@ -30,18 +31,16 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer public class CircleImageRenderer : ViewRenderer { ElmSharp.EvasImage _circleImage; - ElmSharp.EvasObject _nativeParent; protected override void OnElementChanged(ElementChangedEventArgs e) { if (Control == null) { - _nativeParent = Platform.GetRenderer(Element.Parent).NativeView; - _circleImage = new ElmSharp.EvasImage(_nativeParent); + _circleImage = new ElmSharp.EvasImage(XForms.NativeParent); _circleImage.IsFilled = true; GetClipImage(); - var image = new FormsNative.Image(_nativeParent); + var image = new FormsNative.Image(XForms.NativeParent); SetNativeControl(image); Control.Resized += Control_Resized; Control.Moved += Control_Moved; @@ -141,12 +140,12 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer void UpdateBackgroundColor() { - if (_nativeParent == null) return; + if (Control == null) return; if (Element.BackgroundColor.ToNative() != ElmSharp.Color.Transparent && Element.BackgroundColor.ToNative() != ElmSharp.Color.Default) { - _nativeParent.Color = Element.BackgroundColor.ToNative(); + Control.Color = Element.BackgroundColor.ToNative(); } } diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListView.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListView.cs deleted file mode 100644 index fb06f79..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListView.cs +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Flora License, Version 1.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://floralicense.org/license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using ElmSharp.Wearable; -using System; -using System.Collections.Generic; -using Xamarin.Forms; -using ElmSharp; -using System.Collections; -using Xamarin.Forms.Platform.Tizen; -using Xamarin.Forms.Internals; -using System.ComponentModel; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - using GroupList = TemplatedItemsList, Cell>; - - public class CircleListView : CircleGenList - { - const int HeaderMinimumHeight = 115; - const int GroupHeaderMinimumHeight = 83; - - readonly Dictionary _itemContexts = new Dictionary(); - - VisualElement _header; - VisualElement _footer; - int _rowHeight; - - public CircleListView(EvasObject parent, CircleSurface surface) : base(parent, surface) - { - } - - public VisualElement Header - { - get => _header; - set - { - if (_header == value) return; - _header = value; - UpdateHeader(); - } - } - public VisualElement Footer - { - get => _footer; - set - { - if (_footer == value) return; - _footer = value; - UpdateFooter(); - } - } - - public int HeaderRowHeight - { - get => _rowHeight; - set - { - if (_rowHeight == value) return; - _rowHeight = value; - } - } - - public void ResetGroup(GroupList group) - { - GenListItem groupItem; - if (_itemContexts.TryGetValue(group.HeaderContent, out groupItem)) - { - groupItem.ClearSubitems(); - } - } - - public void AddSource(IEnumerable source) - { - UpdateHeader(); - foreach (var data in source) - { - var groupList = data as GroupList; - if (groupList != null) - { - AddGroup(groupList); - foreach (var item in groupList) - { - AddItem(item as Cell, groupList); - } - } - else - { - AddItem(data as Cell, null); - } - } - UpdateFooter(); - } - public void AddSource(IEnumerable source, Cell before) - { - foreach (var data in source) - { - var groupList = data as GroupList; - if (groupList != null) - { - InsertGroup(groupList, before); - foreach (var item in groupList) - { - AddItem(item as Cell, groupList); - } - } - else - { - InsertItem(data as Cell, before, null); - } - } - } - public void AddSource(IEnumerable source, GroupList group, Cell before) - { - foreach (var data in source) - { - InsertItem(data as Cell, before, group); - } - } - public void AddSource(IEnumerable source, GroupList group) - { - foreach (var data in source) - { - AddItem(data as Cell, group); - } - } - - public void RemoveSource(IEnumerable source) - { - foreach (var data in source) - { - if (data is GroupList) - Remove(data as GroupList); - else - Remove(data as Cell); - } - } - - public void ApplyScrollTo(Cell cell, Xamarin.Forms.ScrollToPosition position, bool animated) - { - GenListItem item; - if (_itemContexts.TryGetValue(cell, out item)) - { - ScrollTo(item, position.ToNative(), animated); - } - } - - public void ApplySelectedItem(Cell cell) - { - GenListItem item; - if (_itemContexts.TryGetValue(cell, out item)) - { - item.IsSelected = true; - } - } - - public void AddItem(Cell cell, GroupList group) - { - CellRenderer renderer = ListViewCache.Get(cell); - GenListItem groupItem = null; - if (group != null) - { - _itemContexts.TryGetValue(group.HeaderContent, out groupItem); - } - GenListItem item; - var lastCtx = LastItem?.Data as TypedItemContext; - if (lastCtx != null && (lastCtx.Type == ItemType.Footer || lastCtx.Type == ItemType.BottomPadding)) - { - item = InsertBefore(renderer.Class, new ListViewItemContext(cell, group), LastItem, GenListItemType.Normal, groupItem); - } - else - { - item = Append(renderer.Class, new ListViewItemContext(cell, group), GenListItemType.Normal, groupItem); - } - RegisterItem(cell, item); - } - public void InsertItem(Cell cell, Cell before, GroupList group) - { - CellRenderer renderer = ListViewCache.Get(cell); - GenListItem groupItem = null; - if (group != null) - { - _itemContexts.TryGetValue(group.HeaderContent, out groupItem); - } - _itemContexts.TryGetValue(before, out GenListItem beforeItem); - var item = InsertBefore(renderer.Class, new ListViewItemContext(cell, group), beforeItem, GenListItemType.Normal, groupItem); - RegisterItem(cell, item); - } - public void AddGroup(GroupList group) - { - CellRenderer renderer = ListViewCache.Get(group.HeaderContent, true); - var lastCtx = LastItem?.Data as TypedItemContext; - GenListItem item = null; - if (lastCtx != null && (lastCtx.Type == ItemType.Footer || lastCtx.Type == ItemType.BottomPadding)) - { - item = InsertBefore(renderer.Class, new ListViewItemContext(group), LastItem, GenListItemType.Group); - } - else - { - item = Append(renderer.Class, new ListViewItemContext(group), GenListItemType.Group); - } - RegisterItem(group.HeaderContent, item, true); - } - public void InsertGroup(GroupList group, Cell before) - { - CellRenderer renderer = ListViewCache.Get(group.HeaderContent, true); - _itemContexts.TryGetValue(before, out GenListItem beforeItem); - var item = InsertBefore(renderer.Class, new ListViewItemContext(group), beforeItem, GenListItemType.Group); - RegisterItem(group.HeaderContent, item, true); - } - public void Remove(Cell cell) - { - GenListItem item; - if (_itemContexts.TryGetValue(cell, out item)) - { - item.Delete(); - } - } - public void Remove(GroupList group) - { - Remove(group.HeaderContent); - foreach (var data in group) - { - Remove(data as Cell); - } - } - - public new void Clear() - { - base.Clear(); - } - - protected override void OnRealized() - { - base.OnRealized(); - - ItemRealized += OnItemAppear; - ItemUnrealized += OnItemDisappear; - } - - void OnItemDisappear(object sender, GenListItemEventArgs e) - { - ListViewItemContext ctx = e?.Item?.Data as ListViewItemContext; - if (ctx?.Cell != null) - { - ctx.Cell.SendDisappearing(); - var renderer = ListViewCache.Get(ctx.Cell); - renderer.SendUnrealizedCell(ctx.Cell); - } - } - - void OnItemAppear(object sender, GenListItemEventArgs e) - { - ListViewItemContext ctx = e?.Item?.Data as ListViewItemContext; - if (ctx?.Cell != null) - { - ctx.Cell.SendAppearing(); - } - } - - void UpdateHeaderHeightForGroup(bool isPreviousOfGroup) - { - if (Header == null) return; - if (isPreviousOfGroup) - { - Header.MinimumHeightRequest = GroupHeaderMinimumHeight; // correct visible height on the Group Header - } - else - { - if (Header.HeightRequest < 0 && HeaderRowHeight < 0) - { - Header.MinimumHeightRequest = HeaderMinimumHeight; // correct visible height on the None group header - } - else if(HeaderRowHeight > 0) - { - Header.MinimumHeightRequest = HeaderRowHeight; - } - } - } - - void UpdateHeader() - { - GenItemClass cls = null; - ItemType type = ItemType.TopPadding; - var ctx = FirstItem?.Data as TypedItemContext; - - if (Header == null) - { - cls = ListViewCache.PaddingItemClass; - } - else - { - cls = Forms.CircleListView.GetCancelEffect(Header) ? ListViewCache.InformalItemClassWithoutFishEye : ListViewCache.InformalItemClass; - type = ItemType.Header; - } - - if (FirstItem == null) - { - Append(cls, new TypedItemContext(Header, type)); - } - else - { - if (ctx == null || ctx.Type == ItemType.Footer || ctx.Type == ItemType.BottomPadding) - { - InsertBefore(cls, new TypedItemContext(Header, type), FirstItem); - } - else - { - FirstItem.UpdateItemClass(cls, new TypedItemContext(Header, type)); - } - } - - if (Header != null && FirstItem?.Next != null) - { - var nextCtx = FirstItem.Next?.Data as ListViewItemContext; - var isNextItemIsGroupHeader = nextCtx == null ? false : nextCtx.IsGroupItem; - - UpdateHeaderHeightForGroup(isNextItemIsGroupHeader); - } - } - - void UpdateFooter() - { - GenItemClass cls = null; - ItemType type; - var ctx = LastItem?.Data as TypedItemContext; - if (Footer == null) - { - cls = ListViewCache.PaddingItemClass; - type = ItemType.BottomPadding; - } - else - { - cls = Forms.CircleListView.GetCancelEffect(Footer) ? ListViewCache.InformalItemClassWithoutFishEye : ListViewCache.InformalItemClass; - type = ItemType.Footer; - } - - if (ctx == null || ctx.Type == ItemType.Header || ctx.Type == ItemType.TopPadding) - { - Append(cls, new TypedItemContext(Footer, type)); - } - else - { - LastItem.UpdateItemClass(cls, new TypedItemContext(Footer, type)); - } - } - - void RegisterItem(Cell cell, GenListItem item, bool IsGroup = false) - { - item.SelectionMode = IsGroup ? GenItemSelectionMode.None : GenItemSelectionMode.Always; - item.IsEnabled = cell.IsEnabled; - item.Deleted += ItemDeletedHandler; - _itemContexts[cell] = item; - - - if (Header != null && item == FirstItem.Next) - { - UpdateHeaderHeightForGroup(IsGroup); - } - - if (!IsGroup) - { - cell.PropertyChanged += OnCellPropertyChanged; - (cell as ICellController).ForceUpdateSizeRequested += OnForceUpdateSizeRequested; - } - } - void OnCellPropertyChanged(object sender, PropertyChangedEventArgs e) - { - var cell = sender as Cell; - var renderer = ListViewCache.Get(cell); - GenListItem item; - if (_itemContexts.TryGetValue(cell, out item)) - { - renderer.SendCellPropertyChanged(cell, item, e.PropertyName); - } - } - void OnForceUpdateSizeRequested(object sender, EventArgs e) - { - var cell = sender as Cell; - GenListItem item; - if (_itemContexts.TryGetValue(cell, out item)) - { - item.Update(); - } - } - void ItemDeletedHandler(object sender, EventArgs e) - { - var context = (sender as GenListItem)?.Data as ListViewItemContext; - if (context != null) - { - Cell cell; - if (!context.IsGroupItem) - { - cell = context.Cell; - cell.PropertyChanged -= OnCellPropertyChanged; - (cell as ICellController).ForceUpdateSizeRequested -= OnForceUpdateSizeRequested; - } - else - { - cell = context.Group.HeaderContent; - } - _itemContexts.Remove(cell); - } - } - } - - enum ItemType - { - TopPadding, - BottomPadding, - Header, - Footer - } - - class TypedItemContext - { - public TypedItemContext(VisualElement element, ItemType type) - { - Element = element; - Type = type; - } - public VisualElement Element { get; set; } - public ItemType Type { get; set; } - } - - public class ListViewItemContext : Xamarin.Forms.Platform.Tizen.Native.ListView.ItemContext - { - public ListViewItemContext(Cell cell, GroupList group, bool isGroup) - { - Cell = cell; - Group = group; - IsGroupItem = isGroup; - } - public ListViewItemContext(Cell cell, GroupList group) : this(cell, group, false) - { - } - - public ListViewItemContext(GroupList group) : this(group.HeaderContent, group, true) - { - } - - public GroupList Group { get; set; } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListViewRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListViewRenderer.cs index d6ef93c..91bb806 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListViewRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListViewRenderer.cs @@ -14,243 +14,36 @@ * limitations under the License. */ -using ElmSharp; -using System.Collections; -using System.Collections.Specialized; using Xamarin.Forms; -using Xamarin.Forms.Internals; using Xamarin.Forms.Platform.Tizen; using XForms = Xamarin.Forms.Forms; -using CCircularListView = global::Tizen.Wearable.CircularUI.Forms.CircleListView; -using System; +using CircleListView = Tizen.Wearable.CircularUI.Forms.CircleListView; -[assembly: ExportRenderer(typeof(Tizen.Wearable.CircularUI.Forms.CircleListView), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CircleListViewRenderer))] +[assembly: ExportRenderer(typeof(CircleListView), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CircleListViewRenderer))] namespace Tizen.Wearable.CircularUI.Forms.Renderer { - using GroupList = TemplatedItemsList, Cell>; - - public class CircleListViewRenderer : ViewRenderer + public class CircleListViewRenderer : ListViewRenderer { - int _selectedItemChanging; + new CircleListView Element => base.Element as CircleListView; + WatchListView _listView; public CircleListViewRenderer() { - RegisterPropertyHandler(global::Tizen.Wearable.CircularUI.Forms.CircleListView.HasUnevenRowsProperty, UpdateHasUnevenRows); - RegisterPropertyHandler(CCircularListView.RowHeightProperty, UpdateRowHeight); - RegisterPropertyHandler(CCircularListView.SelectedItemProperty, UpdateSelectedItem); - RegisterPropertyHandler(CCircularListView.ItemsSourceProperty, UpdateSource); - RegisterPropertyHandler("HeaderElement", UpdateHeader); - RegisterPropertyHandler("FooterElement", UpdateFooter); - RegisterPropertyHandler(CCircularListView.BarColorProperty, UpdateBarColor); - } - - protected override void OnElementChanged(ElementChangedEventArgs e) - { - if (Control == null) - { - var surface = this.GetSurface(); - SetNativeControl(NativeFactory.GetNativeControl(typeof(CircleListView), surface) as CircleListView); - Control.ItemSelected += OnListViewItemSelected; - } - - if (e.NewElement != null) - { - e.NewElement.ScrollToRequested += OnScrollToRequested; - e.NewElement.TemplatedItems.GroupedCollectionChanged += OnGroupedCollectionChanged; - e.NewElement.TemplatedItems.CollectionChanged += OnCollectionChanged; - } - if (e.OldElement != null) - { - e.OldElement.ScrollToRequested -= OnScrollToRequested; - e.OldElement.TemplatedItems.GroupedCollectionChanged -= OnGroupedCollectionChanged; - e.OldElement.TemplatedItems.CollectionChanged -= OnCollectionChanged; - } - base.OnElementChanged(e); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (Element != null) - { - Element.ScrollToRequested -= OnScrollToRequested; - Element.TemplatedItems.GroupedCollectionChanged -= OnGroupedCollectionChanged; - Element.TemplatedItems.CollectionChanged -= OnCollectionChanged; - } - if (Control != null) - { - Control.ItemSelected -= OnListViewItemSelected; - } - } - base.Dispose(disposing); - } - - void UpdateFooter() - { - var footer = (Element as IListViewController)?.FooterElement as VisualElement; - Control.Footer = footer; + RegisterPropertyHandler(CircleListView.BarColorProperty, UpdateBarColor); } - void UpdateHeader() + protected override Xamarin.Forms.Platform.Tizen.Native.ListView CreateNativeControl() { - var header = (Element as IListViewController)?.HeaderElement as VisualElement; - Control.Header = header; + return _listView = new WatchListView(XForms.NativeParent, this.GetSurface()); } void UpdateBarColor() { - var color = Element.BarColor; - if (color != Xamarin.Forms.Color.Default) - { - Control.VerticalScrollBarColor = color.ToNative(); - } - } - - void UpdateSource(bool init) - { - if (!init) - Control.Clear(); - Control.AddSource(Element.TemplatedItems); - UpdateSelectedItem(); - } - - void UpdateSelectedItem() - { - if (Element.SelectedItem == null) - { - if (Control.SelectedItem != null) - Control.SelectedItem.IsSelected = false; - } - else - { - var results = Element.TemplatedItems.GetGroupAndIndexOfItem(Element.SelectedItem); - if (results.Item1 != -1 && results.Item2 != -1) - { - var group = (Element.TemplatedItems as ITemplatedItemsList).GetGroup(results.Item1); - var cell = group[results.Item2]; - - _selectedItemChanging++; - Control.ApplySelectedItem(cell); - _selectedItemChanging--; - } - } - } - - void UpdateRowHeight(bool initialize) - { - Control.HeaderRowHeight = Element.RowHeight; - if (!initialize) - Control.UpdateRealizedItems(); - } - - void UpdateHasUnevenRows() - { - Control.Homogeneous = !Element.HasUnevenRows; - Control.UpdateRealizedItems(); - } - - void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (e.Action == NotifyCollectionChangedAction.Add) - { - if (e.NewStartingIndex + e.NewItems.Count < Element.TemplatedItems.Count) - { - Cell before = Element.TemplatedItems[e.NewStartingIndex + e.NewItems.Count]; - Control.AddSource(e.NewItems, before); - } - else - { - Control.AddSource(e.NewItems); - } - } - else if (e.Action == NotifyCollectionChangedAction.Remove) - { - Control.RemoveSource(e.OldItems); - } - else if (e.Action == NotifyCollectionChangedAction.Reset) - { - UpdateSource(false); - } - } - - void OnGroupedCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (e.Action == NotifyCollectionChangedAction.Add) - { - GroupList group = sender as GroupList; - if (e.NewStartingIndex + e.NewItems.Count < Element.TemplatedItems.Count) - { - Cell before = Element.TemplatedItems[e.NewStartingIndex + e.NewItems.Count]; - Control.AddSource(e.NewItems, group, before); - } - else - { - Control.AddSource(e.NewItems, group); - } - } - else if (e.Action == NotifyCollectionChangedAction.Remove) - { - Control.RemoveSource(e.OldItems); - } - else if (e.Action == NotifyCollectionChangedAction.Reset) - { - Control.ResetGroup(sender as GroupList); - } - } - - void OnScrollToRequested(object sender, ScrollToRequestedEventArgs e) - { - Cell cell; - var args = e as ITemplatedItemsListScrollToRequestedEventArgs; - if (Element.IsGroupingEnabled) - { - var results = Element.TemplatedItems.GetGroupAndIndexOfItem(args.Group, args.Item); - if (results.Item1 == -1 || results.Item2 == -1) - return; - - var group = (Element.TemplatedItems as ITemplatedItemsList).GetGroup(results.Item1); - cell = group[results.Item2]; - } - else - { - int index = (Element.TemplatedItems as ITemplatedItemsList).GetGlobalIndexOfItem(args.Item); - cell = Element.TemplatedItems[index]; - } - - Control.ApplyScrollTo(cell, e.Position, e.ShouldAnimate); - } - - void OnListViewItemSelected(object sender, GenListItemEventArgs e) - { - var context = e.Item?.Data as ListViewItemContext; - - if (context == null) - { - return; - } - - if (_selectedItemChanging != 0 || context.IsGroupItem) - { - return; - } - - if (Element.IsGroupingEnabled) - { - int groupIndex = (Element.TemplatedItems as IList).IndexOf(context.Group); - int subIndex = context.Group.IndexOf(context.Cell); - _selectedItemChanging++; - Element.NotifyRowTapped(groupIndex, subIndex); - _selectedItemChanging--; - } - else + if (!Element.BarColor.IsDefault) { - int index = Element.TemplatedItems.IndexOf(context.Cell); - _selectedItemChanging++; - Element.NotifyRowTapped(index); - _selectedItemChanging--; + _listView.CircleGenList.VerticalScrollBarColor = Element.BarColor.ToNative(); } } } diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CirclePageRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CirclePageRenderer.cs index a49e7aa..9aa1ab7 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CirclePageRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CirclePageRenderer.cs @@ -14,90 +14,98 @@ * limitations under the License. */ +using ElmSharp; +using ElmSharp.Wearable; using System; -using System.Collections.ObjectModel; +using System.Collections.Generic; using System.Collections.Specialized; +using System.ComponentModel; +using System.Linq; using Tizen.Wearable.CircularUI.Forms; using Xamarin.Forms; using Xamarin.Forms.Platform.Tizen; +using Xamarin.Forms.Platform.Tizen.Native; +using ERotaryEventManager = ElmSharp.Wearable.RotaryEventManager; +using NPage = Xamarin.Forms.Platform.Tizen.Native.Page; using XForms = Xamarin.Forms.Forms; -using XToolbarItem = Xamarin.Forms.ToolbarItem; +using AppSpecific = Xamarin.Forms.PlatformConfiguration.TizenSpecific.Application; [assembly: ExportRenderer(typeof(CirclePage), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CirclePageRenderer))] + namespace Tizen.Wearable.CircularUI.Forms.Renderer { - public class CirclePageRenderer : VisualElementRenderer + public class CirclePageRenderer : PageRenderer, IBezelInteractionController { - NativeCirclePage _circlePage = null; + ElmSharp.Button _actionButton; + ActionButtonItem _actionButtonItem; + ElmSharp.Layout _surfaceLayout; + CircleSurface _circleSurface; + Dictionary _circleSurfaceItems; + IRotaryFocusable _currentRotaryFocusObject; + bool _isInitialized; + + NPage Control => (NativeView as NPage); + + new CirclePage Element => base.Element as CirclePage; public CirclePageRenderer() { - RegisterPropertyHandler(Xamarin.Forms.Page.BackgroundImageSourceProperty, UpdateBackgroundImage); RegisterPropertyHandler(CirclePage.ActionButtonProperty, UpdateActionButton); RegisterPropertyHandler(CirclePage.RotaryFocusObjectProperty, UpdateRotaryFocusObject); } - public ElmSharp.Wearable.CircleSurface CircleSurface; + public CircleSurface CircleSurface => _circleSurface; - public void UpdateRotaryFocusObject() + IRotaryFocusable IBezelInteractionController.RotaryFocusObject => _currentRotaryFocusObject; + + void IBezelInteractionController.Activate() { - _circlePage.UpdateRotaryFocusObject(Element.RotaryFocusObject); + ActivateRotaryWidget(); } - protected override void OnElementChanged(ElementChangedEventArgs e) + void IBezelInteractionController.Deactivate() { - if (_circlePage == null) - { - _circlePage = NativeFactory.GetNativeControl(typeof(NativeCirclePage)) as NativeCirclePage; - CircleSurface = _circlePage.Surface; - - if (Element.ToolbarItems.Count > 0) - { - Device.BeginInvokeOnMainThread(() => - { - _circlePage.SetVisibleMoreOption(true); + DeactivateRotaryWidget(); + } - foreach (var item in Element.ToolbarItems) - { - _circlePage.AddToolbarItem(item); - } - }); - } - SetNativeView(_circlePage); + public void UpdateRotaryFocusObject(bool initialize) + { + if (initialize) + { + _currentRotaryFocusObject = Element.RotaryFocusObject; } - if (e.NewElement != null) + else { - _circlePage.SetElement(e.NewElement); - - e.NewElement.CircleSurface = _circlePage.Surface; - e.NewElement.Appearing += OnPageAppearing; - e.NewElement.Disappearing += OnPageDisappearing; - var toolbarItems = e.NewElement.ToolbarItems as ObservableCollection; - if (toolbarItems != null) - toolbarItems.CollectionChanged += OnToolbarItemChanged; - var circleSurfaceItems = e.NewElement.CircleSurfaceItems as ObservableCollection; - if (circleSurfaceItems != null) - { - circleSurfaceItems.CollectionChanged += OnCircleSurfaceItemsChanged; + DeactivateRotaryWidget(); + _currentRotaryFocusObject = Element.RotaryFocusObject; + ActivateRotaryWidget(); + } + } - foreach (var item in circleSurfaceItems) - { - _circlePage.AddCircleSurfaceItem(item); - } - } + protected override void OnElementChanged(ElementChangedEventArgs e) + { + // It will create NativeView and it will be Native.Page + base.OnElementChanged(e); + if (!_isInitialized) + { + _isInitialized = true; + InitializeComponent(); } - if (e.OldElement != null) + + if (e.NewElement is CirclePage newElement) { - e.OldElement.Appearing -= OnPageAppearing; - e.OldElement.Disappearing -= OnPageDisappearing; - var toolbarItems = e.NewElement.ToolbarItems as ObservableCollection; - if (toolbarItems != null) - toolbarItems.CollectionChanged -= OnToolbarItemChanged; - var circleSurfaceItems = e.NewElement.CircleSurfaceItems as ObservableCollection; - if (circleSurfaceItems != null) - circleSurfaceItems.CollectionChanged -= OnCircleSurfaceItemsChanged; + newElement.Appearing += OnPageAppearing; + newElement.Disappearing += OnPageDisappearing; + newElement.CircleSurface = CircleSurface; + foreach (var item in newElement.CircleSurfaceItems) + { + AddCircleSurfaceItem(item); + } + if (newElement.CircleSurfaceItems is INotifyCollectionChanged collectionChanged) + { + collectionChanged.CollectionChanged += OnCircleSurfaceItemsChanged; + } } - base.OnElementChanged(e); } protected override void OnElementReady() @@ -111,74 +119,217 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer } } - protected override void UpdateBackgroundColor(bool initialize) + + protected override void OnMoreOptionClosed() { - if (initialize && Element.BackgroundColor.IsDefault) - return; + DeactivateRotaryWidget(); + } + - _circlePage.UpdateBackgroundColor(Element.BackgroundColor); + protected override void OnMoreOptionOpened() + { + ActivateRotaryWidget(); } - protected void UpdateBackgroundImage(bool initialize) + protected override void Dispose(bool disposing) { - if (initialize && Element.BackgroundImageSource.IsNullOrEmpty()) - return; + if (disposing) + { + if (Element != null) + { + Element.Appearing -= OnPageAppearing; + Element.Disappearing -= OnPageDisappearing; + Element.CircleSurface = null; + if (_actionButtonItem != null) + { + _actionButtonItem.PropertyChanged -= OnActionButtonItemChanged; + } + if (Element.CircleSurfaceItems is INotifyCollectionChanged collectionChanged) + { + collectionChanged.CollectionChanged -= OnCircleSurfaceItemsChanged; + } + } + } + base.Dispose(disposing); + } - _circlePage.UpdateBackgroundImage(Element.BackgroundImageSource); + void InitializeComponent() + { + Control.LayoutUpdated += OnLayoutUpdated; + _surfaceLayout = new ElmSharp.Layout(XForms.NativeParent); + _circleSurface = new CircleSurface(_surfaceLayout); + Control.Children.Add(_surfaceLayout); + _surfaceLayout.Show(); + _circleSurfaceItems = new Dictionary(); } - protected override void Dispose(bool disposing) + void InitializeActionButton() { - if (Element != null) + _actionButton = new ElmSharp.Button(XForms.NativeParent) { - Element.Appearing -= OnPageAppearing; - Element.Disappearing -= OnPageDisappearing; + Style = "bottom" + }; + _actionButton.Clicked += OnActionButtonClicked; + Control.Children.Add(_actionButton); + } - var toolbarItems = Element.ToolbarItems as ObservableCollection; - if (toolbarItems != null) - toolbarItems.CollectionChanged -= OnToolbarItemChanged; + void DeinitializeActionButton() + { + _actionButton.Clicked -= OnActionButtonClicked; + Control.Children.Remove(_actionButton); + _actionButton.Unrealize(); + _actionButton = null; + } - var circleSurfaceItems = Element.CircleSurfaceItems as ObservableCollection; - if (circleSurfaceItems != null) - circleSurfaceItems.CollectionChanged -= OnCircleSurfaceItemsChanged; + void UpdateActionButton(bool init) + { + if (_actionButtonItem != null) + { + _actionButtonItem.PropertyChanged -= OnActionButtonItemChanged; + _actionButtonItem = null; } - if (_circlePage != null) + if (Element.ActionButton != null) + { + if (_actionButton == null) + { + InitializeActionButton(); + } + + UpdateActionButtonVisible(Element.ActionButton.IsVisible); + UpdateActionButtonText(Element.ActionButton.Text); + UpdateActionButtonIcon(Element.ActionButton.IconImageSource); + _actionButton.IsEnabled = Element.ActionButton.IsEnable; + _actionButton.BackgroundColor = Element.ActionButton.BackgroundColor.ToNative(); + + _actionButtonItem = Element.ActionButton; + _actionButtonItem.PropertyChanged += OnActionButtonItemChanged; + } + else { - _circlePage.Dispose(disposing); + if (_actionButton != null) + { + DeinitializeActionButton(); + } } + if (!init) + { + Device.BeginInvokeOnMainThread(() => OnLayout()); + } + } - base.Dispose(disposing); + void UpdateActionButtonVisible(bool visible) + { + if (_actionButton == null) + { + return; + } + if (visible) _actionButton.Show(); + else _actionButton.Hide(); } - void UpdateActionButton(bool initialize) + void UpdateActionButtonText(string text) { - _circlePage.UpdateActionButton(Element.ActionButton); + _actionButton.Text = text?.Replace("&", "&") + .Replace("<", "<") + .Replace(">", ">") + .Replace(Environment.NewLine, "
") ?? string.Empty; } - void OnToolbarItemChanged(object sender, NotifyCollectionChangedEventArgs e) + void UpdateActionButtonIcon(ImageSource source) { - _circlePage.SetVisibleMoreOption(Element.ToolbarItems.Count > 0); - if (e.Action == NotifyCollectionChangedAction.Add || - e.Action == NotifyCollectionChangedAction.Replace) + if (source is FileImageSource filesource) { - foreach (XToolbarItem item in e.NewItems) _circlePage.AddToolbarItem(item); + var path = ResourcePath.GetPath(filesource); + var buttonImage = new ElmSharp.Image(_actionButton); + buttonImage.Load(path); + buttonImage.Show(); + _actionButton.SetPartContent("elm.swallow.content", buttonImage); } - if (e.Action == NotifyCollectionChangedAction.Remove || - e.Action == NotifyCollectionChangedAction.Replace) + else { - foreach (XToolbarItem item in e.OldItems) _circlePage.RemoveToolbarITem(item); + _actionButton.SetPartContent("elm.swallow.content", null); } } void OnPageDisappearing(object sender, EventArgs e) { - _circlePage.DeactivateRotaryWidget(); + DeactivateRotaryWidget(); } void OnPageAppearing(object sender, EventArgs e) { - _circlePage.ActivateRotaryWidget(); + ActivateRotaryWidget(); + } + + void OnLayoutUpdated(object sender, LayoutEventArgs e) + { + OnLayout(); + } + + void OnLayout() + { + // Page layout was updated on base class + // It only update ActionButton + + var content = (Element as IElementController).LogicalChildren.FirstOrDefault(); + if (content == null) + return; + + var topmostView = Platform.GetRenderer(content)?.NativeView; + + var bound = Control.Geometry; + + if (_actionButton != null) + { + var btnRect = _actionButton.Geometry; + var btnW = Math.Max(_actionButton.MinimumWidth, btnRect.Width); + var btnH = Math.Max(_actionButton.MinimumHeight, btnRect.Height); + var btnX = bound.X + (bound.Width - btnW) / 2; + var btnY = bound.Y + bound.Height - btnH; + _actionButton.Geometry = new Rect(btnX, btnY, btnW, btnH); + _actionButton.StackAbove(topmostView); + topmostView = _actionButton; + } + + _surfaceLayout.Geometry = bound; + _surfaceLayout.StackAbove(topmostView); + } + + void OnActionButtonClicked(object sender, EventArgs e) + { + if (Element.ActionButton != null) + { + ((IMenuItemController)Element.ActionButton).Activate(); + } + } + + void OnActionButtonItemChanged(object sender, PropertyChangedEventArgs e) + { + if (_actionButton == null) + { + return; + } + if (e.PropertyName == MenuItem.TextProperty.PropertyName) + { + UpdateActionButtonText(Element.ActionButton.Text); + } + else if (e.PropertyName == ActionButtonItem.IsEnableProperty.PropertyName) + { + _actionButton.IsEnabled = Element.ActionButton.IsEnable; + } + else if (e.PropertyName == ActionButtonItem.IsVisibleProperty.PropertyName) + { + UpdateActionButtonVisible(Element.ActionButton.IsVisible); + } + else if (e.PropertyName == ActionButtonItem.BackgroundColorProperty.PropertyName) + { + _actionButton.BackgroundColor = Element.ActionButton.BackgroundColor.ToNative(); + } + else if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName) + { + UpdateActionButtonIcon(Element.ActionButton.IconImageSource); + } } void OnCircleSurfaceItemsChanged(object sender, NotifyCollectionChangedEventArgs e) @@ -187,14 +338,99 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer e.Action == NotifyCollectionChangedAction.Replace) { foreach (ICircleSurfaceItem item in e.NewItems) - _circlePage.AddCircleSurfaceItem(item); + AddCircleSurfaceItem(item); } if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace) { foreach (ICircleSurfaceItem item in e.OldItems) - _circlePage.RemoveCircleSurfaceItem(item); + RemoveCircleSurfaceItem(item); + } + } + + void OnRotaryEventChanged(ElmSharp.Wearable.RotaryEventArgs e) + { + if (_currentRotaryFocusObject is IRotaryEventReceiver receiver) + { + receiver.Rotate(new RotaryEventArgs { IsClockwise = e.IsClockwise }); + } + } + + void AddCircleSurfaceItem(ICircleSurfaceItem item) + { + if (item is CircleProgressBarSurfaceItem progressbar) + { + _circleSurfaceItems[item] = new CircleProgressBarSurfaceItemImplements(progressbar, _surfaceLayout, CircleSurface); + } + else if (item is CircleSliderSurfaceItem slider) + { + _circleSurfaceItems[item] = new CircleSliderSurfaceItemImplements(slider, _surfaceLayout, CircleSurface); + } + } + + void RemoveCircleSurfaceItem(ICircleSurfaceItem item) + { + if (_circleSurfaceItems.TryGetValue(item, out var widget)) + { + (widget as EvasObject)?.Unrealize(); + _circleSurfaceItems.Remove(item); + } + } + + void ActivateRotaryWidget() + { + if (!Element.Appeared) + return; + + if (_currentRotaryFocusObject is IRotaryEventReceiver) + { + ERotaryEventManager.Rotated += OnRotaryEventChanged; + } + else + { + GetRotaryWidget(_currentRotaryFocusObject)?.Activate(); + } + AppSpecific.SetActiveBezelInteractionElement(Application.Current, base.Element); + } + + void DeactivateRotaryWidget() + { + if (_currentRotaryFocusObject is IRotaryEventReceiver) + { + ERotaryEventManager.Rotated -= OnRotaryEventChanged; + } + else if (_currentRotaryFocusObject is IRotaryFocusable) + { + GetRotaryWidget(_currentRotaryFocusObject)?.Deactivate(); + } + if (AppSpecific.GetActiveBezelInteractionElement(Application.Current) == base.Element) + AppSpecific.SetActiveBezelInteractionElement(Application.Current, null); + } + + IRotaryActionWidget GetRotaryWidget(IRotaryFocusable focusable) + { + IRotaryActionWidget rotaryWidget = null; + if (focusable is BindableObject consumer) + { + if (consumer is ICircleSurfaceItem circleSurfaceItem) + { + rotaryWidget = GetCircleWidget(circleSurfaceItem) as IRotaryActionWidget; + } + else + { + rotaryWidget = Platform.GetRenderer(consumer)?.NativeView as IRotaryActionWidget; + } + } + return rotaryWidget; + } + + ICircleWidget GetCircleWidget(ICircleSurfaceItem item) + { + if (_circleSurfaceItems.TryGetValue(item, out ICircleWidget widget)) + { + return widget; } + return null; } } } \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleScrollViewRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleScrollViewRenderer.cs index c11130f..c9b39d2 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleScrollViewRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleScrollViewRenderer.cs @@ -14,259 +14,38 @@ * limitations under the License. */ -using System; -using System.ComponentModel; -using System.Threading.Tasks; -using ElmSharp; -using ElmSharp.Wearable; using Xamarin.Forms; using Xamarin.Forms.Platform.Tizen; -using Xamarin.Forms.Platform.Tizen.Native; -using ERect = ElmSharp.Rect; using XForms = Xamarin.Forms.Forms; +using WatchScroller = Xamarin.Forms.Platform.Tizen.Native.Watch.WatchScroller; [assembly: ExportRenderer(typeof(Tizen.Wearable.CircularUI.Forms.CircleScrollView), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CircleScrollViewRenderer))] namespace Tizen.Wearable.CircularUI.Forms.Renderer { - public class CircleScrollViewRenderer : ViewRenderer + public class CircleScrollViewRenderer : ScrollViewRenderer { - Xamarin.Forms.Platform.Tizen.Native.Box _scrollCanvas; - ElmSharp.SmartEvent _scrollAnimationStart, _scrollAnimationStop; - bool _isAnimation; - TaskCompletionSource _animationTaskComplateSource; + public CircleScrollView CircleElement => Element as CircleScrollView; + WatchScroller _scroller; public CircleScrollViewRenderer() { RegisterPropertyHandler(CircleScrollView.BarColorProperty, UpdateBarColor); - RegisterPropertyHandler("Content", OnContent); } - public override ERect GetNativeContentGeometry() - { - return _scrollCanvas.Geometry; - } - - protected override void OnElementChanged(ElementChangedEventArgs e) - { - if (Control == null) - { - var surface = this.GetSurface(); - SetNativeControl(NativeFactory.GetNativeControl(typeof(CircleScroller), surface) as CircleScroller); - InitControl(); - Control.Scrolled += OnScrolled; - _scrollCanvas = new Xamarin.Forms.Platform.Tizen.Native.Box(Control); - _scrollCanvas.LayoutUpdated += OnContentLayoutUpdated; - Control.SetContent(_scrollCanvas); - } - if (e.OldElement != null) - { - (e.OldElement as IScrollViewController).ScrollToRequested -= OnScrollRequestedAsync; - } - if (e.NewElement != null) - { - (e.NewElement as IScrollViewController).ScrollToRequested += OnScrollRequestedAsync; - } - - UpdateAll(); - - base.OnElementChanged(e); - } - - protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (ScrollView.OrientationProperty.PropertyName == e.PropertyName) - { - UpdateOrientation(); - } - else if (ScrollView.ContentSizeProperty.PropertyName == e.PropertyName) - { - UpdateContentSize(); - } - else if (ScrollView.VerticalScrollBarVisibilityProperty.PropertyName == e.PropertyName) - { - UpdateVerticalScrollBarVisibility(); - } - else if (ScrollView.HorizontalScrollBarVisibilityProperty.PropertyName == e.PropertyName) - { - UpdateHorizontalScrollBarVisibility(); - } - - base.OnElementPropertyChanged(sender, e); - } - - protected override void Dispose(bool disposing) - { - if (disposing) + protected override Xamarin.Forms.Platform.Tizen.Native.Scroller CreateNativeControl() { - if (null != Element) - { - (Element as IScrollViewController).ScrollToRequested -= OnScrollRequestedAsync; - } - if (Control != null) - { - Control.Scrolled -= OnScrolled; - } - if (_scrollCanvas != null) - { - _scrollCanvas.LayoutUpdated -= OnContentLayoutUpdated; - } - _scrollAnimationStart?.Dispose(); - _scrollAnimationStop?.Dispose(); - } - base.Dispose(disposing); - } - - void UpdateAll() - { - UpdateOrientation(); - UpdateVerticalScrollBarVisibility(); - UpdateHorizontalScrollBarVisibility(); - } - - void UpdateVerticalScrollBarVisibility() - { - var orientation = Element.Orientation; - if (orientation == ScrollOrientation.Vertical || orientation == ScrollOrientation.Both) - Control.VerticalScrollBarVisiblePolicy = ScrollBarVisibilityToTizen(Element.VerticalScrollBarVisibility); - } - - void UpdateHorizontalScrollBarVisibility() - { - var orientation = Element.Orientation; - if (orientation == ScrollOrientation.Horizontal || orientation == ScrollOrientation.Both) - Control.HorizontalScrollBarVisiblePolicy = ScrollBarVisibilityToTizen(Element.HorizontalScrollBarVisibility); + return _scroller = new WatchScroller(XForms.NativeParent, this.GetSurface()); } void UpdateBarColor() { - var color = Element.BarColor; - if (color != Xamarin.Forms.Color.Default) - { - Control.VerticalScrollBarColor = color.ToNative(); - Control.HorizontalScrollBarColor = color.ToNative(); - } - } - - ScrollBarVisiblePolicy ScrollBarVisibilityToTizen(ScrollBarVisibility visibility) - { - switch (visibility) - { - case ScrollBarVisibility.Always: - return ScrollBarVisiblePolicy.Visible; - case ScrollBarVisibility.Never: - return ScrollBarVisiblePolicy.Invisible; - default: - return ScrollBarVisiblePolicy.Auto; - } - } - - async void OnScrollRequestedAsync(object sender, ScrollToRequestedEventArgs e) - { - var x = e.ScrollX; - var y = e.ScrollY; - if (e.Mode == ScrollToMode.Element) - { - var itemPosition = (Element as IScrollViewController).GetScrollPositionForElement(e.Element as VisualElement, e.Position); - x = itemPosition.X; - y = itemPosition.Y; - } - var region = new Xamarin.Forms.Rectangle(x, y, Element.Width, Element.Height).ToPixel(); - await ScrollToAsync(region, e.ShouldAnimate).ConfigureAwait(false); - Element.SendScrollFinished(); - } - - void OnScrolled(object sender, EventArgs e) - { - var region = Control.CurrentRegion.ToDP(); - ((IScrollViewController)Element).SetScrolledPosition(region.X, region.Y); - } - - void OnContent() - { - _scrollCanvas.UnPackAll(); - if (Element.Content != null) - { - _scrollCanvas.PackEnd(Platform.GetOrCreateRenderer(Element.Content).NativeView); - UpdateContentSize(); - } - } - - void UpdateContentSize() - { - _scrollCanvas.MinimumWidth = XForms.ConvertToScaledPixel(Element.ContentSize.Width + Element.Padding.HorizontalThickness); - _scrollCanvas.MinimumHeight = XForms.ConvertToScaledPixel(Element.ContentSize.Height + Element.Padding.VerticalThickness); - - Device.BeginInvokeOnMainThread(() => - { - if (Control != null) - { - OnScrolled(Control, EventArgs.Empty); - } - }); - } - - void OnContentLayoutUpdated(object sender, LayoutEventArgs e) - { - UpdateContentSize(); - } - - void UpdateOrientation() - { - switch (Element.Orientation) - { - case ScrollOrientation.Horizontal: - Control.ScrollBlock = ElmSharp.ScrollBlock.Vertical; - Control.HorizontalScrollBarVisiblePolicy = ElmSharp.ScrollBarVisiblePolicy.Auto; - Control.VerticalScrollBarVisiblePolicy = ElmSharp.ScrollBarVisiblePolicy.Invisible; - break; - case ScrollOrientation.Vertical: - Control.ScrollBlock = ElmSharp.ScrollBlock.Horizontal; - Control.HorizontalScrollBarVisiblePolicy = ElmSharp.ScrollBarVisiblePolicy.Invisible; - Control.VerticalScrollBarVisiblePolicy = ElmSharp.ScrollBarVisiblePolicy.Auto; - break; - case ScrollOrientation.Both: - Control.ScrollBlock = ElmSharp.ScrollBlock.None; - Control.HorizontalScrollBarVisiblePolicy = ElmSharp.ScrollBarVisiblePolicy.Auto; - Control.VerticalScrollBarVisiblePolicy = ElmSharp.ScrollBarVisiblePolicy.Auto; - break; - default: - throw new InvalidOperationException("Not supported orientation."); - } - } - - void InitControl() - { - _scrollAnimationStart = new ElmSharp.SmartEvent(Control, Control.RealHandle, "scroll,anim,start"); - _scrollAnimationStop = new ElmSharp.SmartEvent(Control, Control.RealHandle, "scroll,anim,stop"); - _scrollAnimationStart.On += (s, e) => _isAnimation = true; - _scrollAnimationStop.On += (s, e) => - { - if (_animationTaskComplateSource != null) - { - _animationTaskComplateSource.TrySetResult(true); - } - _isAnimation = false; - }; - } - - Task ScrollToAsync(Rect region, bool shouldAnimate) - { - CheckTaskCompletionSource(); - Control.ScrollTo(region, shouldAnimate); - return shouldAnimate && _isAnimation ? _animationTaskComplateSource.Task : Task.CompletedTask; - } - - void CheckTaskCompletionSource() - { - if (_animationTaskComplateSource != null) + var color = CircleElement.BarColor; + if (!color.IsDefault) { - if (_animationTaskComplateSource.Task.Status == TaskStatus.Running) - { - _animationTaskComplateSource.TrySetCanceled(); - } + _scroller.CircleScroller.VerticalScrollBarColor = color.ToNative(); + _scroller.CircleScroller.HorizontalScrollBarColor = color.ToNative(); } - _animationTaskComplateSource = new TaskCompletionSource(); } } } \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleStepperRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleStepperRenderer.cs index 866f812..29dad77 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleStepperRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleStepperRenderer.cs @@ -15,18 +15,17 @@ */ using System; -using ESpinner = ElmSharp.Wearable.CircleSpinner; -using ESize = ElmSharp.Size; using Xamarin.Forms; using Xamarin.Forms.Platform.Tizen; +using Xamarin.Forms.Platform.Tizen.Native.Watch; +using ESize = ElmSharp.Size; using XForms = Xamarin.Forms.Forms; [assembly: ExportRenderer(typeof(Tizen.Wearable.CircularUI.Forms.CircleStepper), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CircleStepperRenderer))] - namespace Tizen.Wearable.CircularUI.Forms.Renderer { - public class CircleStepperRenderer : ViewRenderer + public class CircleStepperRenderer : StepperRenderer { public CircleStepperRenderer() { @@ -36,62 +35,24 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer #pragma warning restore CS0618 // MarkerColorProperty and MarkerLineWidthProperty are obsolete RegisterPropertyHandler(CircleStepper.LabelFormatProperty, UpdateLabelFormat); RegisterPropertyHandler(CircleStepper.TitleProperty, UpdateTitle); - RegisterPropertyHandler(Stepper.MinimumProperty, UpdateMinimum); - RegisterPropertyHandler(Stepper.MaximumProperty, UpdateMaximum); - RegisterPropertyHandler(Stepper.ValueProperty, UpdateValue); - RegisterPropertyHandler(Stepper.IncrementProperty, UpdateIncrement); RegisterPropertyHandler(CircleStepper.IsWrapEnabledProperty, UpdateWrapEnabled); } - protected override void OnElementChanged(ElementChangedEventArgs e) - { - if (Control == null) - { - var surface = this.GetSurface(); - if (null != surface) - { - var spinner = new ESpinner(XForms.NativeParent, surface); - spinner.Style = "circle"; + protected new WatchSpinner Control => base.Control as WatchSpinner; - SetNativeControl(spinner); - Control.ValueChanged += OnValueChanged; - } - else - { - throw new CirclePageNotFoundException(); - } - } + protected new CircleStepper Element => base.Element as CircleStepper; - base.OnElementChanged(e); + protected override ElmSharp.Spinner CreateNativeControl() + { + return new WatchSpinner(XForms.NativeParent, this.GetSurface()); } - private void OnValueChanged(object sender, EventArgs e) - { - double newValue = Control.Value; - ((IElementController)Element).SetValueFromRenderer(Stepper.ValueProperty, newValue); + protected override void OnElementChanged(ElementChangedEventArgs e) + { + base.OnElementChanged(e); - if (Element.LabelFormat == null) - { - // Determines how many decimal places are there in current Stepper's value. - // The 15 pound characters below correspond to the maximum precision of Double type. - var decimalValue = Decimal.Parse(newValue.ToString("0.###############")); - - // GetBits() method returns an array of four 32-bit integer values. - // The third (0-indexing) element of an array contains the following information: - // bits 00-15: unused, required to be 0 - // bits 16-23: an exponent between 0 and 28 indicating the power of 10 to divide the integer number passed as a parameter. - // Conversely this is the number of decimal digits in the number as well. - // bits 24-30: unused, required to be 0 - // bit 31: indicates the sign. 0 means positive number, 1 is for negative numbers. - // - // The precision information needs to be extracted from bits 16-23 of third element of an array - // returned by GetBits() call. Right-shifting by 16 bits followed by zeroing anything else results - // in a nice conversion of this data to integer variable. - var precision = (Decimal.GetBits(decimalValue)[3] >> 16) & 0x000000FF; - - // Sets Stepper's inner label decimal format to use exactly as many decimal places as needed: - Control.LabelFormat = string.Format("%.{0}f", precision); - } + Control.WheelAppeared += OnListShow; + Control.WheelDisappeared += OnListHide; } protected override void Dispose(bool disposing) @@ -117,10 +78,20 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer return new ESize(360, 110); } + void OnListShow(object sender, EventArgs args) + { + Element.SendWheelAppeared(); + } + + void OnListHide(object sender, EventArgs args) + { + Element.SendWheelDisappeared(); + } + void UpdateMarkerColor() { #pragma warning disable CS0618 // MarkerColor is obsolete - if (null != Control && null != Element && Element.MarkerColor != Color.Default) + if (Element.MarkerColor != Color.Default) { Control.MarkerColor = Element.MarkerColor.ToNative(); } @@ -129,68 +100,29 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer void UpdateMarkerLineWidth() { - if (null != Control && null != Element) - { #pragma warning disable CS0618 // MarkerLineWidth is obsolete Control.MarkerLineWidth = Element.MarkerLineWidth; #pragma warning restore CS0618 // MarkerLineWidth is obsolete } - } void UpdateLabelFormat() { - if (null != Control && null != Element) - { Control.LabelFormat = Element.LabelFormat; } - } void UpdateTitle() { - if (null != Control && null != Element) - { Control.SetPartText("elm.text", Element.Title); } - } - - void UpdateValue() - { - if (null != Control && null != Element) - { - Control.Value = Element.Value; - } - } - - void UpdateMaximum() - { - if (null != Control && null != Element) - { - Control.Maximum = Element.Maximum; - } - } - - void UpdateMinimum() - { - if (null != Control && null != Element) - { - Control.Minimum = Element.Minimum; - } - } void UpdateIncrement() { - if (null != Control && null != Element) - { Control.Step = Element.Increment; } - } void UpdateWrapEnabled() { - if (null != Control && null != Element) - { Control.IsWrapEnabled = Element.IsWrapEnabled; } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleSurfaceViewRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleSurfaceViewRenderer.cs index e53e60e..41d388a 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleSurfaceViewRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircleSurfaceViewRenderer.cs @@ -28,13 +28,21 @@ using ELayout = ElmSharp.Layout; [assembly: ExportRenderer(typeof(CircleSurfaceView), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CircleSurfaceViewRenderer))] namespace Tizen.Wearable.CircularUI.Forms.Renderer { - public class CircleSurfaceViewRenderer : ViewRenderer + public class CircleSurfaceViewRenderer : ViewRenderer, ICircleSurfaceItemRenderer { - Dictionary _circleSurfaceItems; ELayout _surfaceLayout; CircleSurface _circleSurface; + ICircleWidget ICircleSurfaceItemRenderer.GetCircleWidget(ICircleSurfaceItem item) + { + if (_circleSurfaceItems.TryGetValue(item, out ICircleWidget widget)) + { + return widget; + } + return null; + } + protected override void OnElementChanged(ElementChangedEventArgs e) { if (Control == null) diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircularUI.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircularUI.cs index f40c4c9..9ab8d3b 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircularUI.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircularUI.cs @@ -17,6 +17,7 @@ using System; using System.Diagnostics; using Tizen.Applications; using Tizen.Wearable.CircularUI.Forms.Renderer; +using Tizen.Wearable.CircularUI.Forms.Renderer.Shell; namespace Tizen.Wearable.CircularUI.Forms { @@ -48,6 +49,7 @@ namespace Tizen.Wearable.CircularUI.Forms { if (IsInitialized) return; IsInitialized = true; + CircularShellRendererFactory.Setup(); } public static void Init(string apiKey) diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircularUIForms.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircularUIForms.cs index fb6dcf3..ad638a3 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircularUIForms.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CircularUIForms.cs @@ -26,7 +26,7 @@ namespace Tizen.Wearable.CircularUI.Forms { typeof(CircleScrollView), () => new CircleScrollViewRenderer() }, { typeof(CircleStepper), () => new CircleStepperRenderer() }, { typeof(CircleSurfaceView), () => new CircleSurfaceViewRenderer() }, - { typeof(CircularShell), () => new ShellRenderer() }, + { typeof(CircularShell), () => new CircularShellRenderer() }, { typeof(ContentButton), () => new ContentButtonRenderer() }, { typeof(GoogleMapView), () => new GoogleMapViewRenderer() }, { typeof(IndexPage), () => new IndexPageRenderer() }, diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CollectionViewRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CollectionViewRenderer.cs new file mode 100644 index 0000000..1fa945f --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/CollectionViewRenderer.cs @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using Xamarin.Forms; +using XStructuredItemsViewRenderer = Xamarin.Forms.Platform.Tizen.StructuredItemsViewRenderer; +using CStructuredItemsViewRenderer = Tizen.Wearable.CircularUI.Forms.Renderer.StructuredItemsViewRenderer; + +using XCarouselViewRenderer = Xamarin.Forms.Platform.Tizen.CarouselViewRenderer; +using CCarouselViewRenderer = Tizen.Wearable.CircularUI.Forms.Renderer.CarouselViewRenderer; + + +[assembly: ExportRenderer(typeof(StructuredItemsView), typeof(CStructuredItemsViewRenderer))] +[assembly: ExportRenderer(typeof(CarouselView), typeof(CCarouselViewRenderer))] + +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class StructuredItemsViewRenderer : XStructuredItemsViewRenderer + { + protected override void UpdateRotaryInteraction(bool enable) + { + if (Element.FindBezelRouter() == null) + { + base.UpdateRotaryInteraction(enable); + } + } + } + + public class CarouselViewRenderer : XCarouselViewRenderer + { + protected override void UpdateRotaryInteraction(bool enable) + { + if (Element.FindBezelRouter() == null) + { + base.UpdateRotaryInteraction(enable); + } + } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/DatePickerRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/DatePickerRenderer.cs new file mode 100644 index 0000000..fa21ebe --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/DatePickerRenderer.cs @@ -0,0 +1,25 @@ +using Xamarin.Forms; + +using XDatePickerRenderer = Xamarin.Forms.Platform.Tizen.DatePickerRenderer; +using CDatePickerRenderer = Tizen.Wearable.CircularUI.Forms.Renderer.DatePickerRenderer; +using System; + +[assembly: ExportRenderer(typeof(DatePicker), typeof(CDatePickerRenderer))] + +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class DatePickerRenderer : XDatePickerRenderer + { + protected override void OnPickerOpened(object sender, EventArgs args) + { + Element.FindBezelController()?.Deactivate(); + base.OnPickerOpened(sender, args); + } + + protected override void OnPickerClosed(object sender, EventArgs args) + { + base.OnPickerClosed(sender, args); + Element.FindBezelController()?.Activate(); + } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/GoogleMapViewRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/GoogleMapViewRenderer.cs index 29c7023..f8788c0 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/GoogleMapViewRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/GoogleMapViewRenderer.cs @@ -15,7 +15,7 @@ */ using System; -using SCObjectModel = System.Collections.ObjectModel; +using OModel = System.Collections.ObjectModel; using System.Collections.Specialized; using System.Text; using Tizen.Wearable.CircularUI.Forms; @@ -59,13 +59,13 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer if (e.OldElement != null) { - ((SCObjectModel.ObservableCollection)e.OldElement.Markers).CollectionChanged -= OnCollectionChanged; + ((OModel.ObservableCollection)e.OldElement.Markers).CollectionChanged -= OnCollectionChanged; e.OldElement.LoadMapRequested -= OnLoadMapRequested; } if (e.NewElement != null) { - ((SCObjectModel.ObservableCollection)e.NewElement.Markers).CollectionChanged += OnCollectionChanged; + ((OModel.ObservableCollection)e.NewElement.Markers).CollectionChanged += OnCollectionChanged; e.NewElement.LoadMapRequested += OnLoadMapRequested; LoadMap(); } @@ -85,7 +85,7 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer } if (Element != null) { - ((SCObjectModel.ObservableCollection)Element.Markers).CollectionChanged -= OnCollectionChanged; + ((OModel.ObservableCollection)Element.Markers).CollectionChanged -= OnCollectionChanged; Element.LoadMapRequested -= OnLoadMapRequested; } } diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/IBezelInteractionController.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/IBezelInteractionController.cs new file mode 100644 index 0000000..043a067 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/IBezelInteractionController.cs @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public interface IBezelInteractionController + { + IRotaryFocusable RotaryFocusObject { get; } + + void Activate(); + void Deactivate(); + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ICircleSurfaceItemRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ICircleSurfaceItemRenderer.cs new file mode 100644 index 0000000..9b617da --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ICircleSurfaceItemRenderer.cs @@ -0,0 +1,9 @@ +using ElmSharp.Wearable; + +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + interface ICircleSurfaceItemRenderer + { + ICircleWidget GetCircleWidget(ICircleSurfaceItem item); + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/IndexPageRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/IndexPageRenderer.cs index 9985603..a41dc3c 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/IndexPageRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/IndexPageRenderer.cs @@ -148,9 +148,10 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer (nativeView as ElmSharp.Widget)?.AllowFocus(true); index++; } - _innerContainer.MinimumWidth = Element.Children.Count * bound.Width; - if (_scroller.HorizontalPageIndex != _pageIndex) + var widthRequest = Element.Children.Count * bound.Width; + _innerContainer.MinimumWidth = widthRequest; + if (_innerContainer.Geometry.Width == widthRequest && _scroller.HorizontalPageIndex != _pageIndex) { _scroller.ScrollTo(_pageIndex, 0, false); } @@ -242,8 +243,8 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer } _pageIndex = Element.Children.IndexOf(Element.CurrentPage); _isUpdateCarousel = true; + Element.UpdateFocusTreePolicy(); _scroller.ScrollTo(_pageIndex, 0, false); - Element.UpdateFocusTreePolicy(); _isUpdateCarousel = false; } diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/InformationPopupImplementation.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/InformationPopupImplementation.cs index df0a943..cbea260 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/InformationPopupImplementation.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/InformationPopupImplementation.cs @@ -255,7 +255,7 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer _bottomButton.Clicked += (s, e) => { - ((IMenuItemController)BottomButton).Activate(); + (BottomButton as IMenuItemController)?.Activate(); }; if (_buttonBgColor != Color.Default) @@ -266,7 +266,7 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer } else { - _bottomButton.Unrealize(); + _bottomButton?.Unrealize(); _bottomButton = null; } diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/LayoutCanvas.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/LayoutCanvas.cs index f1e6119..9e71b65 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/LayoutCanvas.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/LayoutCanvas.cs @@ -16,18 +16,18 @@ using System; using ElmSharp; using System.Collections.Generic; -using System.Collections.ObjectModel; +using OModel = System.Collections.ObjectModel; using System.Collections.Specialized; -using TNative = Xamarin.Forms.Platform.Tizen.Native; +using Xamarin.Forms.Platform.Tizen.Native; namespace Tizen.Wearable.CircularUI.Forms { - public class LayoutCanvas : ElmSharp.Layout, TNative.IContainable + public class LayoutCanvas : ElmSharp.Layout, IContainable { /// /// The list of Views. /// - readonly ObservableCollection _children = new ObservableCollection(); + readonly OModel.ObservableCollection _children = new OModel.ObservableCollection(); Xamarin.Forms.Platform.Tizen.Native.Box _box; @@ -72,7 +72,7 @@ namespace Tizen.Wearable.CircularUI.Forms }; } - public event EventHandler LayoutUpdated + public event EventHandler LayoutUpdated { add { _box.LayoutUpdated += value; } remove { _box.LayoutUpdated -= value; } diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ListViewCache.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ListViewCache.cs deleted file mode 100644 index bb64770..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ListViewCache.cs +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Flora License, Version 1.1 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://floralicense.org/license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using ElmSharp; -using Xamarin.Forms; -using Xamarin.Forms.Platform.Tizen; -using XForms = Xamarin.Forms.Forms; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - public static class ListViewCache - { - static readonly Dictionary _cellRendererCache = new Dictionary(); - static GenItemClass _informalItemClass; - static GenItemClass _informalItemClassWithoutFishEye; - static GenItemClass _paddingItemClass; - static GroupTextCellRenderer _groupCache; - - public static CellRenderer Get(Cell cell, bool IsGroupHeader) - { - if (IsGroupHeader) - { - if (_groupCache == null) - { - _groupCache = new GroupTextCellRenderer(); - } - return _groupCache; - } - - Type type = cell.GetType(); - CellRenderer renderer; - if (_cellRendererCache.TryGetValue(type, out renderer)) - { - return renderer; - } - else - { - renderer = XForms.GetHandler(type); - if (renderer == null) - { - throw new ArgumentNullException("Unsupported cell type"); - } - return _cellRendererCache[type] = renderer; - } - } - public static CellRenderer Get(Cell cell) => Get(cell, false); - - public static GenItemClass InformalItemClass => _informalItemClass ?? (_informalItemClass = new HeaderOrFooterItemClass()); - public static GenItemClass PaddingItemClass => _paddingItemClass ?? (_paddingItemClass = new PaddingItemClass()); - public static GenItemClass InformalItemClassWithoutFishEye => _informalItemClassWithoutFishEye ?? (_informalItemClassWithoutFishEye = new HeaderOrFooterItemClass(false)); - } - - public class HeaderOrFooterItemClass : GenItemClass - { - static int ToPx(double dp) - { - return (int)Math.Round(dp * Device.Info.ScalingFactor); - } - public HeaderOrFooterItemClass(bool fishEye) : base(fishEye ? "full" : "full_off") - { - GetContentHandler = OnGetContent; - } - - public HeaderOrFooterItemClass() : this(true) - { - } - - protected EvasObject OnGetContent(object data, string part) - { - var ctx = data as TypedItemContext; - if (ctx != null) - { - var element = ctx.Element; - var renderer = Platform.GetOrCreateRenderer(element); - if (element.MinimumHeightRequest == -1) - { - var request = element.Measure(double.PositiveInfinity, double.PositiveInfinity); - renderer.NativeView.MinimumHeight = ToPx(request.Request.Height); - } - else - { - renderer.NativeView.MinimumHeight = ToPx(element.MinimumHeightRequest); - } - (renderer as LayoutRenderer)?.RegisterOnLayoutUpdated(); - return renderer.NativeView; - } - return null; - } - } - - public class PaddingItemClass : GenItemClass - { - public PaddingItemClass() : base("padding") - { - } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ListViewRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ListViewRenderer.cs new file mode 100644 index 0000000..c30e78c --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ListViewRenderer.cs @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using Xamarin.Forms; +using XListViewRenderer = Xamarin.Forms.Platform.Tizen.ListViewRenderer; +using CListViewRenderer = Tizen.Wearable.CircularUI.Forms.Renderer.ListViewRenderer; + +[assembly: ExportRenderer(typeof(ListView), typeof(CListViewRenderer))] +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class ListViewRenderer : XListViewRenderer + { + protected override void UpdateRotaryInteraction(bool enable) + { + if (Element.FindBezelRouter() == null) + { + base.UpdateRotaryInteraction(enable); + } + } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/NativeCirclePage.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/NativeCirclePage.cs index ef0bc84..deddd0a 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/NativeCirclePage.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/NativeCirclePage.cs @@ -28,7 +28,7 @@ using ERotaryEventManager = ElmSharp.Wearable.RotaryEventManager; namespace Tizen.Wearable.CircularUI.Forms.Renderer { - public class NativeCirclePage : ObservableBox + class NativeCirclePage : ObservableBox { ElmSharp.Rectangle _bgColorObject; ElmSharp.EvasImage _bgImageObject; @@ -154,6 +154,10 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer public void ActivateRotaryWidget() { + CirclePage cp = _element as CirclePage; + if (!cp.Appeared) + return; + if (_currentRotaryFocusObject is IRotaryEventReceiver) { ERotaryEventManager.Rotated += OnRotaryEventChanged; diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/NativeFactory.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/NativeFactory.cs index 301e0b7..cb30e7d 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/NativeFactory.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/NativeFactory.cs @@ -21,9 +21,9 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer page.Hide(); circlePages.Add(page); - var listview = new CircleListView(window, page.Surface); - listview.Hide(); - circleListviews.Add(page.Surface, listview); + //var listview = new CircleListView(window, page.Surface); + //listview.Hide(); + //circleListviews.Add(page.Surface, listview); var scroller = new CircleScroller(window, page.Surface); scroller.Hide(); @@ -45,16 +45,16 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer } else if (type == typeof(CircleListView)) { - if (circleListviews.ContainsKey(surface)) - { - var listview = circleListviews[surface]; - if (listview != null) - { - circleListviews.Remove(surface); - return listview; - } - } - return new CircleListView(XForms.NativeParent, surface); + //if (circleListviews.ContainsKey(surface)) + //{ + // var listview = circleListviews[surface]; + // if (listview != null) + // { + // circleListviews.Remove(surface); + // return listview; + // } + //} + //return new CircleListView(XForms.NativeParent, surface); } else if (type == typeof(CircleScroller)) { @@ -80,11 +80,11 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer } circlePages.Clear(); - foreach (var item in circleListviews) - { - item.Value.Unrealize(); - } - circleListviews.Clear(); + //foreach (var item in circleListviews) + //{ + // item.Value.Unrealize(); + //} + //circleListviews.Clear(); foreach (var item in circleScrollers) { diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ObservableBox.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ObservableBox.cs index 265f955..0c28ba0 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ObservableBox.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ObservableBox.cs @@ -17,15 +17,11 @@ using System.Collections.Generic; using System.Collections.Specialized; using ElmSharp; -using Tizen.Wearable.CircularUI.Forms; -using Xamarin.Forms; using Xamarin.Forms.Platform.Tizen.Native; -[assembly: ExportRenderer(typeof(CirclePage), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CirclePageRenderer))] - namespace Tizen.Wearable.CircularUI.Forms.Renderer { - public class ObservableBox : ElmSharp.Box, IContainable + class ObservableBox : ElmSharp.Box, IContainable { ReObservableCollection _children; public ObservableBox(EvasObject parent) : base(parent) diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/PageRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/PageRenderer.cs new file mode 100644 index 0000000..c2bc4fb --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/PageRenderer.cs @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using Xamarin.Forms; +using Xamarin.Forms.Platform.Tizen; +using Xamarin.Forms.Platform.Tizen.Native.Watch; +using XPageRenderer = Xamarin.Forms.Platform.Tizen.PageRenderer; +using CPageRenderer = Tizen.Wearable.CircularUI.Forms.Renderer.PageRenderer; + +[assembly: ExportRenderer(typeof(Page), typeof(CPageRenderer))] +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class PageRenderer : XPageRenderer + { + protected override FormsMoreOptionItem CreateMoreOptionItem(ToolbarItem item) + { + var moreOptionItem = base.CreateMoreOptionItem(item); + if (item is CircleToolbarItem circleToolbarItem) + { + moreOptionItem.SubText = circleToolbarItem.SubText; + } + return moreOptionItem; + } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/PopupEntryRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/PopupEntryRenderer.cs index 6e4b6cf..20e24fd 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/PopupEntryRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/PopupEntryRenderer.cs @@ -183,6 +183,7 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer { CreatePopup(); } + _editor.IsPassword = Control.IsPassword; if (Control is IEntry ie) { diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/RadioRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/RadioRenderer.cs index de8112a..b27e89a 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/RadioRenderer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/RadioRenderer.cs @@ -25,8 +25,10 @@ using ERadio = ElmSharp.Radio; using XForms = Xamarin.Forms.Forms; [assembly: ExportRenderer(typeof(Radio), typeof(RadioRenderer))] + namespace Tizen.Wearable.CircularUI.Forms.Renderer { + public class RadioRenderer : ViewRenderer { static Lazy s_GroupManager = new Lazy(); diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ScrollViewRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ScrollViewRenderer.cs new file mode 100644 index 0000000..cfa2f32 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ScrollViewRenderer.cs @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using Xamarin.Forms; +using XScrollViewRenderer = Xamarin.Forms.Platform.Tizen.ScrollViewRenderer; +using CScrollViewRenderer = Tizen.Wearable.CircularUI.Forms.Renderer.ScrollViewRenderer; + +[assembly: ExportRenderer(typeof(ScrollView), typeof(CScrollViewRenderer))] +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class ScrollViewRenderer : XScrollViewRenderer + { + protected override void UpdateRotaryInteraction(bool enable) + { + if (Element.FindBezelRouter() == null) + { + base.UpdateRotaryInteraction(enable); + } + } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellRenderer.cs new file mode 100644 index 0000000..14cc4f9 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellRenderer.cs @@ -0,0 +1,78 @@ +using ElmSharp; +using System; +using System.Linq; +using Xamarin.Forms; +using Xamarin.Forms.Platform.Tizen; +using XShell = Xamarin.Forms.Shell; +using NavigationDrawer = Xamarin.Forms.Platform.Tizen.Watch.NavigationDrawer; +using NavigationView = Xamarin.Forms.Platform.Tizen.Watch.NavigationView; + +[assembly: ExportRenderer(typeof(XShell), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.CircularShellRenderer))] +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class CircularShellRenderer : Xamarin.Forms.Platform.Tizen.Watch.ShellRenderer + { + + NavigationDrawer _drawer; + NavigationView _navigationView; + + public CircularShellRenderer() + { + RegisterPropertyHandler(CircularShell.FlyoutIconBackgroundColorProperty, UpdateFlyoutIconBackgroundColor); + RegisterPropertyHandler(CircularShell.FlyoutForegroundColorProperty, UpdateFlyoutForegroundColor); + } + + protected override NavigationDrawer CreateNavigationDrawer(EvasObject parent) + { + return _drawer = base.CreateNavigationDrawer(parent); + } + + protected override NavigationView CreateNavigationView(EvasObject parent) + { + return _navigationView = base.CreateNavigationView(parent); + } + + protected override void OnNavigationDrawerToggled(object sender, EventArgs e) + { + base.OnNavigationDrawerToggled(sender, e); + if (!Element.FlyoutIsPresented) + { + var currentPage = GetCurrentPage(Element); + + if (currentPage != null) + { + var renderer = Platform.GetOrCreateRenderer(currentPage); + (renderer as IBezelInteractionController)?.Activate(); + } + } + } + + void UpdateFlyoutIconBackgroundColor() + { + _drawer.HandlerBackgroundColor = CircularShell.GetFlyoutIconBackgroundColor(Element).ToNative(); + } + + void UpdateFlyoutForegroundColor(bool init) + { + if (init && CircularShell.GetFlyoutForegroundColor(Element).IsDefault) + return; + + if (_navigationView != null) + { + _navigationView.ForegroundColor = CircularShell.GetFlyoutForegroundColor(Element).ToNative(); + } + } + + static Page GetCurrentPage(XShell shell) + { + var stack = (shell.CurrentItem.CurrentItem as ShellSection)?.Stack; + var currentPage = stack?.LastOrDefault(); + + if (currentPage == null) + { + currentPage = (shell.CurrentItem.CurrentItem.CurrentItem as IShellContentController)?.Page; + } + return currentPage; + } + } +} diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellRendererFactory.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellRendererFactory.cs new file mode 100644 index 0000000..5294de1 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellRendererFactory.cs @@ -0,0 +1,22 @@ +using Xamarin.Forms; +using Xamarin.Forms.Platform.Tizen.Watch; + +namespace Tizen.Wearable.CircularUI.Forms.Renderer.Shell +{ + class CircularShellRendererFactory : ShellRendererFactory + { + public static void Setup() + { + Default = new CircularShellRendererFactory(); + } + + public override IShellItemRenderer CreateItemRenderer(ShellSection item) + { + if (item.Items.Count == 1) + { + return CreateItemRenderer(item.CurrentItem); + } + return new CircularShellSectionItemsRenderer(item); + } + } +} diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellSectionItemsRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellSectionItemsRenderer.cs new file mode 100644 index 0000000..0ba03f5 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/CircularShellSectionItemsRenderer.cs @@ -0,0 +1,34 @@ +using System.Linq; +using Xamarin.Forms; +using Xamarin.Forms.Platform.Tizen; +using Xamarin.Forms.Platform.Tizen.Watch; + +namespace Tizen.Wearable.CircularUI.Forms.Renderer.Shell +{ + public class CircularShellSectionItemsRenderer : ShellSectionItemsRenderer + { + public CircularShellSectionItemsRenderer(ShellSection section) : base(section) + { + } + + protected override bool OnRotated(bool isClockwise) + { + var currentPage = GetCurrentPage(ShellSection); + if (currentPage is IBezelInteractionRouter) + { + var renderer = Platform.GetOrCreateRenderer(currentPage); + if (renderer is IBezelInteractionController bezelController) + { + bezelController.Activate(); + return false; + } + } + return base.OnRotated(isClockwise); + } + + Page GetCurrentPage(ShellSection section) + { + return section?.Stack?.LastOrDefault() ?? (section?.CurrentItem as IShellContentController)?.Page; + } + } +} diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/IShellItemRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/IShellItemRenderer.cs deleted file mode 100644 index aeffc75..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/IShellItemRenderer.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using ElmSharp; -using Xamarin.Forms; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - public interface IShellItemRenderer : IDisposable - { - BaseShellItem Item { get; } - EvasObject NativeView { get; } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationDrawer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationDrawer.cs deleted file mode 100644 index 342021d..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationDrawer.cs +++ /dev/null @@ -1,543 +0,0 @@ -using ElmSharp; -using ElmSharp.Wearable; -using System; -using System.Threading; -using System.Threading.Tasks; -using Xamarin.Forms; -using Xamarin.Forms.Platform.Tizen; -using EColor = ElmSharp.Color; -using EImage = ElmSharp.Image; -using ELayout = ElmSharp.Layout; -using EWidget = ElmSharp.Widget; -using EButton = ElmSharp.Button; -using ERotaryEventManager = ElmSharp.Wearable.RotaryEventManager; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - public class NavigationDrawer : ELayout, IAnimatable - { - static readonly int TouchWidth = 50; - static readonly int IconSize = 40; - static readonly string DefaultIcon = "Tizen.Wearable.CircularUI.Forms.Renderer.res.wc_visual_cue.png"; - - Box _mainLayout; - Box _contentGestureBox; - Box _contentBox; - Box _drawerBox; - Box _drawerContentBox; - Box _drawerIconBox; - - EvasObject _content; - EvasObject _drawerContent; - - EImage _drawerIcon; - EButton _touchArea; - - GestureLayer _gestureOnContent; - GestureLayer _gestureOnDrawer; - - ImageSource _drawerIconSource; - - bool _isOpen; - bool _isDefaultIcon; - - CancellationTokenSource _fadeInCancelTokenSource = null; - - bool HasDrawer => _drawerBox != null; - - public NavigationDrawer(EvasObject parent) : base(parent) - { - Initialize(); - } - - public int HandlerHeight { get; set; } = 40; - - public bool IsOpen - { - get - { - return _isOpen; - } - set - { - if (_isOpen != value) - { - if (value) - { - Open(); - } - else - { - Close(); - } - } - } - } - - EColor _handlerBackgroundColor = EColor.Transparent; - public EColor HandlerBackgroundColor - { - get => _handlerBackgroundColor; - set - { - _handlerBackgroundColor = value; - UpdateHandlerBackgroundColor(); - } - } - - public event EventHandler Toggled; - - public void SetMainContent(EvasObject content) - { - if (content == null) - { - UnsetMainContent(); - return; - } - - _content = content; - _content.Show(); - _contentBox.PackEnd(_content); - _content.Geometry = _contentBox.Geometry; - } - - public void SetDrawerContent(EvasObject content) - { - InitializeDrawerBox(); - - if (content == null) - { - UnsetDrawerContent(); - return; - } - - _drawerContent = content; - _drawerContent.Show(); - _drawerContentBox.PackEnd(_drawerContent); - - _drawerContentBox.Show(); - _drawerIconBox.Show(); - - if (_drawerContent is NavigationView nv) - { - nv.Dragged += (s, e) => - { - if (e.State == DraggedState.EdgeTop) - { - Close(); - } - }; - } - } - - public void UpdateDrawerIcon(ImageSource source) - { - _drawerIconSource = source; - if (HasDrawer) - { - SetDrawerIcon(_drawerIconSource); - } - } - - public async void Open(uint length = 300) - { - if (!HasDrawer) - return; - - var toMove = _drawerBox.Geometry; - toMove.Y = 0; - - await RunMoveAnimation(_drawerBox, toMove, length); - - if (!_isOpen) - { - _isOpen = true; - Toggled?.Invoke(this, EventArgs.Empty); - } - OnLayout(); - OnDrawerLayout(); - FlipIcon(); - } - - public async void Close(uint length = 300) - { - if (!HasDrawer) - return; - - var toMove = _drawerBox.Geometry; - toMove.Y = Geometry.Height - HandlerHeight; - - await RunMoveAnimation(_drawerBox, toMove, length); - - if (_isOpen) - { - _isOpen = false; - Toggled?.Invoke(this, EventArgs.Empty); - } - OnLayout(); - OnDrawerLayout(); - ResetIcon(); - StartHighlightAnimation(_drawerIcon); - } - - void IAnimatable.BatchBegin() - { - } - - void IAnimatable.BatchCommit() - { - } - - protected override IntPtr CreateHandle(EvasObject parent) - { - _mainLayout = new Box(parent); - return _mainLayout.Handle; - } - - void Initialize() - { - _mainLayout.SetLayoutCallback(OnLayout); - - _contentGestureBox = new Box(_mainLayout); - _contentGestureBox.Show(); - _mainLayout.PackEnd(_contentGestureBox); - - _contentBox = new Box(_mainLayout); - _contentBox.SetLayoutCallback(OnContentLayout); - _contentBox.Show(); - _mainLayout.PackEnd(_contentBox); - } - - void InitializeDrawerBox() - { - if (_drawerBox != null) - return; - - _drawerBox = new Box(_mainLayout); - _drawerBox.SetLayoutCallback(OnDrawerLayout); - _drawerBox.Show(); - _mainLayout.PackEnd(_drawerBox); - - _drawerContentBox = new Box(_drawerBox); - _drawerBox.PackEnd(_drawerContentBox); - - _drawerIconBox = new Box(_drawerBox) - { - BackgroundColor = _handlerBackgroundColor - }; - _drawerBox.PackEnd(_drawerIconBox); - - _drawerIcon = new EImage(_drawerIconBox) - { - AlignmentY = 0.5, - AlignmentX = 0.5, - MinimumHeight = IconSize, - MinimumWidth = IconSize, - }; - _drawerIcon.Show(); - _drawerIconBox.PackEnd(_drawerIcon); - SetDrawerIcon(_drawerIconSource); - - _touchArea = new EButton(_drawerBox) - { - Color = EColor.Transparent, - BackgroundColor = EColor.Transparent, - }; - _touchArea.SetPartColor("effect", EColor.Transparent); - _touchArea.Show(); - _touchArea.RepeatEvents = true; - _touchArea.Clicked += OnIconClicked; - - _drawerBox.PackEnd(_touchArea); - - _gestureOnContent = new GestureLayer(_contentGestureBox); - _gestureOnContent.SetMomentumCallback(GestureLayer.GestureState.Start, OnContentDragStarted); - _gestureOnContent.SetMomentumCallback(GestureLayer.GestureState.End, OnContentDragEnded); - _gestureOnContent.SetMomentumCallback(GestureLayer.GestureState.Abort, OnContentDragEnded); - _gestureOnContent.Attach(_contentGestureBox); - _contentBox.RepeatEvents = true; - - _gestureOnDrawer = new GestureLayer(_drawerIconBox); - _gestureOnDrawer.SetMomentumCallback(GestureLayer.GestureState.Move, OnDrawerDragged); - _gestureOnDrawer.SetMomentumCallback(GestureLayer.GestureState.End, OnDrawerDragEnded); - _gestureOnDrawer.SetMomentumCallback(GestureLayer.GestureState.Abort, OnDrawerDragEnded); - _gestureOnDrawer.Attach(_drawerIconBox); - - ERotaryEventManager.Rotated += OnRotateEventReceived; - } - - void SetDrawerIcon(ImageSource source) - { - if (source == null) - { - _drawerIcon.LoadFromImageSourceAsync(ImageSource.FromResource(DefaultIcon, GetType().Assembly)); - _isDefaultIcon = true; - } - else - { - _isDefaultIcon = false; - if (source is FileImageSource fsource) - { - _drawerIcon.Load(fsource.ToAbsPath()); - } - else - { - _drawerIcon.LoadFromImageSourceAsync(source); - } - } - } - - void UpdateHandlerBackgroundColor() - { - if (_drawerIconBox != null) - { - _drawerIconBox.BackgroundColor = _handlerBackgroundColor; - } - } - - void OnIconClicked(object sender, EventArgs e) - { - if (IsOpen) - Close(); - else - Open(); - } - - async Task ShowAsync(EWidget target, Easing easing = null, uint length = 300, CancellationToken cancelltaionToken = default(CancellationToken)) - { - var tcs = new TaskCompletionSource(); - - await Task.Delay(1000); - - if (cancelltaionToken.IsCancellationRequested) - { - cancelltaionToken.ThrowIfCancellationRequested(); - } - - target.Show(); - var opacity = target.Opacity; - - if (opacity == 255 || opacity == -1) - return true; - - new Animation((progress) => - { - target.Opacity = opacity + (int)((255 - opacity) * progress); - - }).Commit(this, "FadeIn", length: length, finished: (p, e) => - { - target.Opacity = 255; - tcs.SetResult(true); - StartHighlightAnimation(_drawerIcon); - }); - - return await tcs.Task; - } - - void OnLayout() - { - var bound = Geometry; - _contentGestureBox.Geometry = bound; - _contentBox.Geometry = bound; - if (_drawerBox != null) - { - bound.Y = _isOpen ? 0 : (bound.Height - HandlerHeight); - _drawerBox.Geometry = bound; - } - } - - void OnContentLayout() - { - if (_content != null) - { - _content.Geometry = _contentBox.Geometry; - } - } - - void OnDrawerLayout() - { - this.AbortAnimation("HighlightAnimation"); - - var bound = _drawerBox.Geometry; - - var currentY = bound.Y; - var ratio = currentY / (double)(Geometry.Height - HandlerHeight); - - var contentBound = bound; - contentBound.Y += (int)(HandlerHeight * ratio); - _drawerContentBox.Geometry = contentBound; - - var drawerHandleBound = bound; - drawerHandleBound.Height = HandlerHeight; - _drawerIconBox.Geometry = drawerHandleBound; - - var drawerTouchBound = drawerHandleBound; - drawerTouchBound.Width = TouchWidth; - drawerTouchBound.X = drawerHandleBound.X + (drawerHandleBound.Width - TouchWidth) / 2; - _touchArea.Geometry = drawerTouchBound; - } - - async Task HideAsync(EWidget target, Easing easing = null, uint length = 300) - { - var tcs = new TaskCompletionSource(); - - var opacity = target.Opacity; - if (opacity == -1) - opacity = 255; - - new Animation((progress) => - { - target.Opacity = opacity - (int)(progress * opacity); - - }).Commit(this, "FadeOut", length: length, finished: (p, e) => - { - target.Opacity = 0; - target.Hide(); - tcs.SetResult(true); - }); - - return await tcs.Task; - } - - void StartHighlightAnimation(EWidget target) - { - if (!_isDefaultIcon || this.AnimationIsRunning("HighlightAnimation")) - return; - - int count = 2; - var bound = target.Geometry; - var y = bound.Y; - var dy = bound.Y - bound.Height / 3; - - var anim = new Animation(); - - var transfAnim = new Animation((f) => - { - bound.Y = (int)f; - var map = new EvasMap(4); - map.PopulatePoints(bound, 0); - target.IsMapEnabled = true; - target.EvasMap = map; - }, y, dy); - - var opacityAnim = new Animation(f => target.Opacity = (int)f, 255, 40); - - anim.Add(0, 1, opacityAnim); - anim.Add(0, 1, transfAnim); - - anim.Commit(this, "HighlightAnimation", 16, 800, finished: (f, b) => - { - target.Opacity = 255; - target.IsMapEnabled = false; - }, repeat:() => --count > 0); - } - - async void OnRotateEventReceived(EventArgs args) - { - _fadeInCancelTokenSource?.Cancel(); - _fadeInCancelTokenSource = new CancellationTokenSource(); - - if (!_isOpen) - { - var token = _fadeInCancelTokenSource.Token; - await HideAsync(_drawerBox); - _ = ShowAsync(_drawerBox, cancelltaionToken: token); - } - } - - void OnContentDragStarted(GestureLayer.MomentumData moment) - { - _fadeInCancelTokenSource?.Cancel(); - _fadeInCancelTokenSource = null; - - if (!_isOpen) - { - _ = HideAsync(_drawerBox); - } - } - - void OnContentDragEnded(GestureLayer.MomentumData moment) - { - _fadeInCancelTokenSource = new CancellationTokenSource(); - _ = ShowAsync(_drawerBox, cancelltaionToken: _fadeInCancelTokenSource.Token); - } - - void OnDrawerDragged(GestureLayer.MomentumData moment) - { - var toMove = _drawerBox.Geometry; - toMove.Y = (moment.Y2 < 0) ? 0 : moment.Y2; - _drawerBox.Geometry = toMove; - OnDrawerLayout(); - } - - void OnDrawerDragEnded(GestureLayer.MomentumData moment) - { - if (_drawerBox.Geometry.Y < (_mainLayout.Geometry.Height / 2)) - { - Open(); - } - else - { - Close(); - } - } - - void FlipIcon() - { - if (_isDefaultIcon) - { - _drawerIcon.Orientation = ImageOrientation.FlipVertical; - } - } - - void ResetIcon() - { - _drawerIcon.Orientation = ImageOrientation.None; - } - - Task RunMoveAnimation(EvasObject target, Rect dest, uint length, Easing easing = null) - { - var tcs = new TaskCompletionSource(); - - var dx = target.Geometry.X - dest.X; - var dy = target.Geometry.Y - dest.Y; - - new Animation((progress) => - { - var toMove = dest; - toMove.X += (int)(dx * (1 - progress)); - toMove.Y += (int)(dy * (1 - progress)); - target.Geometry = toMove; - OnDrawerLayout(); - }).Commit(this, "Move", length: length, finished: (s, e) => - { - target.Geometry = dest; - tcs.SetResult(true); - }); - return tcs.Task; - } - - void UnsetMainContent() - { - if (_content != null) - { - _contentBox.UnPack(_content); - _content.Hide(); - _content = null; - } - } - - void UnsetDrawerContent() - { - if (_drawerContent != null) - { - _drawerContentBox.UnPack(_drawerContent); - _drawerContent.Hide(); - _drawerContent = null; - - _drawerContentBox.Hide(); - _drawerIconBox.Hide(); - } - } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationView.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationView.cs deleted file mode 100644 index bd07f3c..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationView.cs +++ /dev/null @@ -1,365 +0,0 @@ -using ElmSharp; -using ElmSharp.Wearable; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; -using Xamarin.Forms; -using Xamarin.Forms.Platform.Tizen; -using EColor = ElmSharp.Color; -using ELayout = ElmSharp.Layout; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - public class NavigationView : ELayout - { - readonly int _dafaultIconSize = 60; - - class Item : INotifyPropertyChanged - { - Element _source; - public Element Source - { - get - { - return _source; - } - set - { - if (_source != null) - { - _source.PropertyChanged -= OnElementPropertyChanged; - } - _source = value; - _source.PropertyChanged += OnElementPropertyChanged; - UpdateContent(); - } - } - - public string Text { get; set; } - public string Icon { get; set; } - - public event PropertyChangedEventHandler PropertyChanged; - - void UpdateContent() - { - if (Source is BaseShellItem shellItem) - { - Text = shellItem.Title; - Icon = (shellItem.Icon as FileImageSource)?.ToAbsPath(); - } - else if (Source is MenuItem menuItem) - { - Text = menuItem.Text; - Icon = (menuItem.IconImageSource as FileImageSource)?.ToAbsPath(); - } - else - { - Text = null; - Icon = null; - } - SendPropertyChanged(); - } - - void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) - { - UpdateContent(); - } - - void SendPropertyChanged([CallerMemberName] string propertyName = "") - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } - - Box _outterBox; - ELayout _surfaceLayout; - CircleSurface _surface; - CircleGenList _naviMenu; - - GenItemClass _defaultClass; - SmartEvent _draggedUpCallback; - SmartEvent _draggedDownCallback; - - GenListItem _header; - GenListItem _footer; - - List> _itemCache; - List _items = new List(); - - public NavigationView(EvasObject parent) : base(parent) - { - InitializeComponent(); - } - - public event EventHandler ItemSelected; - - public event EventHandler Dragged; - - - EColor _backgroundColor = EColor.Black; - public override EColor BackgroundColor - { - get => _backgroundColor; - set - { - _backgroundColor = value.IsDefault ? EColor.Black : value; - UpdateBackgroundColor(); - } - } - - EColor _foregroundColor = EColor.Default; - public EColor ForegroundColor - { - get => _foregroundColor; - set - { - _foregroundColor = value; - UpdateForegroundColor(); - } - } - - - public void Build(List> items) - { - // Only update when items was changed - if (!IsUpdated(items)) - { - return; - } - _itemCache = items; - - ClearItemPropertyChangedHandler(); - _naviMenu.Clear(); - _items.Clear(); - // header - _header = _naviMenu.Append(_defaultClass, new Item { Text = "" }); - - // TODO. need to improve, need to support group - foreach (var group in items) - { - foreach (var item in group) - { - var data = new Item - { - Source = item - }; - if (item is BaseShellItem shellItem) - { - data.Text = shellItem.Title; - data.Icon = (shellItem.Icon as FileImageSource)?.ToAbsPath(); - } - else if (item is MenuItem menuItem) - { - data.Text = menuItem.Text; - data.Icon = (menuItem.IconImageSource as FileImageSource)?.ToAbsPath(); - } - var genitem = _naviMenu.Append(_defaultClass, data, GenListItemType.Normal); - genitem.SetPartColor("bg", _backgroundColor); - _items.Add(genitem); - data.PropertyChanged += OnItemPropertyChanged; - } - } - _footer = _naviMenu.Append(_defaultClass, new Item { Text = "" }); - } - - public void Activate() - { - (_naviMenu as IRotaryActionWidget)?.Activate(); - } - public void Deactivate() - { - (_naviMenu as IRotaryActionWidget)?.Deactivate(); - } - - protected override IntPtr CreateHandle(EvasObject parent) - { - _outterBox = new Box(parent); - return _outterBox.Handle; - } - - void InitializeComponent() - { - _outterBox.SetLayoutCallback(OnLayout); - - _surfaceLayout = new ELayout(this); - _surfaceLayout.Show(); - _surface = new CircleSurface(_surfaceLayout); - - _naviMenu = new CircleGenList(this, _surface) - { - Homogeneous = true, - BackgroundColor = _backgroundColor - }; - _naviMenu.Show(); - - _draggedUpCallback = new SmartEvent(_naviMenu, "drag,start,up"); - _draggedUpCallback.On += (s, e) => - { - if (_footer.TrackObject.IsVisible) - { - Dragged?.Invoke(this, new DraggedEventArgs(DraggedState.EdgeBottom)); - } - else - { - Dragged?.Invoke(this, new DraggedEventArgs(DraggedState.Up)); - } - }; - - _draggedDownCallback = new SmartEvent(_naviMenu, "drag,start,down"); - _draggedDownCallback.On += (s, e) => - { - if (_header.TrackObject.IsVisible) - { - Dragged?.Invoke(this, new DraggedEventArgs(DraggedState.EdgeTop)); - } - else - { - Dragged?.Invoke(this, new DraggedEventArgs(DraggedState.Down)); - } - }; - - _outterBox.PackEnd(_naviMenu); - _outterBox.PackEnd(_surfaceLayout); - - _surfaceLayout.StackAbove(_naviMenu); - - _defaultClass = new GenItemClass("1icon_1text") - { - GetTextHandler = (obj, part) => - { - if (part == "elm.text") - { - var text = (obj as Item).Text; - if (_foregroundColor != EColor.Default) - return $"{text}"; - else - return text; - } - return null; - }, - GetContentHandler = (obj, part) => - { - if (part == "elm.swallow.icon" && obj is Item menuItem && !string.IsNullOrEmpty(menuItem.Icon)) - { - var icon = new ElmSharp.Image(Xamarin.Forms.Forms.NativeParent) - { - AlignmentX = -1, - AlignmentY = -1, - WeightX = 1.0, - WeightY = 1.0, - MinimumWidth = _dafaultIconSize, - MinimumHeight = _dafaultIconSize, - }; - icon.Show(); - icon.Load(menuItem.Icon); - return icon; - } - return null; - } - }; - - _naviMenu.ItemSelected += OnItemSelected; - - } - - void OnItemSelected(object sender, GenListItemEventArgs e) - { - ItemSelected?.Invoke(this, new SelectedItemChangedEventArgs((e.Item.Data as Item).Source, -1)); - } - - void OnLayout() - { - _surfaceLayout.Geometry = Geometry; - _naviMenu.Geometry = Geometry; - } - - void UpdateBackgroundColor() - { - _naviMenu.BackgroundColor = _backgroundColor; - foreach (var item in _items) - { - item.SetPartColor("bg", _backgroundColor); - } - } - - void UpdateForegroundColor() - { - foreach (var item in _items) - { - item.Update(); - } - } - - bool IsUpdated(List> items) - { - if (_itemCache == null) - return true; - - if (_itemCache.Count != items.Count) - return true; - - for (int i = 0; i < items.Count; i++) - { - if (_itemCache[i].Count != items[i].Count) - return true; - - for (int j = 0; j < items[i].Count; j++) - { - if (_itemCache[i][j] != items[i][j]) - return true; - } - } - return false; - } - - void ClearItemPropertyChangedHandler() - { - foreach (var item in _items) - { - (item.Data as Item).PropertyChanged -= OnItemPropertyChanged; - } - } - - void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e) - { - var item = _items.Where((d) => d.Data == sender).FirstOrDefault(); - item?.Update(); - } - - } - public enum DraggedState - { - EdgeTop, - Up, - Down, - EdgeBottom, - } - - public class DraggedEventArgs - { - public DraggedState State { get; private set; } - - public DraggedEventArgs(DraggedState state) - { - State = state; - } - } - - static class FileImageSourceEX - { - public static string ToAbsPath(this FileImageSource source) - { - return ResourcePath.GetPath(source.File); - } - } - - static class ColorEX - { - public static string ToHex(this EColor c) - { - return string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", c.R, c.G, c.B, c.A); - } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellContentRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellContentRenderer.cs deleted file mode 100644 index 47c0673..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellContentRenderer.cs +++ /dev/null @@ -1,40 +0,0 @@ -using ElmSharp; -using Xamarin.Forms; -using Xamarin.Forms.Platform.Tizen; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - public class ShellContentRenderer : IShellItemRenderer - { - public ShellContentRenderer(ShellContent content) - { - ShellContent = content; - NativeView = GetNativeView(content); - } - - public ShellContent ShellContent { get; protected set; } - - public BaseShellItem Item => ShellContent; - - public EvasObject NativeView { get; protected set; } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - NativeView?.Unrealize(); - } - } - - static EvasObject GetNativeView(ShellContent content) - { - var page = (content as IShellContentController).GetOrCreateContent(); - return Platform.GetOrCreateRenderer(page).NativeView; - } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellItemRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellItemRenderer.cs deleted file mode 100644 index 908851a..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellItemRenderer.cs +++ /dev/null @@ -1,97 +0,0 @@ -using ElmSharp; -using System.Collections.Generic; -using System.ComponentModel; -using Xamarin.Forms; -using XForms = Xamarin.Forms.Forms; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - public class ShellItemRenderer : IShellItemRenderer - { - Box _mainLayout; - EvasObject _currentItem; - Dictionary _rendererCache = new Dictionary(); - - public ShellItemRenderer(ShellItem item) - { - ShellItem = item; - ShellItem.PropertyChanged += OnItemPropertyChanged; - InitializeComponent(); - UpdateCurrentItem(); - } - - public ShellItem ShellItem { get; protected set; } - - public BaseShellItem Item => ShellItem; - - public EvasObject NativeView => _mainLayout; - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - ResetCurrentItem(); - ShellItem.PropertyChanged -= OnItemPropertyChanged; - } - } - - void InitializeComponent() - { - _mainLayout = new Box(XForms.NativeParent); - _mainLayout.SetLayoutCallback(OnLayout); - } - - void UpdateCurrentItem() - { - ResetCurrentItem(); - var currentItem = ShellItem.CurrentItem; - if (currentItem != null) - { - if (!_rendererCache.TryGetValue(currentItem, out IShellItemRenderer renderer)) - { - renderer = ShellRendererFactory.Default.CreateShellNavigationRenderer(currentItem); - _rendererCache[currentItem] = renderer; - } - SetCurrentItem(renderer.NativeView); - } - } - - void SetCurrentItem(EvasObject item) - { - _currentItem = item; - _currentItem.Show(); - _mainLayout.PackEnd(_currentItem); - } - - void ResetCurrentItem() - { - if (_currentItem != null) - { - _mainLayout.UnPack(_currentItem); - _currentItem.Hide(); - _currentItem = null; - } - } - - void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(ShellItem.CurrentItem)) - { - UpdateCurrentItem(); - } - } - - void OnLayout() - { - if (_currentItem != null) - { - _currentItem.Geometry = _mainLayout.Geometry; - } - } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRenderer.cs deleted file mode 100644 index 525e369..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRenderer.cs +++ /dev/null @@ -1,242 +0,0 @@ -using ElmSharp; -using System; -using System.Collections.Generic; -using System.Linq; -using Xamarin.Forms; -using Xamarin.Forms.Platform.Tizen; -using XForms = Xamarin.Forms.Forms; -using XShell = Xamarin.Forms.Shell; -using Tizen.Wearable.CircularUI.Forms; - -[assembly: ExportRenderer(typeof(CircularShell), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.ShellRenderer))] -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - public class ShellRenderer : VisualElementRenderer - { - NavigationDrawer _drawer; - NavigationView _navigationView; - - Dictionary _rendererCache = new Dictionary(); - - public ShellRenderer() - { - RegisterPropertyHandler(XShell.CurrentItemProperty, UpdateCurrentItem); - RegisterPropertyHandler(XShell.FlyoutIsPresentedProperty, UpdateFlyoutIsPresented); - RegisterPropertyHandler(XShell.FlyoutBehaviorProperty, UpdateFlyoutBehavior); - RegisterPropertyHandler(XShell.FlyoutIconProperty, UpdateFlyoutIcon); - RegisterPropertyHandler(XShell.FlyoutBackgroundColorProperty, UpdateFlyoutBackgroundColor); - RegisterPropertyHandler(CircularShell.FlyoutIconBackgroundColorProperty, UpdateFlyoutIconBackgroundColor); - RegisterPropertyHandler(CircularShell.FlyoutForegroundColorProperty, UpdateFlyoutForegroundColor); - } - - protected override void OnElementChanged(ElementChangedEventArgs e) - { - InitializeComponent(); - base.OnElementChanged(e); - } - - protected override void OnElementReady() - { - base.OnElementReady(); - UpdateFlyoutMenu(); - (Element as IShellController).StructureChanged += OnNavigationStructureChanged; - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - foreach (var renderer in _rendererCache.Values) - { - renderer.Dispose(); - } - (Element as IShellController).StructureChanged -= OnNavigationStructureChanged; - } - base.Dispose(disposing); - } - - void InitializeComponent() - { - if (_drawer == null) - { - _drawer = new NavigationDrawer(XForms.NativeParent); - _drawer.IsOpen = Element.FlyoutIsPresented; - _drawer.Toggled += OnNavigationDrawerToggled; - SetNativeView(_drawer); - } - } - - void OnNavigationStructureChanged(object sender, EventArgs e) - { - UpdateFlyoutMenu(); - } - - void UpdateFlyoutMenu() - { - if (Element.FlyoutBehavior == FlyoutBehavior.Disabled) - return; - - var flyoutItems = (Element as IShellController).GenerateFlyoutGrouping(); - int itemCount = 0; - foreach (var item in flyoutItems) - { - itemCount += item.Count; - } - - if (itemCount > 1) - { - InitializeNavigationDrawer(); - _navigationView.Build(flyoutItems); - } - else - { - DeinitializeNavigationView(); - } - } - - void InitializeNavigationDrawer() - { - if (_navigationView != null) - { - return; - } - - _navigationView = new NavigationView(XForms.NativeParent) - { - AlignmentX = -1, - AlignmentY = -1, - WeightX = 1, - WeightY = 1, - }; - _navigationView.Show(); - _navigationView.ItemSelected += OnMenuItemSelected; - - _drawer.SetDrawerContent(_navigationView); - } - - void OnNavigationDrawerToggled(object sender, EventArgs e) - { - if (_drawer.IsOpen) - { - _navigationView.Activate(); - } - else - { - _navigationView.Deactivate(); - - var stack = (Element.CurrentItem.CurrentItem as ShellSection)?.Stack; - var currentPage = stack?.LastOrDefault(); - - if (currentPage == null) - { - currentPage = (Element.CurrentItem.CurrentItem.CurrentItem as IShellContentController)?.Page; - } - - if (currentPage != null) - { - var renderer = Platform.GetOrCreateRenderer(currentPage); - (renderer as CirclePageRenderer)?.UpdateRotaryFocusObject(); - } - } - - Element.SetValueFromRenderer(XShell.FlyoutIsPresentedProperty, _drawer.IsOpen); - } - - void DeinitializeNavigationView() - { - if (_navigationView == null) - return; - _drawer.SetDrawerContent(null); - _navigationView.Unrealize(); - _navigationView = null; - } - - void OnMenuItemSelected(object sender, SelectedItemChangedEventArgs e) - { - ((IShellController)Element).OnFlyoutItemSelected(e.SelectedItem as Element); - } - - void UpdateCurrentItem() - { - ResetCurrentItem(); - if (Element.CurrentItem != null) - { - if (!_rendererCache.TryGetValue(Element.CurrentItem, out IShellItemRenderer renderer)) - { - renderer = ShellRendererFactory.Default.CreateItemRenderer(Element.CurrentItem); - _rendererCache[Element.CurrentItem] = renderer; - } - SetCurrentItem(renderer.NativeView); - } - } - - void UpdateFlyoutBehavior(bool init) - { - if (init) - return; - - if (Element.FlyoutBehavior == FlyoutBehavior.Disabled) - { - DeinitializeNavigationView(); - } - else if (Element.FlyoutBehavior == FlyoutBehavior.Flyout) - { - UpdateFlyoutMenu(); - } - else if (Element.FlyoutBehavior == FlyoutBehavior.Locked) - { - // Locked behavior is not supported on circularshell - } - } - - void UpdateFlyoutIcon(bool init) - { - if (init && Element.FlyoutIcon == null) - return; - - _drawer.UpdateDrawerIcon(Element.FlyoutIcon); - } - - void UpdateFlyoutBackgroundColor(bool init) - { - if (init && Element.FlyoutBackgroundColor.IsDefault) - return; - - if (_navigationView != null) - { - _navigationView.BackgroundColor = Element.FlyoutBackgroundColor.ToNative(); - } - } - - void UpdateFlyoutForegroundColor(bool init) - { - if (init && CircularShell.GetFlyoutForegroundColor(Element).IsDefault) - return; - - if (_navigationView != null) - { - _navigationView.ForegroundColor = CircularShell.GetFlyoutForegroundColor(Element).ToNative(); - } - } - - void UpdateFlyoutIconBackgroundColor() - { - _drawer.HandlerBackgroundColor = CircularShell.GetFlyoutIconBackgroundColor(Element).ToNative(); - } - - void UpdateFlyoutIsPresented() - { - _drawer.IsOpen = Element.FlyoutIsPresented; - } - - void SetCurrentItem(EvasObject item) - { - _drawer.SetMainContent(item); - } - - void ResetCurrentItem() - { - _drawer.SetMainContent(null); - } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRendererFactory.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRendererFactory.cs deleted file mode 100644 index 5895d44..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRendererFactory.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Xamarin.Forms; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - public class ShellRendererFactory - { - static ShellRendererFactory _instance; - public static ShellRendererFactory Default - { - get - { - if (_instance == null) - { - _instance = new ShellRendererFactory(); - } - return _instance; - } - set - { - _instance = value; - } - - } - - public virtual IShellItemRenderer CreateItemRenderer(ShellItem item) - { - if (item.Items.Count == 1) - { - return CreateShellNavigationRenderer(item.CurrentItem); - } - return new ShellItemRenderer(item); - } - - public virtual IShellItemRenderer CreateShellNavigationRenderer(ShellSection item) - { - return new ShellSectionNavigationRenderer(item); - } - - public virtual IShellItemRenderer CreateItemRenderer(ShellSection item) - { - if (item.Items.Count == 1) - { - return CreateItemRenderer(item.CurrentItem); - } - return new ShellSectionItemsRenderer(item); - } - - public virtual IShellItemRenderer CreateItemRenderer(ShellContent item) - { - return new ShellContentRenderer(item); - } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionItemsRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionItemsRenderer.cs deleted file mode 100644 index 3e72aca..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionItemsRenderer.cs +++ /dev/null @@ -1,290 +0,0 @@ -using ElmSharp; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using Xamarin.Forms; -using XForms = Xamarin.Forms.Forms; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - public class ShellSectionItemsRenderer : IShellItemRenderer - { - const int ItemMaxCount = 20; - const int OddMiddleItem = 10; - const int EvenMiddleItem = 11; - - Box _mainLayout; - Index _indexIndicator; - Scroller _scroller; - Box _innerContainer; - List _items = new List(); - - int _currentIndex = -1; - Rect _lastLayoutBound; - int _updateByCode; - - - public ShellSectionItemsRenderer(ShellSection shellSection) - { - ShellSection = shellSection; - ShellSection.PropertyChanged += OnSectionPropertyChanged; - (ShellSection.Items as INotifyCollectionChanged).CollectionChanged += OnItemsChanged; - InitializeComponent(); - UpdateItems(); - } - - public ShellSection ShellSection { get; protected set; } - - public BaseShellItem Item => ShellSection; - - public EvasObject NativeView => _mainLayout; - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _mainLayout?.Unrealize(); - (ShellSection.Items as INotifyCollectionChanged).CollectionChanged -= OnItemsChanged; - ShellSection.PropertyChanged -= OnSectionPropertyChanged; - } - } - - void InitializeComponent() - { - _mainLayout = new Box(XForms.NativeParent) - { - AlignmentX = -1, - AlignmentY = -1, - WeightX = 1, - WeightY = 1, - }; - _mainLayout.Show(); - _mainLayout.SetLayoutCallback(OnLayout); - - _indexIndicator = new Index(_mainLayout) - { - IsHorizontal = true, - AutoHide = false, - Style = IndexStyle.Circle, - }; - _indexIndicator.Show(); - - _scroller = new Scroller(_mainLayout); - _scroller.PageScrolled += OnPageScrolled; - _scroller.DragStart += OnDragStarted; - - // Disables the visibility of the scrollbar in both directions: - _scroller.HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible; - _scroller.VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible; - // Sets the limit of scroll to one page maximum: - _scroller.HorizontalPageScrollLimit = 1; - _scroller.SetPageSize(1.0, 1.0); - _scroller.SetAlignment(-1, -1); - _scroller.SetWeight(1.0, 1.0); - _scroller.Show(); - - _innerContainer = new Box(_mainLayout); - _innerContainer.SetLayoutCallback(OnInnerLayoutUpdate); - _innerContainer.SetAlignment(-1, -1); - _innerContainer.SetWeight(1.0, 1.0); - _innerContainer.Show(); - _scroller.SetContent(_innerContainer); - - _mainLayout.PackEnd(_indexIndicator); - _mainLayout.PackEnd(_scroller); - _indexIndicator.StackAbove(_scroller); - } - - void OnDragStarted(object sender, EventArgs e) - { - if (_currentIndex - 1 >= 0 && !_items[_currentIndex - 1].IsRealized) - { - RealizeItem(_items[_currentIndex - 1]); - } - if (_currentIndex + 1 < _items.Count && !_items[_currentIndex + 1].IsRealized) - { - RealizeItem(_items[_currentIndex + 1]); - } - } - - void UpdateItems() - { - _items.Clear(); - _indexIndicator.Clear(); - _innerContainer.UnPackAll(); - _lastLayoutBound = default(Rect); - - foreach (var item in ShellSection.Items) - { - var indexItem = _indexIndicator.Append(null); - indexItem.Style = GetItemStyle(ShellSection.Items.Count, _items.Count); - _items.Add(new ItemHolder - { - IsRealized = false, - IndexItem = indexItem, - Item = item - }); - } - _indexIndicator.Update(0); - UpdateCurrentPage(ShellSection.Items.IndexOf(ShellSection.CurrentItem)); - } - - void RealizeItem(ItemHolder item) - { - var renderer = ShellRendererFactory.Default.CreateItemRenderer(item.Item); - renderer.NativeView.Show(); - item.NativeView = renderer.NativeView; - item.IsRealized = true; - _innerContainer.PackEnd(item.NativeView); - item.NativeView.StackBelow(_indexIndicator); - item.NativeView.Geometry = item.Bound; - } - - void UpdateCurrentPage(int index) - { - if (_currentIndex == index) - return; - - _currentIndex = index; - UpdateCurrentIndexIndicator(); - if (!_items[index].IsRealized) - { - RealizeItem(_items[index]); - } - UpdateFocusPolicy(); - } - - void UpdateFocusPolicy() - { - foreach (var item in _items) - { - if (item.IsRealized) - { - if (item.NativeView is ElmSharp.Widget widget) - { - widget.AllowTreeFocus = (_items[_currentIndex] == item); - } - } - } - } - - void UpdateCurrentIndexIndicator() - { - if (_currentIndex >= 0 && _currentIndex < _items.Count) - { - _items[_currentIndex].IndexItem.Select(true); - } - } - void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e) - { - UpdateItems(); - } - - void OnPageScrolled(object sender, EventArgs e) - { - if (_updateByCode > 0) - { - return; - } - - if (_currentIndex < 0 || ShellSection.Items.Count <= _currentIndex) - { - return; - } - - UpdateCurrentPage(_scroller.HorizontalPageIndex); - var currentItem = ShellSection.Items[_currentIndex]; - ShellSection.SetValueFromRenderer(ShellSection.CurrentItemProperty, currentItem); - } - - void OnSectionPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(ShellSection.CurrentItem)) - { - var newIndex = ShellSection.Items.IndexOf(ShellSection.CurrentItem); - if (_currentIndex != newIndex) - { - UpdateCurrentPage(newIndex); - _updateByCode++; - _scroller.ScrollTo(newIndex, 0, false); - _updateByCode--; - } - } - } - - void OnLayout() - { - _indexIndicator.Geometry = _mainLayout.Geometry; - _scroller.Geometry = _mainLayout.Geometry; - } - - void OnInnerLayoutUpdate() - { - if (_lastLayoutBound == _innerContainer.Geometry) - { - return; - } - _lastLayoutBound = _innerContainer.Geometry; - - var layoutBound = _innerContainer.Geometry.Size; - int baseX = _innerContainer.Geometry.X; - - Rect bound = _scroller.Geometry; - int index = 0; - foreach (var item in _items) - { - bound.X = baseX + index * bound.Width; - item.Bound = bound; - if (item.IsRealized) - { - item.NativeView.Geometry = bound; - } - index++; - } - _innerContainer.MinimumWidth = _items.Count * bound.Width; - - if (_items.Count > _currentIndex && _currentIndex >= 0) - { - _updateByCode++; - _scroller.ScrollTo(_currentIndex, 0, false); - _updateByCode--; - } - } - - static string GetItemStyle(int itemCount, int offset) - { - string returnValue = string.Empty; - int startItem; - int styleNumber; - - if (itemCount % 2 == 0) //Item count is even. - { - startItem = EvenMiddleItem - itemCount / 2; - styleNumber = startItem + offset; - returnValue = "item/even_" + styleNumber; - } - else //Item count is odd. - { - startItem = OddMiddleItem - itemCount / 2; - styleNumber = startItem + offset; - returnValue = "item/odd_" + styleNumber; - } - return returnValue; - } - - class ItemHolder - { - public bool IsRealized { get; set; } - public Rect Bound { get; set; } - public EvasObject NativeView { get; set; } - public IndexItem IndexItem { get; set; } - public ShellContent Item { get; set; } - } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionNavigationRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionNavigationRenderer.cs deleted file mode 100644 index ca5d705..0000000 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionNavigationRenderer.cs +++ /dev/null @@ -1,208 +0,0 @@ -using ElmSharp; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Xamarin.Forms; -using Xamarin.Forms.Internals; -using Xamarin.Forms.Platform.Tizen; -using XForms = Xamarin.Forms.Forms; - -namespace Tizen.Wearable.CircularUI.Forms.Renderer -{ - class SimpleViewStack : Box - { - EvasObject _lastTop; - - public SimpleViewStack(EvasObject parent) : base(parent) - { - InternalStack = new List(); - SetLayoutCallback(OnLayout); - } - - List InternalStack { get; set; } - - public IReadOnlyList Stack => InternalStack; - - public void Push(EvasObject view) - { - InternalStack.Add(view); - PackEnd(view); - UpdateTopView(); - } - - public void Pop() - { - if (_lastTop != null) - { - var tobeRemoved = _lastTop; - InternalStack.Remove(tobeRemoved); - UnPack(tobeRemoved); - UpdateTopView(); - - // if Pop was called by removed page, - // Unrealize cause deletation of NativeCallback, it could be a cause of crash - Device.BeginInvokeOnMainThread(() => - { - tobeRemoved.Unrealize(); - }); - } - } - - public void PopToRoot() - { - while (InternalStack.Count > 1) - { - Pop(); - } - } - - public void Insert(EvasObject before, EvasObject view) - { - view.Hide(); - var idx = InternalStack.IndexOf(before); - InternalStack.Insert(idx, view); - PackEnd(view); - UpdateTopView(); - } - - public void Remove(EvasObject view) - { - InternalStack.Remove(view); - UnPack(view); - UpdateTopView(); - Device.BeginInvokeOnMainThread(() => - { - view?.Unrealize(); - }); - } - - void UpdateTopView() - { - if (_lastTop != InternalStack.LastOrDefault()) - { - _lastTop?.Hide(); - _lastTop = InternalStack.LastOrDefault(); - _lastTop.Show(); - } - } - - void OnLayout() - { - foreach (var view in Stack) - { - view.Geometry = Geometry; - } - } - - } - - public class ShellSectionNavigationRenderer : IShellItemRenderer - { - SimpleViewStack _viewStack; - IShellItemRenderer _rootPageRenderer; - - public ShellSectionNavigationRenderer(ShellSection item) - { - ShellSection = item; - (ShellSection as IShellSectionController).NavigationRequested += OnNavigationRequested; - InitializeComponent(); - } - - public ShellSection ShellSection { get; protected set; } - - public BaseShellItem Item => ShellSection; - - public EvasObject NativeView => _viewStack; - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _rootPageRenderer?.Dispose(); - _viewStack?.Unrealize(); - (ShellSection as IShellSectionController).NavigationRequested -= OnNavigationRequested; - } - } - - void InitializeComponent() - { - _viewStack = new SimpleViewStack(XForms.NativeParent); - _viewStack.Show(); - - _rootPageRenderer = ShellRendererFactory.Default.CreateItemRenderer(ShellSection); - _viewStack.Push(_rootPageRenderer.NativeView); - } - - void OnInsertRequest(NavigationRequestedEventArgs request) - { - var before = Platform.GetRenderer(request.BeforePage)?.NativeView ?? null; - if (before == null) - { - request.Task = Task.FromException(new ArgumentException("Can't found page on stack", nameof(request.BeforePage))); - return; - } - var renderer = Platform.GetOrCreateRenderer(request.Page); - _viewStack.Insert(before, renderer.NativeView); - request.Task = Task.FromResult(true); - } - - void OnPushRequest(NavigationRequestedEventArgs request) - { - var renderer = Platform.GetOrCreateRenderer(request.Page); - _viewStack.Push(renderer.NativeView); - request.Task = Task.FromResult(true); - } - - void OnPopRequest(NavigationRequestedEventArgs request) - { - _viewStack.Pop(); - request.Task = Task.FromResult(true); - } - - void OnPopToRootRequest(NavigationRequestedEventArgs request) - { - _viewStack.PopToRoot(); - request.Task = Task.FromResult(true); - } - - void OnRemoveRequest(NavigationRequestedEventArgs request) - { - var renderer = Platform.GetRenderer(request.Page); - if (renderer == null) - { - request.Task = Task.FromException(new ArgumentException("Can't found page on stack", nameof(request.Page))); - return; - } - _viewStack.Remove(renderer.NativeView); - request.Task = Task.FromResult(true); - } - - void OnNavigationRequested(object sender, NavigationRequestedEventArgs e) - { - switch (e.RequestType) - { - case NavigationRequestType.Insert: - OnInsertRequest(e); - break; - case NavigationRequestType.Push: - OnPushRequest(e); - break; - case NavigationRequestType.Pop: - OnPopRequest(e); - break; - case NavigationRequestType.PopToRoot: - OnPopToRootRequest(e); - break; - case NavigationRequestType.Remove: - OnRemoveRequest(e); - break; - } - } - } -} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/StepperRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/StepperRenderer.cs new file mode 100644 index 0000000..d201e22 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/StepperRenderer.cs @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using Xamarin.Forms; +using XStepperRenderer = Xamarin.Forms.Platform.Tizen.StepperRenderer; +using CStepperRenderer = Tizen.Wearable.CircularUI.Forms.Renderer.StepperRenderer; + +[assembly: ExportRenderer(typeof(Stepper), typeof(CStepperRenderer))] +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class StepperRenderer : XStepperRenderer + { + protected override void UpdateRotaryInteraction(bool enable) + { + if (Element.FindBezelRouter() == null) + { + base.UpdateRotaryInteraction(enable); + } + } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ThemeLoader.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ThemeLoader.cs index 6b5e569..8e4ecc2 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ThemeLoader.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/ThemeLoader.cs @@ -19,9 +19,9 @@ using Circular = Tizen.Wearable.CircularUI.Forms.FormsCircularUI; namespace Tizen.Wearable.CircularUI.Forms.Renderer { - internal static class ThemeLoader - { - const string CircularUITheme = "/usr/share/elm-sharp/tizen-circular-ui-theme.edj"; + internal static class ThemeLoader + { + const string CircularUITheme = "/usr/share/elm-sharp/tizen-circular-ui-theme.edj"; public static string AppResourcePath { get; private set; } @@ -37,14 +37,14 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer } } - public static void AddThemeOverlay(string themeFilePath) - { - if (!IsInitialized) - { - Log.Error(Circular.Tag, $"ThemeLoader is not initialized properly"); - return; - } - Elementary.AddThemeOverlay(themeFilePath); - } - } + public static void AddThemeOverlay(string themeFilePath) + { + if (!IsInitialized) + { + Log.Error(Circular.Tag, $"ThemeLoader is not initialized properly"); + return; + } + Elementary.AddThemeOverlay(themeFilePath); + } + } } \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TimePickerRenderer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TimePickerRenderer.cs new file mode 100644 index 0000000..3680aa6 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TimePickerRenderer.cs @@ -0,0 +1,25 @@ +using Xamarin.Forms; + +using XTimePickerRenderer = Xamarin.Forms.Platform.Tizen.TimePickerRenderer; +using CTimePickerRenderer = Tizen.Wearable.CircularUI.Forms.Renderer.TimePickerRenderer; +using System; + +[assembly: ExportRenderer(typeof(TimePicker), typeof(CTimePickerRenderer))] + +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class TimePickerRenderer : XTimePickerRenderer + { + protected override void OnPickerOpened(object sender, EventArgs args) + { + Element.FindBezelController()?.Deactivate(); + base.OnPickerOpened(sender, args); + } + + protected override void OnPickerClosed(object sender, EventArgs args) + { + base.OnPickerClosed(sender, args); + Element.FindBezelController()?.Activate(); + } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TizenCircleSurfaceEffect.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TizenCircleSurfaceEffect.cs old mode 100755 new mode 100644 diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TwoButtonPopupImplementation.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TwoButtonPopupImplementation.cs index f5141a2..d69e90d 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TwoButtonPopupImplementation.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/TwoButtonPopupImplementation.cs @@ -259,7 +259,7 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer _firstButton.Clicked += (s, e) => { - ((IMenuItemController)FirstButton).Activate(); + (FirstButton as IMenuItemController)?.Activate(); }; if (_firstButtonBgColor != Color.Default) @@ -305,7 +305,7 @@ namespace Tizen.Wearable.CircularUI.Forms.Renderer _secondButton.Clicked += (s, e) => { - ((IMenuItemController)SecondButton).Activate(); + (SecondButton as IMenuItemController)?.Activate(); }; if (_secondButtonBgColor != Color.Default) diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/WatchListView.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/WatchListView.cs new file mode 100644 index 0000000..007261a --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms.Renderer/WatchListView.cs @@ -0,0 +1,65 @@ +using ElmSharp; +using ElmSharp.Wearable; +using Xamarin.Forms; +using Xamarin.Forms.Platform.Tizen; +using XForms = Xamarin.Forms.Forms; +using CForms = Tizen.Wearable.CircularUI.Forms; + +namespace Tizen.Wearable.CircularUI.Forms.Renderer +{ + public class WatchListView : Xamarin.Forms.Platform.Tizen.Native.Watch.WatchListView + { + GenItemClass _cancelEffectTemplete; + + public WatchListView(EvasObject parent, CircleSurface surface) : base(parent, surface) + { + } + + public override void SetHeader(VisualElement header) + { + base.SetHeader(header); + if (HasHeader() && CForms.CircleListView.GetCancelEffect(header)) + { + FirstItem.UpdateItemClass(GetCancelEffectTemplete(), header); + } + } + + public override void SetFooter(VisualElement footer) + { + base.SetFooter(footer); + if (HasFooter() && CForms.CircleListView.GetCancelEffect(footer)) + { + LastItem.UpdateItemClass(GetCancelEffectTemplete(), footer); + } + } + + GenItemClass GetCancelEffectTemplete() + { + if (_cancelEffectTemplete != null) + return _cancelEffectTemplete; + _cancelEffectTemplete = new GenItemClass("full_off") + { + GetContentHandler = (data, part) => + { + VisualElement element = data as VisualElement; + var renderer = Platform.GetOrCreateRenderer(element); + + if (element.MinimumHeightRequest == -1) + { + SizeRequest request = element.Measure(double.PositiveInfinity, double.PositiveInfinity); + renderer.NativeView.MinimumHeight = XForms.ConvertToScaledPixel(request.Request.Height); + } + else + { + renderer.NativeView.MinimumHeight = XForms.ConvertToScaledPixel(element.MinimumHeightRequest); + } + (renderer as LayoutRenderer)?.RegisterOnLayoutUpdated(); + + return renderer.NativeView; + } + }; + + return _cancelEffectTemplete; + } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/BezelInteractionPage.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/BezelInteractionPage.cs new file mode 100644 index 0000000..3d923b4 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/BezelInteractionPage.cs @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.ComponentModel; +using Xamarin.Forms; + +namespace Tizen.Wearable.CircularUI.Forms +{ + /// + /// The BezelInteractionPage is a ContentPage, which allows you to interact with Bezel rotation + /// + public class BezelInteractionPage : ContentPage, IBezelInteractionRouter + { + /// + /// BindableProperty. Identifies the RotaryFocusObject bindable property Key. + /// + public static readonly BindableProperty RotaryFocusObjectProperty = BindableProperty.Create(nameof(RotaryFocusObject), typeof(IRotaryFocusable), typeof(BezelInteractionPage), null); + + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Appeared { get; set; } + + /// + /// Gets or sets object of RotaryFocusObject to receive bezel action(take a rotary event) from the current page. + /// + public IRotaryFocusable RotaryFocusObject + { + get => (IRotaryFocusable)GetValue(RotaryFocusObjectProperty); + set => SetValue(RotaryFocusObjectProperty, value); + } + + protected override void OnAppearing() + { + base.OnAppearing(); + Appeared = true; + } + + protected override void OnDisappearing() + { + base.OnDisappearing(); + Appeared = false; + } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/Check.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/Check.cs index 90b5008..5fcf978 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/Check.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/Check.cs @@ -38,6 +38,7 @@ namespace Tizen.Wearable.CircularUI.Forms /// } /// /// + [Obsolete("Check is obsolete as of version 1.5.0. Please use Xamarin.Forms.Switch instead.")] public class Check : Switch { /// diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/CirclePage.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/CirclePage.cs index 85beff4..f4df755 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/CirclePage.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/CirclePage.cs @@ -14,6 +14,7 @@ * limitations under the License. */ +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; @@ -27,7 +28,8 @@ namespace Tizen.Wearable.CircularUI.Forms /// It has an ActionButton, and can use the MenuItem type as text, icon, command, and so on. /// /// 4 - public class CirclePage : ContentPage, ICircleSurfaceProvider + [Obsolete("CirclePage is obsolete as of version 1.5.0. Please use Xamarin.Forms.ContentPage, CircleSurfaceView, and BezelInteracationPage instead.")] + public class CirclePage : ContentPage, ICircleSurfaceProvider, IBezelInteractionRouter { /// /// BindableProperty. Identifies the ActionButton bindable property. diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleScrollView.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleScrollView.cs index a71c37b..f7dde6e 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleScrollView.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleScrollView.cs @@ -14,6 +14,7 @@ * limitations under the License. */ +using System; using Xamarin.Forms; namespace Tizen.Wearable.CircularUI.Forms @@ -29,7 +30,7 @@ namespace Tizen.Wearable.CircularUI.Forms /// BindableProperty. Identifies the Header, Footer cancel the Fish Eye Effect or not. /// /// 4 - public static readonly BindableProperty BarColorProperty = BindableProperty.CreateAttached("BarColor", typeof(Color), typeof(CircleScrollView), Color.Default); + public static readonly BindableProperty BarColorProperty = BindableProperty.CreateAttached("BarColor", typeof(Color), typeof(CircleScrollView), Color.Default); /// /// Gets or sets a scroll bar color value. diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleStepper.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleStepper.cs index 1e0cf39..b2a34f9 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleStepper.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleStepper.cs @@ -15,6 +15,7 @@ */ using System; +using System.ComponentModel; using Xamarin.Forms; namespace Tizen.Wearable.CircularUI.Forms @@ -112,5 +113,35 @@ namespace Tizen.Wearable.CircularUI.Forms /// /// 4 public ICircleSurfaceProvider CircleSurfaceProvider { get; set; } + + /// + /// Occurs when the circle stepper's wheel is appeared. + /// + /// 4 + public event EventHandler WheelAppeared; + + /// + /// Occurs when the circle stepper's wheel is disappeared. + /// + /// 4 + public event EventHandler WheelDisappeared; + + /// + /// Internal use only, initializes a new instance of the EmbeddingControls. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void SendWheelAppeared() + { + WheelAppeared?.Invoke(this, EventArgs.Empty); + } + + /// + /// Internal use only, initializes a new instance of the EmbeddingControls. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void SendWheelDisappeared() + { + WheelDisappeared?.Invoke(this, EventArgs.Empty); + } } } \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleSurfaceView.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleSurfaceView.cs index 4bf63db..3d32b84 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleSurfaceView.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/CircleSurfaceView.cs @@ -46,10 +46,16 @@ namespace Tizen.Wearable.CircularUI.Forms void OnCircleObjectItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) { - if (args.Action != NotifyCollectionChangedAction.Add) - return; - foreach (Element item in args.NewItems) - item.Parent = this; + if (args.Action == NotifyCollectionChangedAction.Add) + { + foreach (Element item in args.NewItems) + item.Parent = this; + } + else if (args.Action == NotifyCollectionChangedAction.Remove) + { + foreach (Element item in args.OldItems) + item.Parent = null; + } } } } \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/ContextPopupEffectBehavior.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/ContextPopupEffectBehavior.cs index d9c196a..ee2d3a7 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/ContextPopupEffectBehavior.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/ContextPopupEffectBehavior.cs @@ -162,7 +162,7 @@ namespace Tizen.Wearable.CircularUI.Forms TargetView = view; view.SetValue(ContextPopupEffectBehaviorProperty, this); - global::System.Diagnostics.Debug.WriteLine($"TargetView = {TargetView}"); + Console.WriteLine($"TargetView = {TargetView}"); var effect = Effect.Resolve("CircleUI.ContextPopupEffectBehavior"); if (effect != null) diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/IBezelInteractionRouter.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/IBezelInteractionRouter.cs new file mode 100644 index 0000000..a183297 --- /dev/null +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/IBezelInteractionRouter.cs @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Tizen.Wearable.CircularUI.Forms +{ + public interface IBezelInteractionRouter + { + IRotaryFocusable RotaryFocusObject { get; } + bool Appeared { get; } + } +} \ No newline at end of file diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/IndexPage.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/IndexPage.cs index 1f19fed..3f93200 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/IndexPage.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/IndexPage.cs @@ -14,6 +14,7 @@ * limitations under the License. */ +using System; using Xamarin.Forms; namespace Tizen.Wearable.CircularUI.Forms @@ -23,6 +24,7 @@ namespace Tizen.Wearable.CircularUI.Forms /// When Page is added/removed at Multipage. circular index is added/removed automatically at the top of window. /// /// 4 + [Obsolete("IndexPage is obsolete as of version 1.5.0. Please use Xamarin.Forms.CarouselView and Xamarin.Forms.IndicatorView instead.")] public class IndexPage : MultiPage { protected override ContentPage CreateDefault(object item) diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/MediaPlayer.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/MediaPlayer.cs index 0206336..e66c350 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/MediaPlayer.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/MediaPlayer.cs @@ -23,7 +23,6 @@ using System.Threading.Tasks; using Xamarin.Forms; using Xamarin.Forms.Internals; using Xamarin.Forms.PlatformConfiguration.TizenSpecific; -using Xamarin.Forms.Platform.Tizen.Native; namespace Tizen.Wearable.CircularUI.Forms { diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/MediaView.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/MediaView.cs index a69c8a2..e517b61 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/MediaView.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/MediaView.cs @@ -70,7 +70,6 @@ namespace Tizen.Wearable.CircularUI.Forms } } } - protected override void LayoutChildren(double x, double y, double width, double height) { _controller?.Layout(new Rectangle(x, y, width, height)); diff --git a/src/XSF/Tizen.Wearable.CircularUI.Forms/Radio.cs b/src/XSF/Tizen.Wearable.CircularUI.Forms/Radio.cs index ab1ff25..3b9f05c 100644 --- a/src/XSF/Tizen.Wearable.CircularUI.Forms/Radio.cs +++ b/src/XSF/Tizen.Wearable.CircularUI.Forms/Radio.cs @@ -50,6 +50,7 @@ namespace Tizen.Wearable.CircularUI.Forms /// }; /// /// + [Obsolete("Radio is obsolete as of version 1.5.0. Please use Xamarin.Forms.RadioButton instead.")] public class Radio : View { /// diff --git a/src/XSF/Xamarin.Forms.Core/Expander.cs b/src/XSF/Xamarin.Forms.Core/Expander.cs index 67f5a9b..b331631 100644 --- a/src/XSF/Xamarin.Forms.Core/Expander.cs +++ b/src/XSF/Xamarin.Forms.Core/Expander.cs @@ -76,7 +76,7 @@ namespace Xamarin.Forms StackLayout ExpanderLayout { get; } ContentView ContentHolder { get; set; } - + double ContentHeightRequest { get diff --git a/src/XSF/Xamarin.Forms.Core/ExperimentalFlags.cs b/src/XSF/Xamarin.Forms.Core/ExperimentalFlags.cs index e4c1fe8..62887c2 100644 --- a/src/XSF/Xamarin.Forms.Core/ExperimentalFlags.cs +++ b/src/XSF/Xamarin.Forms.Core/ExperimentalFlags.cs @@ -29,7 +29,7 @@ namespace Xamarin.Forms { if (DesignMode.IsDesignModeEnabled) { - return; + return; } if (Device.Flags == null || !Device.Flags.Contains(flagName)) diff --git a/src/XSF/Xamarin.Forms.Core/OnAppTheme.cs b/src/XSF/Xamarin.Forms.Core/OnAppTheme.cs index 49c3c04..b8b7b67 100644 --- a/src/XSF/Xamarin.Forms.Core/OnAppTheme.cs +++ b/src/XSF/Xamarin.Forms.Core/OnAppTheme.cs @@ -6,7 +6,7 @@ namespace Xamarin.Forms { WeakReference _weakTarget; BindableProperty _targetProperty; - + public OnAppTheme() { Application.Current.RequestedThemeChanged += ThemeChanged; diff --git a/src/XSF/Xamarin.Forms.Platform.Tizen/Renderers/StepperRenderer.cs b/src/XSF/Xamarin.Forms.Platform.Tizen/Renderers/StepperRenderer.cs index beb5b02..f54eb1e 100644 --- a/src/XSF/Xamarin.Forms.Platform.Tizen/Renderers/StepperRenderer.cs +++ b/src/XSF/Xamarin.Forms.Platform.Tizen/Renderers/StepperRenderer.cs @@ -98,4 +98,4 @@ namespace Xamarin.Forms.Platform.Tizen Control.Step = Element.Increment; } } -} +} \ No newline at end of file -- 2.7.4