From 0dc5554d8b17d6ee9a390caf4f22798d035b78c5 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 17 May 2021 20:48:02 +0900 Subject: [PATCH 001/266] Adds the Tizen backend --- ...osoft.Maui.Controls.MultiTargeting.targets | 9 + .../Core/src/AppHostBuilderExtensions.cs | 12 +- .../src/Tizen/Extensions/ColorExtensions.cs | 2 +- .../Core/src/Tizen/Properties/AssemblyInfo.cs | 2 +- .../Core/src/Tizen/RendererToHandlerShim.cs | 112 ++++++++ .../NavigationPageHandler.Tizen.cs | 260 ++++++++++++++++++ src/Core/src/IMauiContext.cs | 2 + .../Tizen/ImageSourceServiceResult.cs | 39 +++ .../src/Platform/Tizen/ActivationState.cs | 14 + .../src/Platform/Tizen/CoreUIAppContext.cs | 160 +++++++++++ .../src/Platform/Tizen/HandlerExtensions.cs | 48 ++++ src/Core/src/Platform/Tizen/MauiContext.cs | 32 +++ src/Core/src/Platform/Tizen/PageView.cs | 16 ++ 13 files changed, 696 insertions(+), 12 deletions(-) create mode 100644 src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs create mode 100644 src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs create mode 100644 src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs create mode 100644 src/Core/src/Platform/Tizen/ActivationState.cs create mode 100644 src/Core/src/Platform/Tizen/CoreUIAppContext.cs create mode 100644 src/Core/src/Platform/Tizen/HandlerExtensions.cs create mode 100644 src/Core/src/Platform/Tizen/MauiContext.cs create mode 100644 src/Core/src/Platform/Tizen/PageView.cs diff --git a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets index bfa81e0fadab..cb2665ca33ea 100644 --- a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets +++ b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets @@ -29,7 +29,16 @@ + + + + + + + + + diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs index 05ba74189f44..74d3ef3b694d 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs @@ -36,20 +36,12 @@ #elif TIZEN using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; using Microsoft.Maui.Graphics.Skia; -using BoxRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.BoxViewRenderer; using CollectionViewRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.StructuredItemsViewRenderer; using OpenGLViewRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.DefaultRenderer; +using BoxRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.BoxViewRenderer; +using DefaultRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.DefaultRenderer; using StreamImagesourceHandler = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.StreamImageSourceHandler; using ImageLoaderSourceHandler = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.UriImageSourceHandler; -using DefaultRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.DefaultRenderer; -using FrameRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.FrameRenderer; -using ImageRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.ImageRenderer; -using EllipseRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.EllipseRenderer; -using LineRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.LineRenderer; -using PathRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.PathRenderer; -using PolygonRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.PolygonRenderer; -using PolylineRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.PolylineRenderer; -using RectangleRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.RectangleRenderer; #endif namespace Microsoft.Maui.Controls.Compatibility.Hosting diff --git a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs index 0f86966258f1..472f073f47e4 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs @@ -10,7 +10,7 @@ public static class ColorExtensions /// /// ElmSharp.Color instance representing a color which corresponds to the provided Microsoft.Maui.Controls.Compatibility.Color /// The Microsoft.Maui.Controls.Compatibility.Color instance which will be converted to a ElmSharp.Color - public static EColor ToNative(this Color c) + public static EColor ToPlatform(this Color c) { if (c == null) { diff --git a/src/Compatibility/Core/src/Tizen/Properties/AssemblyInfo.cs b/src/Compatibility/Core/src/Tizen/Properties/AssemblyInfo.cs index 54f1710e1f6e..08f186324624 100644 --- a/src/Compatibility/Core/src/Tizen/Properties/AssemblyInfo.cs +++ b/src/Compatibility/Core/src/Tizen/Properties/AssemblyInfo.cs @@ -3,4 +3,4 @@ [assembly: Preserve] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Platform")] -[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Material")] \ No newline at end of file +[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Material")] diff --git a/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs b/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs new file mode 100644 index 000000000000..753a8af5bd6b --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs @@ -0,0 +1,112 @@ +using System; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +using ElmSharp; +using ViewHandler = Microsoft.Maui.Handlers.EViewHandler; + +namespace Microsoft.Maui.Controls.Compatibility +{ + public class RendererToHandlerShim : ViewHandler + { + internal IVisualElementRenderer VisualElementRenderer { get; private set; } + + public static IViewHandler CreateShim(object renderer) + { + if (renderer is IViewHandler handler) + return handler; + + if (renderer is IVisualElementRenderer ivr) + return new RendererToHandlerShim(ivr); + + return new RendererToHandlerShim(); + } + + public RendererToHandlerShim() : base(ViewHandler.ViewMapper) + { + } + + public RendererToHandlerShim(IVisualElementRenderer visualElementRenderer) : this() + { + if (visualElementRenderer != null) + SetupRenderer(visualElementRenderer); + } + + public void SetupRenderer(IVisualElementRenderer visualElementRenderer) + { + VisualElementRenderer = visualElementRenderer; + VisualElementRenderer.ElementChanged += OnElementChanged; + + if (VisualElementRenderer.Element is IView view) + { + view.Handler = this; + SetVirtualView(view); + } + else if (VisualElementRenderer.Element != null) + throw new Exception($"{VisualElementRenderer.Element} must implement: {nameof(IView)}"); + } + + void OnElementChanged(object sender, VisualElementChangedEventArgs e) + { + if (e.OldElement is IView view) + view.Handler = null; + + if (e.NewElement is IView newView) + { + newView.Handler = this; + this.SetVirtualView(newView); + } + else if (e.NewElement != null) + throw new Exception($"{e.NewElement} must implement: {nameof(IView)}"); + } + + protected override EvasObject CreateNativeView() + { + return VisualElementRenderer.NativeView; + } + + protected override void ConnectHandler(EvasObject nativeView) + { + base.ConnectHandler(nativeView); + VirtualView.Handler = this; + } + + protected override void DisconnectHandler(EvasObject nativeView) + { + Platform.Tizen.Platform.SetRenderer(VisualElementRenderer.Element, VisualElementRenderer); + + VisualElementRenderer.SetElement(null); + + base.DisconnectHandler(nativeView); + VirtualView.Handler = null; + } + + public override void SetVirtualView(IView view) + { + if (VisualElementRenderer == null) + { + var renderer = Internals.Registrar.Registered.GetHandlerForObject(view) ?? new DefaultRenderer(); + + SetupRenderer(renderer); + } + + if (VisualElementRenderer.Element != view) + { + VisualElementRenderer.SetElement((VisualElement)view); + } + else + { + base.SetVirtualView(view); + } + + Platform.Tizen.Platform.SetRenderer(VisualElementRenderer.Element, VisualElementRenderer); + } + + public override void UpdateValue(string property) + { + base.UpdateValue(property); + if (property == "Frame") + { + NativeArrange(VisualElementRenderer.Element.Bounds); + } + } + } +} diff --git a/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs new file mode 100644 index 000000000000..188b64746ded --- /dev/null +++ b/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Maui.Handlers; +using Microsoft.Maui.Controls.Internals; +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; + +using TButton = Tizen.UIExtensions.ElmSharp.Button; +using TSpan = Tizen.UIExtensions.Common.Span; +using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class NavigationPageHandler : + EViewHandler + { + readonly List _naviItemContentPartList = new List(); + TaskCompletionSource _currentTaskSource = null; + IDictionary _naviItemMap; + + Page PreviousPage => VirtualView.Navigation.NavigationStack.Count > 1 ? VirtualView.Navigation.NavigationStack[VirtualView.Navigation.NavigationStack.Count - 2] : null; + NaviItem CurrentNaviItem => NativeView.NavigationStack.Count > 0 ? NativeView.NavigationStack.Last() : null; + NaviItem PreviousNaviItem => NativeView.NavigationStack.Count > 1 ? NativeView.NavigationStack[NativeView.NavigationStack.Count - 2] : null; + + protected override Naviframe CreateNativeView() + { + return new Naviframe(NativeParent) + { + PreserveContentOnPop = true, + DefaultBackButtonEnabled = false, + }; + } + + protected override void ConnectHandler(Naviframe nativeView) + { + base.ConnectHandler(nativeView); + nativeView.AnimationFinished += OnAnimationFinished; + _naviItemMap = new Dictionary(); + + if (VirtualView == null) + return; + + VirtualView.PushRequested += OnPushRequested; + VirtualView.PopRequested += OnPopRequested; + VirtualView.InternalChildren.CollectionChanged += OnPageCollectionChanged; + + foreach (Page page in VirtualView.InternalChildren) + { + _naviItemMap[page] = NativeView.Push(CreateNavItem(page), SpanTitle(page.Title)); + page.PropertyChanged += NavigationBarPropertyChangedHandler; + + UpdateHasNavigationBar(page); + } + } + + protected override void DisconnectHandler(Naviframe nativeView) + { + base.DisconnectHandler(nativeView); + nativeView.AnimationFinished -= OnAnimationFinished; + + VirtualView.PushRequested -= OnPushRequested; + VirtualView.PopRequested -= OnPopRequested; + VirtualView.InternalChildren.CollectionChanged -= OnPageCollectionChanged; + } + + public static void MapPadding(NavigationPageHandler handler, NavigationPage view) { } + + public static void MapBarTextColor(NavigationPageHandler handler, NavigationPage view) + { + handler.UpdateTitle(view.CurrentPage); + } + + public static void MapBarBackground(NavigationPageHandler handler, NavigationPage view) { } + + public static void MapTitleIcon(NavigationPageHandler handler, NavigationPage view) { } + + public static void MapTitleView(NavigationPageHandler handler, NavigationPage view) { } + + void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + // this handler is invoked only for child pages (contained on a navigation stack) + if (e.PropertyName == NavigationPage.HasNavigationBarProperty.PropertyName) + UpdateHasNavigationBar(sender as Page); + else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName || + e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) + UpdateHasBackButton(sender as Page); + else if (e.PropertyName == Page.TitleProperty.PropertyName) + UpdateTitle(sender as Page); + } + + void OnPageCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.OldItems != null) + foreach (Page page in e.OldItems) + page.PropertyChanged -= NavigationBarPropertyChangedHandler; + if (e.NewItems != null) + foreach (Page page in e.NewItems) + page.PropertyChanged += NavigationBarPropertyChangedHandler; + } + + void OnPushRequested(object sender, NavigationRequestedEventArgs nre) + { + if (nre.Animated || NativeView.NavigationStack.Count == 0) + { + _naviItemMap[nre.Page] = NativeView.Push(CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); + _currentTaskSource = new TaskCompletionSource(); + nre.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after the first Push + if (NativeView.NavigationStack.Count == 1) + CompleteCurrentNavigationTask(); + } + else + { + _naviItemMap[nre.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); + } + UpdateHasNavigationBar(nre.Page); + } + + void OnPopRequested(object sender, NavigationRequestedEventArgs nre) + { + if (VirtualView.InternalChildren.Count == NativeView.NavigationStack.Count) + { + nre.Page?.SendDisappearing(); + UpdateNavigationBar(PreviousPage, PreviousNaviItem); + + if (nre.Animated) + { + NativeView.Pop(); + + _currentTaskSource = new TaskCompletionSource(); + nre.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after Pop the last page + if (NativeView.NavigationStack.Count == 0) + CompleteCurrentNavigationTask(); + } + else + { + CurrentNaviItem?.Delete(); + } + + if (_naviItemMap.ContainsKey(nre.Page)) + _naviItemMap.Remove(nre.Page); + } + } + + void OnAnimationFinished(object sender, EventArgs e) + { + CompleteCurrentNavigationTask(); + } + + void CompleteCurrentNavigationTask() + { + if (_currentTaskSource != null) + { + var tmp = _currentTaskSource; + _currentTaskSource = null; + tmp.SetResult(true); + } + } + + void UpdateHasNavigationBar(Page page) + { + NaviItem item = GetNaviItemForPage(page); + item.SetTabBarStyle(); + item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty); + UpdateBarBackgroundColor(item); + } + + void UpdateNavigationBar(Page page, NaviItem item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + UpdateTitle(page, item); + UpdateBarBackgroundColor(item); + } + + void UpdateHasBackButton(Page page, NaviItem item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + TButton button = null; + + if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty) && NativeView.NavigationStack.Count > 1) + { + button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty)); + } + item.SetBackButton(button); + } + + void UpdateTitle(Page page, NaviItem item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + item.SetTitle(SpanTitle(page.Title)); + } + + string SpanTitle(string Title) + { + TSpan span = new TSpan + { + Text = Title, + HorizontalTextAlignment = TTextAlignment.Center, + ForegroundColor = VirtualView.BarTextColor.ToNative() + }; + return span.GetMarkupText(); + } + + void UpdateBarBackgroundColor(NaviItem item) + { + item.TitleBarBackgroundColor = VirtualView.BarBackgroundColor.ToNativeEFL(); + } + + TButton CreateNavigationButton(string text) + { + var button = new TButton(NativeParent) + { + Text = text + }; + button.SetNavigationBackStyle(); + button.Clicked += (sender, e) => + { + if (!VirtualView.SendBackButtonPressed()) + Tizen.Applications.Application.Current.Exit(); + }; + _naviItemContentPartList.Add(button); + button.Deleted += NaviItemPartContentDeletedHandler; + return button; + } + + void NaviItemPartContentDeletedHandler(object sender, EventArgs e) + { + _naviItemContentPartList.Remove(sender as Widget); + } + + NaviItem GetNaviItemForPage(Page page) + { + NaviItem item; + if (_naviItemMap.TryGetValue(page, out item)) + { + return item; + } + return null; + } + + EvasObject CreateNavItem(Page page) + { + //TODO: Fix me + EvasObject nativeView = (EvasObject)page.Handler.NativeView; + return nativeView; + } + } +} diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index cf899f3188b5..824a47332e78 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -10,6 +10,8 @@ public interface IMauiContext #if __ANDROID__ Android.Content.Context? Context { get; } +#elif TIZEN + CoreUIAppContext Context { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs b/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs new file mode 100644 index 000000000000..6e48ceaec7c1 --- /dev/null +++ b/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs @@ -0,0 +1,39 @@ +#nullable enable +using System; + +namespace Microsoft.Maui +{ + public class ImageSourceServiceResult : IImageSourceServiceResult + { + Action? _dispose; + + public ImageSourceServiceResult(bool result, Action? dispose = null) + : this(result, false, dispose) + { + } + + public ImageSourceServiceResult(bool result, bool resolutionDependent, Action? dispose = null) + { + Value = result; + IsResolutionDependent = resolutionDependent; + _dispose = dispose; + } + + public bool Value { get; } + + public bool IsResolutionDependent { get; } + + public bool IsDisposed { get; private set; } + + public void Dispose() + { + if (IsDisposed) + return; + + IsDisposed = true; + + _dispose?.Invoke(); + _dispose = null; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ActivationState.cs b/src/Core/src/Platform/Tizen/ActivationState.cs new file mode 100644 index 000000000000..6719e581c7ce --- /dev/null +++ b/src/Core/src/Platform/Tizen/ActivationState.cs @@ -0,0 +1,14 @@ +using System; + +namespace Microsoft.Maui +{ + public class ActivationState : IActivationState + { + public ActivationState(IMauiContext context) + { + Context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public IMauiContext Context { get; } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs new file mode 100644 index 000000000000..f321eeaf1dcc --- /dev/null +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -0,0 +1,160 @@ +using System; +using System.Reflection; +using Tizen.Common; +using Tizen.Applications; +using ElmSharp; +using ElmSharp.Wearable; +using Tizen.UIExtensions.ElmSharp; +using ELayout = ElmSharp.Layout; + +namespace Microsoft.Maui +{ + public class CoreUIAppContext + { + DisplayResolutionUnit _displayResolutionUnit = DisplayResolutionUnit.DP; + double _viewPortWidth = -1; + + static CoreUIAppContext? _instance = null; + + public static bool IsInitialized { get; private set; } + + public static CoreUIAppContext GetInstance(CoreApplication application, Window? window = null) + { + if (IsInitialized) + return _instance!; + + _instance = (window == null) ? new CoreUIAppContext(application) : new CoreUIAppContext(application, window); + return _instance; + } + + public CoreApplication CurrentApplication { get; private set; } + + public string ResourceDir => CurrentApplication.DirectoryInfo.Resource; + + public EvasObject NativeParent => BaseLayout; + + public Window MainWindow { get; set; } + + public ELayout BaseLayout { get; set; } + + public CircleSurface? BaseCircleSurface { get; set; } + + public DeviceType DeviceType => DeviceInfo.GetDeviceType(); + + public DisplayResolutionUnit DisplayResolutionUnit + { + get => _displayResolutionUnit; + set + { + _displayResolutionUnit = value; + DeviceInfo.DisplayResolutionUnit = _displayResolutionUnit; + } + } + + public double ViewportWidth + { + get => _viewPortWidth; + set + { + _viewPortWidth = value; + ViewportWidth = _viewPortWidth; + } + } + + protected CoreUIAppContext(CoreApplication application) : this(application, CreateDefaultWindow()) + { + } + + protected CoreUIAppContext(CoreApplication application, Window window) + { + _ = application ?? throw new ArgumentNullException(nameof(application)); + _ = window ?? throw new ArgumentNullException(nameof(window)); + + if (DisplayResolutionUnit == DisplayResolutionUnit.VP && ViewportWidth < 0) + throw new InvalidOperationException($"ViewportWidth should be set in case of DisplayResolutionUnit == VP"); + + Elementary.Initialize(); + Elementary.ThemeOverlay(); + CurrentApplication = application; + MainWindow = window; + InitializeMainWindow(); + + _ = BaseLayout ?? throw new ArgumentNullException(nameof(BaseLayout)); + + if (DotnetUtil.TizenAPIVersion < 5) + { + // We should set the env variable to support IsolatedStorageFile on tizen 4.0 or lower version. + Environment.SetEnvironmentVariable("XDG_DATA_HOME", CurrentApplication.DirectoryInfo.Data); + } + + IsInitialized = true; + } + + public void SetContent(EvasObject content) + { + content.SetAlignment(-1, -1); + content.SetWeight(1, 1); + content.Show(); + BaseLayout.SetContent(content); + } + + static Window CreateDefaultWindow() + { + return GetPreloadedWindow() ?? new Window("XamarinWindow"); + } + + static Window? GetPreloadedWindow() + { + var type = typeof(Window); + // Use reflection to avoid breaking compatibility. ElmSharp.Window.CreateWindow() is has been added since API6. + var methodInfo = type.GetMethod("CreateWindow", BindingFlags.NonPublic | BindingFlags.Static); + + return (Window?)methodInfo?.Invoke(null, new object[] { "FormsWindow" }); + } + + void InitializeMainWindow() + { +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8601 // Possible null reference assignment. + BaseLayout = (ELayout)MainWindow.GetType().GetProperty("BaseLayout")?.GetValue(MainWindow); + BaseCircleSurface = (CircleSurface)MainWindow.GetType().GetProperty("BaseCircleSurface")?.GetValue(MainWindow); +#pragma warning restore CS8601 // Possible null reference assignment. +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. + + if (BaseLayout == null) + { + var conformant = new Conformant(MainWindow); + conformant.Show(); + + var layout = new ApplicationLayout(conformant); + layout.Show(); + + BaseLayout = layout; + + if (DeviceType == DeviceType.Watch) + { + BaseCircleSurface = new CircleSurface(conformant); + } + conformant.SetContent(BaseLayout); + + if (DeviceType == DeviceType.Watch) + { + BaseCircleSurface = new CircleSurface(conformant); + } + } + + MainWindow.Active(); + MainWindow.Show(); + MainWindow.AvailableRotations = DisplayRotation.Degree_0 | DisplayRotation.Degree_90 | DisplayRotation.Degree_180 | DisplayRotation.Degree_270; + + MainWindow.Deleted += (s, e) => CurrentApplication.Exit(); + + MainWindow.RotationChanged += (sender, e) => + { + // TODO : should update later + }; + + MainWindow.BackButtonPressed += (sender, e) => CurrentApplication.Exit(); + } + } +} diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs new file mode 100644 index 000000000000..878728238bba --- /dev/null +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -0,0 +1,48 @@ +using System; +using ElmSharp; +using Microsoft.Maui.Handlers; + +namespace Microsoft.Maui +{ + public static class HandlerExtensions + { + public static EvasObject ToNative(this IView view, IMauiContext context, bool isRoot = true) + { + _ = view ?? throw new ArgumentNullException(nameof(view)); + _ = context ?? throw new ArgumentNullException(nameof(context)); + + //This is how MVU works. It collapses views down + if (view is IReplaceableView ir) + view = ir.ReplacedView; + + var handler = view.Handler; + + if (handler == null) + { + handler = context.Handlers.GetHandler(view.GetType()); + + if (handler == null) + throw new Exception($"Handler not found for view {view}"); + + handler.SetMauiContext(context); + + view.Handler = handler; + } + + handler.SetVirtualView(view); + + if (!(handler.NativeView is EvasObject result)) + { + throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); + } + + // Root content view should register to LayoutUpdated() callback. + if (isRoot && handler is LayoutHandler layoutHandler) + { + layoutHandler.RegisterOnLayoutUpdated(); + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiContext.cs b/src/Core/src/Platform/Tizen/MauiContext.cs new file mode 100644 index 000000000000..7b248d30ecb5 --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiContext.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.Maui +{ + public class MauiContext : IMauiContext + { + readonly CoreUIAppContext _context; + readonly IServiceProvider? _services; + readonly IMauiHandlersServiceProvider? _mauiHandlersServiceProvider; + + public MauiContext(CoreUIAppContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public MauiContext(IServiceProvider services, CoreUIAppContext context) + { + _services = services ?? throw new ArgumentNullException(nameof(services)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + _mauiHandlersServiceProvider = Services.GetRequiredService(); + } + + public CoreUIAppContext Context => _context; + + public IServiceProvider Services => + _services ?? throw new InvalidOperationException($"No service provider was specified during construction."); + + public IMauiHandlersServiceProvider Handlers => + _mauiHandlersServiceProvider ?? throw new InvalidOperationException($"No service provider was specified during construction."); + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/PageView.cs b/src/Core/src/Platform/Tizen/PageView.cs new file mode 100644 index 000000000000..24ec2915c420 --- /dev/null +++ b/src/Core/src/Platform/Tizen/PageView.cs @@ -0,0 +1,16 @@ +using System; +using Microsoft.Maui.Graphics; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui +{ + public class PageView : Page + { + public PageView(ElmSharp.EvasObject parent) : base(parent) + { + } + + internal Func? CrossPlatformMeasure { get; set; } + internal Func? CrossPlatformArrange { get; set; } + } +} From be5f10ee90b6f18ce420efb27648132a24e042b3 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 21 May 2021 11:03:52 +0900 Subject: [PATCH 002/266] Update the PageHandler.Tizen * Implements the MapContent() --- src/Core/src/Handlers/Page/PageHandler.Tizen.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index 76b957fa7c77..4b876d18d570 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -25,5 +25,19 @@ protected override ContentCanvas CreatePlatformView() return view; } + + void UpdateContent() + { + _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); + _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + NativeView.Children.Add(VirtualView.Content.ToNative(MauiContext, false)); + // TODO : Fix me later + //if (VirtualView.Content.Handler is INativeViewHandler thandler) + //{ + // thandler?.SetParent(this); + //} + } } } \ No newline at end of file From 57db385a94cd38a9af0a94c8d912fc4233c1bbbb Mon Sep 17 00:00:00 2001 From: JoonghyunCho Date: Fri, 23 Apr 2021 14:10:08 +0900 Subject: [PATCH 003/266] [Tizen] Add Resizetizer Tizen Implementation --- .../src/TizenIconManifestUpdator.cs | 56 ++++++ .../Resizetizer/src/TizenSplashUpdator.cs | 160 ++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs create mode 100644 src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs diff --git a/src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs b/src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs new file mode 100644 index 000000000000..b8ea28316b95 --- /dev/null +++ b/src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs @@ -0,0 +1,56 @@ +using System; +using System.Xml; + +namespace Microsoft.Maui.Resizetizer +{ + internal class TizenIconManifestUpdator + { + const string namespaceURI = "http://tizen.org/ns/packages"; + + public TizenIconManifestUpdator(string appIconName, DpiPath[] dpis, ILogger logger) + { + AppIconName = appIconName; + Dpis = dpis; + Logger = logger; + } + + public string AppIconName { get; private set; } + + public DpiPath[] Dpis { get; } + + public ILogger Logger { get; private set; } + + public void Update() + { + XmlDocument doc = new XmlDocument(); + var xmlPath = Environment.CurrentDirectory + "\\tizen-manifest.xml"; + try + { + doc.Load(xmlPath); + } + catch + { + Logger.Log($"Failed to load tizen-manifest.xml"); + return; + } + + var nsmgr = new XmlNamespaceManager(doc.NameTable); + nsmgr.AddNamespace("manifest", namespaceURI); + var uiApplicationNode = doc.SelectSingleNode("//manifest:ui-application", nsmgr); + if (uiApplicationNode == null) + { + Logger.Log($"Failed to find "); + return; + } + var IconNode = doc.SelectSingleNode("//manifest:icon", nsmgr); + if (IconNode == null) + { + IconNode = doc.CreateElement("icon", namespaceURI); + uiApplicationNode.AppendChild(IconNode); + } + IconNode.InnerText = AppIconName + Dpis[1].FileSuffix + ".png"; + + doc.Save(xmlPath); + } + } +} diff --git a/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs b/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs new file mode 100644 index 000000000000..0559f47e702b --- /dev/null +++ b/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using SkiaSharp; + +namespace Microsoft.Maui.Resizetizer +{ + public class TizenSplashUpdator : Task + { + [Required] + public ITaskItem[] MauiSplashScreen { get; set; } + + [Required] + public string IntermediateOutputPath { get; set; } + + public ILogger Logger { get; private set; } + + public override bool Execute() + { + if (UpdateSplashImage()) + UpdateManifest(); + return !Log.HasLoggedErrors; + } + + const string namespaceURI = "http://tizen.org/ns/packages"; + const string splashDirectoryName = "splash"; + List orientations = new List() { "portrait", "landscape" }; + Dictionary splashDpiMap = new Dictionary(); + + public bool UpdateSplashImage() + { + var splash = MauiSplashScreen[0]; + var image = Path.GetFileNameWithoutExtension(splash.ItemSpec) + ".png"; + var sharedResFullPath = Path.GetFullPath(Path.Combine(IntermediateOutputPath, "shared/res/")); + var splashFullPath = Path.Combine(sharedResFullPath, splashDirectoryName); + + if (Directory.Exists(splashFullPath)) + { + Directory.Delete(splashFullPath, true); + } + Directory.CreateDirectory(splashFullPath); + + foreach (var dpi in DpiPath.Tizen) + { + var imageOutputPath = Path.GetFullPath(Path.Combine(IntermediateOutputPath, dpi.Path)); + var imageFullPath = Path.Combine(imageOutputPath, image); + if (File.Exists(imageFullPath)) + { + var resolution = dpi.Path.Split('-')[1].ToLower(); + var newImage = Path.GetFileNameWithoutExtension(splash.ItemSpec) + "." + resolution + ".png"; + splashDpiMap.Add(resolution, $"{splashDirectoryName}/{ newImage }"); + UpdateColorAndMoveFile(imageFullPath, Path.Combine(splashFullPath, newImage)); + } + else + { + Log.LogWarning($"Unable to find splash image at {imageFullPath}."); + return false; + } + } + return true; + } + + public void UpdateColorAndMoveFile(string sourceFilePath, string destFilePath) + { + var splash = MauiSplashScreen[0]; + var colorMetadata = splash.GetMetadata("Color"); + var color = Utils.ParseColorString(colorMetadata); + if (color == null) + { + if (!string.IsNullOrEmpty(colorMetadata)) + { + Log.LogWarning($"Unable to parse color value '{colorMetadata}' for '{splash.ItemSpec}'."); + } + color = SKColors.White; + } + + using (SKBitmap bmp = SKBitmap.Decode(sourceFilePath)) + { + SKImageInfo info = new SKImageInfo(bmp.Width, bmp.Height); + using (SKSurface surface = SKSurface.Create(info)) + { + SKCanvas canvas = surface.Canvas; + canvas.Clear(color.Value); + using SKPaint paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High + }; + canvas.DrawBitmap(bmp, info.Rect, paint); + canvas.Flush(); + + var updatedsplash = surface.Snapshot(); + using (var data = updatedsplash.Encode(SKEncodedImageFormat.Png, 100)) + { + using (var stream = File.Create(destFilePath)) + { + data.SaveTo(stream); + } + } + } + } + File.Delete(sourceFilePath); + } + + public void UpdateManifest() + { + XmlDocument doc = new XmlDocument(); + var xmlPath = Environment.CurrentDirectory + "\\tizen-manifest.xml"; + try + { + doc.Load(xmlPath); + } + catch + { + Log.LogWarning($"Failed to load tizen-manifest.xml"); + return; + } + + var nsmgr = new XmlNamespaceManager(doc.NameTable); + nsmgr.AddNamespace("manifest", namespaceURI); + var uiApplicationNode = doc.SelectSingleNode("//manifest:ui-application", nsmgr); + if (uiApplicationNode == null) + { + Log.LogWarning($"Failed to find "); + return; + } + var splashScreensNodeList = doc.SelectNodes("//manifest:splash-screens", nsmgr); + if (splashScreensNodeList != null) + { + foreach (XmlNode node in splashScreensNodeList) + { + uiApplicationNode.RemoveChild(node); + } + } + + var splashScreensNode = doc.CreateElement("splash-screens", namespaceURI); + uiApplicationNode.AppendChild(splashScreensNode); + + foreach(var image in splashDpiMap) + { + foreach (var orientation in orientations) + { + var splashScreenNode = doc.CreateElement("splash-screen", namespaceURI); + splashScreenNode.SetAttribute("src", image.Value); + splashScreenNode.SetAttribute("type", "img"); + splashScreenNode.SetAttribute("dpi", image.Key); + splashScreenNode.SetAttribute("orientation", orientation); + splashScreenNode.SetAttribute("indicator-display", "false"); + splashScreenNode.SetAttribute("app-control-operation", "http://tizen.org/appcontrol/operation/default"); + splashScreensNode.AppendChild(splashScreenNode); + } + } + + doc.Save(xmlPath); + } + } +} From 4362d4945073be4d1e3868eb258f50ffd4033008 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 1 Jun 2021 07:39:20 +0900 Subject: [PATCH 004/266] Bump to latest and fix build error --- .../Core/src/Tizen/RendererToHandlerShim.cs | 112 ------------------ .../samples/Controls.Sample/Tizen/Main.cs | 24 ++++ .../Controls.Sample/Tizen/tizen-manifest.xml | 24 ++++ .../CheckBox/CheckBoxHandler.Tizen.cs | 5 + .../src/Platform/Tizen/CheckBoxExtensions.cs | 9 ++ 5 files changed, 62 insertions(+), 112 deletions(-) delete mode 100644 src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs create mode 100644 src/Controls/samples/Controls.Sample/Tizen/Main.cs create mode 100644 src/Controls/samples/Controls.Sample/Tizen/tizen-manifest.xml diff --git a/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs b/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs deleted file mode 100644 index 753a8af5bd6b..000000000000 --- a/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; -using ElmSharp; -using ViewHandler = Microsoft.Maui.Handlers.EViewHandler; - -namespace Microsoft.Maui.Controls.Compatibility -{ - public class RendererToHandlerShim : ViewHandler - { - internal IVisualElementRenderer VisualElementRenderer { get; private set; } - - public static IViewHandler CreateShim(object renderer) - { - if (renderer is IViewHandler handler) - return handler; - - if (renderer is IVisualElementRenderer ivr) - return new RendererToHandlerShim(ivr); - - return new RendererToHandlerShim(); - } - - public RendererToHandlerShim() : base(ViewHandler.ViewMapper) - { - } - - public RendererToHandlerShim(IVisualElementRenderer visualElementRenderer) : this() - { - if (visualElementRenderer != null) - SetupRenderer(visualElementRenderer); - } - - public void SetupRenderer(IVisualElementRenderer visualElementRenderer) - { - VisualElementRenderer = visualElementRenderer; - VisualElementRenderer.ElementChanged += OnElementChanged; - - if (VisualElementRenderer.Element is IView view) - { - view.Handler = this; - SetVirtualView(view); - } - else if (VisualElementRenderer.Element != null) - throw new Exception($"{VisualElementRenderer.Element} must implement: {nameof(IView)}"); - } - - void OnElementChanged(object sender, VisualElementChangedEventArgs e) - { - if (e.OldElement is IView view) - view.Handler = null; - - if (e.NewElement is IView newView) - { - newView.Handler = this; - this.SetVirtualView(newView); - } - else if (e.NewElement != null) - throw new Exception($"{e.NewElement} must implement: {nameof(IView)}"); - } - - protected override EvasObject CreateNativeView() - { - return VisualElementRenderer.NativeView; - } - - protected override void ConnectHandler(EvasObject nativeView) - { - base.ConnectHandler(nativeView); - VirtualView.Handler = this; - } - - protected override void DisconnectHandler(EvasObject nativeView) - { - Platform.Tizen.Platform.SetRenderer(VisualElementRenderer.Element, VisualElementRenderer); - - VisualElementRenderer.SetElement(null); - - base.DisconnectHandler(nativeView); - VirtualView.Handler = null; - } - - public override void SetVirtualView(IView view) - { - if (VisualElementRenderer == null) - { - var renderer = Internals.Registrar.Registered.GetHandlerForObject(view) ?? new DefaultRenderer(); - - SetupRenderer(renderer); - } - - if (VisualElementRenderer.Element != view) - { - VisualElementRenderer.SetElement((VisualElement)view); - } - else - { - base.SetVirtualView(view); - } - - Platform.Tizen.Platform.SetRenderer(VisualElementRenderer.Element, VisualElementRenderer); - } - - public override void UpdateValue(string property) - { - base.UpdateValue(property); - if (property == "Frame") - { - NativeArrange(VisualElementRenderer.Element.Bounds); - } - } - } -} diff --git a/src/Controls/samples/Controls.Sample/Tizen/Main.cs b/src/Controls/samples/Controls.Sample/Tizen/Main.cs new file mode 100644 index 000000000000..ad4de56904ff --- /dev/null +++ b/src/Controls/samples/Controls.Sample/Tizen/Main.cs @@ -0,0 +1,24 @@ +using System; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Compatibility; +using Tizen.NUI; +using Tizen.NUI.BaseComponents; + +namespace Maui.Controls.Sample.SingleProject +{ + class Program : MauiApplication + { + protected override void OnCreate() + { + base.OnCreate(); + //Microsoft.Maui.Controls.Essentials.Platform.Init(this); + } + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/src/Controls/samples/Controls.Sample/Tizen/tizen-manifest.xml b/src/Controls/samples/Controls.Sample/Tizen/tizen-manifest.xml new file mode 100644 index 000000000000..3b9f9701ab24 --- /dev/null +++ b/src/Controls/samples/Controls.Sample/Tizen/tizen-manifest.xml @@ -0,0 +1,24 @@ + + + + + + appicon.xhigh.png + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Core/src/Handlers/CheckBox/CheckBoxHandler.Tizen.cs b/src/Core/src/Handlers/CheckBox/CheckBoxHandler.Tizen.cs index 6cd3c4805f9f..490971f929a9 100644 --- a/src/Core/src/Handlers/CheckBox/CheckBoxHandler.Tizen.cs +++ b/src/Core/src/Handlers/CheckBox/CheckBoxHandler.Tizen.cs @@ -29,6 +29,11 @@ public static void MapForeground(ICheckBoxHandler handler, ICheckBox check) handler.PlatformView?.UpdateForeground(check); } + public static void MapForeground(CheckBoxHandler handler, ICheckBox check) + { + handler.NativeView?.UpdateForeground(check); + } + void OnStateChanged(object? sender, EventArgs e) { if (VirtualView == null) diff --git a/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs b/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs index 34f9ecdf5912..56be0cdf7d6e 100644 --- a/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs +++ b/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs @@ -18,5 +18,14 @@ public static void UpdateForeground(this Check platformCheck, ICheckBox check) platformCheck.Color = solid.Color.ToPlatformEFL(); } } + + public static void UpdateForeground(this Check nativeCheck, ICheckBox check) + { + // For the moment, we're only supporting solid color Paint + if (check.Foreground is SolidPaint solid) + { + nativeCheck.Color = solid.Color.ToNativeEFL(); + } + } } } \ No newline at end of file From 040eb53fc845b029ae6a4e14bac73c3be19ea2d4 Mon Sep 17 00:00:00 2001 From: Seungkeun Lee Date: Tue, 8 Jun 2021 19:44:05 +0900 Subject: [PATCH 005/266] Fix Tizen Handlers --- .../Core/src/Tizen/HandlerToRendererShim.cs | 2 + .../NavigationPageHandler.Tizen.cs | 12 +- .../src/Graphics/PaintExtensions.Tizen.cs | 2 +- .../src/Handlers/Page/PageHandler.Tizen.cs | 21 +- .../src/Handlers/View/ViewHandler.Tizen.cs | 50 + .../src/Platform/Tizen/HandlerExtensions.cs | 15 +- src/Core/src/Platform/Tizen/LayoutCanvas.cs | 49 - .../SKColorExtensions.cs | 17 + .../SKGraphicsExtensions.cs | 402 ++++++++ .../SKPaintExtensions.cs | 39 + .../SkiaBitmapExportContext.cs | 112 +++ .../SkiaCanvas.cs | 904 ++++++++++++++++++ .../SkiaCanvasState.cs | 451 +++++++++ .../SkiaDelegatingFontService.cs | 82 ++ .../SkiaFontFamily.cs | 77 ++ .../SkiaFontService.cs | 87 ++ .../SkiaFontStyle.cs | 74 ++ .../SkiaGraphicsService.cs | 94 ++ .../Microsoft.Maui.Graphics.Skia/SkiaImage.cs | 162 ++++ .../SkiaTextLayout.cs | 266 ++++++ .../Views/SkiaGraphicsView.Tizen.cs | 45 + src/Core/src/Platform/Tizen/PageView.cs | 3 - src/Core/src/Platform/Tizen/WrapperView.cs | 8 +- 23 files changed, 2894 insertions(+), 80 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/LayoutCanvas.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKColorExtensions.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKGraphicsExtensions.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKPaintExtensions.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaBitmapExportContext.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvas.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvasState.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaDelegatingFontService.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontFamily.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontService.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontStyle.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaImage.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaTextLayout.cs create mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/Views/SkiaGraphicsView.Tizen.cs diff --git a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs index fe07cba3ba82..d90ff96b622e 100644 --- a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs +++ b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs @@ -75,6 +75,8 @@ public void SetElement(VisualElement element) NativeView.Deleted += OnNativeDeleted; ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(oldElement, Element)); + + (ViewHandler as INativeViewHandler)?.SetParent(new MockParentHandler(element.RealParent as VisualElement)); } void OnBatchCommitted(object sender, EventArg e) diff --git a/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs index 188b64746ded..03583d02cfcf 100644 --- a/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs +++ b/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; -using Microsoft.Maui.Handlers; -using Microsoft.Maui.Controls.Internals; using ElmSharp; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Handlers; using Tizen.UIExtensions.ElmSharp; - using TButton = Tizen.UIExtensions.ElmSharp.Button; using TSpan = Tizen.UIExtensions.Common.Span; using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; @@ -15,7 +13,7 @@ namespace Microsoft.Maui.Controls.Handlers { public partial class NavigationPageHandler : - EViewHandler + ViewHandler { readonly List _naviItemContentPartList = new List(); TaskCompletionSource _currentTaskSource = null; @@ -252,9 +250,7 @@ NaviItem GetNaviItemForPage(Page page) EvasObject CreateNavItem(Page page) { - //TODO: Fix me - EvasObject nativeView = (EvasObject)page.Handler.NativeView; - return nativeView; + return page.ToNative(MauiContext); } } } diff --git a/src/Core/src/Graphics/PaintExtensions.Tizen.cs b/src/Core/src/Graphics/PaintExtensions.Tizen.cs index f683d214fe84..c94f14e13962 100644 --- a/src/Core/src/Graphics/PaintExtensions.Tizen.cs +++ b/src/Core/src/Graphics/PaintExtensions.Tizen.cs @@ -79,4 +79,4 @@ public static TColor ToPlatform(this Paint paint) static bool IsValid(this GradientPaint? gradienPaint) => gradienPaint?.GradientStops?.Length > 0; } -} \ No newline at end of file +} diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index 4b876d18d570..52097e13bc5a 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -26,18 +26,27 @@ protected override ContentCanvas CreatePlatformView() return view; } + public override void NativeArrange(Graphics.Rectangle frame) + { + // empty on purpose + } + void UpdateContent() { _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); - NativeView.Children.Add(VirtualView.Content.ToNative(MauiContext, false)); - // TODO : Fix me later - //if (VirtualView.Content.Handler is INativeViewHandler thandler) - //{ - // thandler?.SetParent(this); - //} + NativeView.Children.Clear(); + _contentHandler?.Dispose(); + _contentHandler = null; + + NativeView.Children.Add(VirtualView.Content.ToNative(MauiContext)); + if (VirtualView.Content.Handler is INativeViewHandler thandler) + { + thandler?.SetParent(this); + _contentHandler = thandler; + } } } } \ No newline at end of file diff --git a/src/Core/src/Handlers/View/ViewHandler.Tizen.cs b/src/Core/src/Handlers/View/ViewHandler.Tizen.cs index acfe080adffa..7b185ff373c5 100644 --- a/src/Core/src/Handlers/View/ViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/View/ViewHandler.Tizen.cs @@ -128,5 +128,55 @@ void OnPlatformViewDeleted(object? sender, EventArgs e) { OnPlatformViewDeleted(); } + + protected virtual void OnNativeViewDeleted() + { + } + + protected virtual void OnFocused() + { + } + + protected virtual void OnUnfocused() + { + } + + protected void OnFocused(object? sender, EventArgs e) + { + OnFocused(); + } + + protected void OnUnfocused(object? sender, EventArgs e) + { + OnUnfocused(); + } + + partial void ConnectingHandler(NativeView? nativeView) + { + if (nativeView == null) + return; + + + nativeView.Deleted += OnNativeViewDeleted; + + if (nativeView is Widget widget) + { + widget.Focused += OnFocused; + widget.Unfocused += OnUnfocused; + } + } + + partial void DisconnectingHandler(NativeView? nativeView) + { + if (nativeView == null) + return; + + nativeView.Deleted -= OnNativeViewDeleted; + } + + void OnNativeViewDeleted(object? sender, EventArgs e) + { + OnNativeViewDeleted(); + } } } diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 878728238bba..eb58125d4f4c 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -1,12 +1,11 @@ using System; using ElmSharp; -using Microsoft.Maui.Handlers; namespace Microsoft.Maui { public static class HandlerExtensions { - public static EvasObject ToNative(this IView view, IMauiContext context, bool isRoot = true) + public static EvasObject ToNative(this IView view, IMauiContext context) { _ = view ?? throw new ArgumentNullException(nameof(view)); _ = context ?? throw new ArgumentNullException(nameof(context)); @@ -25,23 +24,15 @@ public static EvasObject ToNative(this IView view, IMauiContext context, bool is throw new Exception($"Handler not found for view {view}"); handler.SetMauiContext(context); - + handler.SetVirtualView(view); view.Handler = handler; } - handler.SetVirtualView(view); - - if (!(handler.NativeView is EvasObject result)) + if (((INativeViewHandler)handler).NativeView is not EvasObject result) { throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); } - // Root content view should register to LayoutUpdated() callback. - if (isRoot && handler is LayoutHandler layoutHandler) - { - layoutHandler.RegisterOnLayoutUpdated(); - } - return result; } } diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs deleted file mode 100644 index 7aa89aa8ebc0..000000000000 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using ElmSharp; -using Tizen.UIExtensions.Common; -using Tizen.UIExtensions.ElmSharp; -using Rect = Microsoft.Maui.Graphics.Rect; -using Size = Microsoft.Maui.Graphics.Size; -using TSize = Tizen.UIExtensions.Common.Size; - -namespace Microsoft.Maui.Platform -{ - public class LayoutCanvas : Canvas, IMeasurable - { - IView _virtualView; - Size _measureCache; - - public LayoutCanvas(EvasObject parent, IView view) : base(parent) - { - _virtualView = view; - LayoutUpdated += OnLayoutUpdated; - } - - public TSize Measure(double availableWidth, double availableHeight) - { - return CrossPlatformMeasure?.Invoke(availableWidth.ToScaledDP(), availableHeight.ToScaledDP()).ToPixel() ?? new TSize(0, 0); - } - - internal Func? CrossPlatformMeasure { get; set; } - internal Func? CrossPlatformArrange { get; set; } - - protected void OnLayoutUpdated(object? sender, LayoutEventArgs e) - { - var platformGeometry = Geometry.ToDP(); - - var measured = CrossPlatformMeasure!(platformGeometry.Width, platformGeometry.Height); - if (measured != _measureCache && _virtualView?.Parent is IView parentView) - { - parentView?.InvalidateMeasure(); - } - _measureCache = measured; - - if (platformGeometry.Width > 0 && platformGeometry.Height > 0) - { - platformGeometry.X = 0; - platformGeometry.Y = 0; - CrossPlatformArrange!(platformGeometry); - } - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKColorExtensions.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKColorExtensions.cs new file mode 100644 index 000000000000..c069806ecdae --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKColorExtensions.cs @@ -0,0 +1,17 @@ +using SkiaSharp; + +namespace Microsoft.Maui.Graphics.Skia +{ + public static class SKColorExtensions + { + public static SKColor ToColor(this Color target, float alpha = 1) + { + var r = (byte) (target.Red * 255f); + var g = (byte) (target.Green * 255f); + var b = (byte) (target.Blue * 255f); + var a = (byte) (target.Alpha * 255f * alpha); + + return new SKColor(r, g, b, a); + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKGraphicsExtensions.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKGraphicsExtensions.cs new file mode 100644 index 000000000000..c1edc743cf6a --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKGraphicsExtensions.cs @@ -0,0 +1,402 @@ +using System; +using SkiaSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public static class SKGraphicsExtensions + { + public static SKColor AsSKColorMultiplyAlpha(this Color target, float alpha) + { + var r = (byte) (target.Red * 255f); + var g = (byte) (target.Green * 255f); + var b = (byte) (target.Blue * 255f); + var a = (byte) (target.Alpha * alpha * 255f); + + if (a > 255) + a = 255; + + var color = new SKColor(r, g, b, a); + return color; + } + + public static int ToArgb(this Color target) + { + var a = (int) (target.Alpha * 255f); + var r = (int) (target.Red * 255f); + var g = (int) (target.Green * 255f); + var b = (int) (target.Blue * 255f); + + var argb = a << 24 | r << 16 | g << 8 | b; + return argb; + } + + public static int ToArgb(this Color target, float alpha) + { + var a = (int) (target.Alpha * 255f * alpha); + var r = (int) (target.Red * 255f); + var g = (int) (target.Green * 255f); + var b = (int) (target.Blue * 255f); + + var argb = a << 24 | r << 16 | g << 8 | b; + return argb; + } + + public static SKColor AsSKColor(this Color target) + { + var r = (byte) (target.Red * 255f); + var g = (byte) (target.Green * 255f); + var b = (byte) (target.Blue * 255f); + var a = (byte) (target.Alpha * 255f); + return new SKColor(r, g, b, a); + } + + public static Color AsColor(this SKColor target) + { + var r = (int) target.Red; + var g = (int) target.Green; + var b = (int) target.Blue; + var a = (int) target.Alpha; + return new Color(r, g, b, a); + } + + public static SKRect AsSKRect(this RectangleF target) + { + return new SKRect(target.Left, target.Top, target.Right, target.Bottom); + } + + public static RectangleF AsRectangleF(this SKRect target) + { + return new RectangleF(target.Left, target.Top, Math.Abs(target.Right - target.Left), Math.Abs(target.Bottom - target.Top)); + } + + public static SKPoint ToSKPoint(this PointF target) + { + return new SKPoint(target.X, target.Y); + } + + public static SKMatrix AsMatrix(this AffineTransform transform) + { + var matrix = new SKMatrix + { + ScaleX = transform.ScaleX, + SkewX = transform.ShearX, + TransX = transform.TranslateX, + SkewY = transform.ShearY, + ScaleY = transform.ScaleY, + TransY = transform.TranslateY, + Persp0 = 0, + Persp1 = 0, + Persp2 = 1 + }; + return matrix; + } + + public static SKPath AsSkiaPath(this PathF target) + { + return AsSkiaPath(target, 1); + } + + public static SKPath AsSkiaPath(this PathF path, float ppu) + { + return AsSkiaPath(path, ppu, 0, 0, 1, 1); + } + + public static SKPath AsSkiaPath( + this PathF path, + float ppu, + float ox, + float oy, + float fx, + float fy) + { + var nativePath = new SKPath(); + + var ppux = ppu * fx; + var ppuy = ppu * fy; + + var pointIndex = 0; + var arcAngleIndex = 0; + var arcClockwiseIndex = 0; + + foreach (var type in path.SegmentTypes) + { + if (type == PathOperation.Move) + { + var point = path[pointIndex++]; + nativePath.MoveTo((ox + point.X * ppux), (oy + point.Y * ppuy)); + } + else if (type == PathOperation.Line) + { + var point = path[pointIndex++]; + nativePath.LineTo((ox + point.X * ppux), (oy + point.Y * ppuy)); + } + + else if (type == PathOperation.Quad) + { + var controlPoint = path[pointIndex++]; + var point = path[pointIndex++]; + nativePath.QuadTo((ox + controlPoint.X * ppux), (oy + controlPoint.Y * ppuy), (ox + point.X * ppux), (oy + point.Y * ppuy)); + } + else if (type == PathOperation.Cubic) + { + var controlPoint1 = path[pointIndex++]; + var controlPoint2 = path[pointIndex++]; + var point = path[pointIndex++]; + nativePath.CubicTo((ox + controlPoint1.X * ppux), (oy + controlPoint1.Y * ppuy), (ox + controlPoint2.X * ppux), (oy + controlPoint2.Y * ppuy), (ox + point.X * ppux), + (oy + point.Y * ppuy)); + } + else if (type == PathOperation.Arc) + { + var topLeft = path[pointIndex++]; + var bottomRight = path[pointIndex++]; + var startAngle = path.GetArcAngle(arcAngleIndex++); + var endAngle = path.GetArcAngle(arcAngleIndex++); + var clockwise = path.GetArcClockwise(arcClockwiseIndex++); + + while (startAngle < 0) + { + startAngle += 360; + } + + while (endAngle < 0) + { + endAngle += 360; + } + + var rect = new SKRect(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); + var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); + + startAngle *= -1; + if (!clockwise) + sweep *= -1; + + nativePath.AddArc(rect, startAngle, sweep); + } + else if (type == PathOperation.Close) + { + nativePath.Close(); + } + } + + return nativePath; + } + + public static SKPath AsSkiaPath(this PathF path, float ppu, float zoom) + { + return AsSkiaPath(path, ppu * zoom); + } + + public static SKPath AsSkiaPathFromSegment(this PathF target, int segmentIndex, float ppu, float zoom) + { + ppu = zoom * ppu; + + var path = new SKPath(); + + var type = target.GetSegmentType(segmentIndex); + if (type == PathOperation.Line) + { + var pointIndex = target.GetSegmentPointIndex(segmentIndex); + var startPoint = target[pointIndex - 1]; + path.MoveTo(startPoint.X * ppu, startPoint.Y * ppu); + + var endPoint = target[pointIndex]; + path.LineTo(endPoint.X * ppu, endPoint.Y * ppu); + } + else if (type == PathOperation.Quad) + { + var pointIndex = target.GetSegmentPointIndex(segmentIndex); + var startPoint = target[pointIndex - 1]; + path.MoveTo(startPoint.X * ppu, startPoint.Y * ppu); + + var controlPoint = target[pointIndex++]; + var endPoint = target[pointIndex]; + path.QuadTo(controlPoint.X * ppu, controlPoint.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); + } + else if (type == PathOperation.Cubic) + { + var pointIndex = target.GetSegmentPointIndex(segmentIndex); + var startPoint = target[pointIndex - 1]; + path.MoveTo(startPoint.X * ppu, startPoint.Y * ppu); + + var controlPoint1 = target[pointIndex++]; + var controlPoint2 = target[pointIndex++]; + var endPoint = target[pointIndex]; + path.CubicTo(controlPoint1.X * ppu, controlPoint1.Y * ppu, controlPoint2.X * ppu, controlPoint2.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); + } + else if (type == PathOperation.Arc) + { + target.GetSegmentInfo(segmentIndex, out var pointIndex, out var arcAngleIndex, out var arcClockwiseIndex); + + var topLeft = target[pointIndex++]; + var bottomRight = target[pointIndex]; + var startAngle = target.GetArcAngle(arcAngleIndex++); + var endAngle = target.GetArcAngle(arcAngleIndex); + var clockwise = target.GetArcClockwise(arcClockwiseIndex); + + while (startAngle < 0) + { + startAngle += 360; + } + + while (endAngle < 0) + { + endAngle += 360; + } + + var rect = new SKRect(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); + var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); + + startAngle *= -1; + if (!clockwise) + sweep *= -1; + + path.AddArc(rect, startAngle, sweep); + } + + return path; + } + + public static SKPath AsRotatedAndroidPath(this PathF target, PointF center, float ppu, float zoom, float angle) + { + ppu = zoom * ppu; + + var path = new SKPath(); + + var pointIndex = 0; + var arcAngleIndex = 0; + var arcClockwiseIndex = 0; + + foreach (var type in target.SegmentTypes) + { + if (type == PathOperation.Move) + { + var point = target.GetRotatedPoint(pointIndex++, center, angle); + path.MoveTo(point.X * ppu, point.Y * ppu); + } + else if (type == PathOperation.Line) + { + var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); + path.LineTo(endPoint.X * ppu, endPoint.Y * ppu); + } + else if (type == PathOperation.Quad) + { + var controlPoint1 = target.GetRotatedPoint(pointIndex++, center, angle); + var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); + path.QuadTo( + controlPoint1.X * ppu, + controlPoint1.Y * ppu, + endPoint.X * ppu, + endPoint.Y * ppu); + } + else if (type == PathOperation.Cubic) + { + var controlPoint1 = target.GetRotatedPoint(pointIndex++, center, angle); + var controlPoint2 = target.GetRotatedPoint(pointIndex++, center, angle); + var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); + path.CubicTo( + controlPoint1.X * ppu, + controlPoint1.Y * ppu, + controlPoint2.X * ppu, + controlPoint2.Y * ppu, + endPoint.X * ppu, + endPoint.Y * ppu); + } + else if (type == PathOperation.Arc) + { + var topLeft = target[pointIndex++]; + var bottomRight = target[pointIndex++]; + var startAngle = target.GetArcAngle(arcAngleIndex++); + var endAngle = target.GetArcAngle(arcAngleIndex++); + var clockwise = target.GetArcClockwise(arcClockwiseIndex++); + + while (startAngle < 0) + { + startAngle += 360; + } + + while (endAngle < 0) + { + endAngle += 360; + } + + var rect = new SKRect(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); + var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); + + startAngle *= -1; + if (!clockwise) + sweep *= -1; + + path.AddArc(rect, startAngle, sweep); + } + else if (type == PathOperation.Close) + { + path.Close(); + } + } + + return path; + } + + public static SizeF AsSize(this SKSize target) + { + return new SizeF(target.Width, target.Height); + } + + public static SKSize AsSizeF(this SizeF target) + { + return new SKSize(target.Width, target.Height); + } + + public static PointF AsPointF(this SKPoint target) + { + return new PointF(target.X, target.Y); + } + + public static SKBitmap GetPatternBitmap(this PatternPaint patternPaint, float scale = 1) + { + var pattern = patternPaint?.Pattern; + if (pattern == null) + return null; + + using (var context = new SkiaBitmapExportContext((int) (pattern.Width * scale), (int) (pattern.Height * scale), scale, disposeBitmap: false)) + { + var canvas = context.Canvas; + + canvas.Scale(scale, scale); + pattern.Draw(canvas); + + return context.Bitmap; + } + } + + public static SKBitmap GetPatternBitmap(this PatternPaint patternPaint, float scaleX, float scaleY, object currentFigure) + { + var pattern = patternPaint?.Pattern; + if (pattern == null) + return null; + + using (var context = new SkiaBitmapExportContext((int) (pattern.Width * scaleX), (int) (pattern.Height * scaleY), 1, disposeBitmap: false)) + { + var canvas = context.Canvas; + + if (currentFigure != null) + { + } + + canvas.Scale(scaleX, scaleY); + pattern.Draw(canvas); + + if (currentFigure != null) + { + } + + //var filename = "/storage/emulated/0/" + pattern.GetType().Name + ".png"; + //System.Console.WriteLine("Writing to :{0}",filename); + //context.WriteToFile (filename); + return context.Bitmap; + } + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKPaintExtensions.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKPaintExtensions.cs new file mode 100644 index 000000000000..b9d407a6e574 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKPaintExtensions.cs @@ -0,0 +1,39 @@ +using SkiaSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public static class SKPaintExtensions + { + public static SKPaint CreateCopy(this SKPaint paint) + { + if (paint == null) + return null; + + var copy = new SKPaint + { + BlendMode = paint.BlendMode, + Color = paint.Color, + ColorFilter = paint.ColorFilter, + ImageFilter = paint.ImageFilter, + IsAntialias = paint.IsAntialias, + IsStroke = paint.IsStroke, + MaskFilter = paint.MaskFilter, + Shader = paint.Shader, + StrokeCap = paint.StrokeCap, + StrokeJoin = paint.StrokeJoin, + StrokeMiter = paint.StrokeMiter, + StrokeWidth = paint.StrokeWidth, + TextAlign = paint.TextAlign, + TextEncoding = paint.TextEncoding, + TextScaleX = paint.TextScaleX, + TextSize = paint.TextSize, + TextSkewX = paint.TextSkewX, + Typeface = paint.Typeface, + }; + + return copy; + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaBitmapExportContext.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaBitmapExportContext.cs new file mode 100644 index 000000000000..0b1824503d61 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaBitmapExportContext.cs @@ -0,0 +1,112 @@ +using System.IO; +using SkiaSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaBitmapExportContext : BitmapExportContext + { + private readonly bool _disposeBitmap; + + private SKBitmap _bitmap; + private SKImage _image; + private SKSurface _surface; + private SKCanvas _skiaCanvas; + private ScalingCanvas _canvas; + + public SkiaBitmapExportContext( + int width, + int height, + float displayScale, + int dpi = 72, + bool disposeBitmap = true, + bool transparent = true) : base(width, height, dpi) + { + if (transparent) + { + var imageInfo = new SKImageInfo(width, height, SKColorType.Rgba8888, SKAlphaType.Premul); + _surface = SKSurface.Create(imageInfo); + } + else + { + var imageInfo = new SKImageInfo(width, height, SKColorType.Rgb565, SKAlphaType.Opaque); + _surface = SKSurface.Create(imageInfo); + } + + if (_surface == null) + { + Logger.Warn("Unable to create a Skia surface"); + return; + } + + _skiaCanvas = _surface.Canvas; + var nativeCanvas = new SkiaCanvas + { + Canvas = _skiaCanvas, + DisplayScale = displayScale + }; + _canvas = new ScalingCanvas(nativeCanvas); + _disposeBitmap = disposeBitmap; + } + + public override ICanvas Canvas => _canvas; + + public override IImage Image => new SkiaImage(Bitmap); + + public SKImage SKImage => _image ?? (_image = _surface.Snapshot()); + + public SKBitmap Bitmap + { + get + { + if (_bitmap == null) + { + var data = SKImage.Encode(); + _bitmap = SKBitmap.Decode(data); + } + + return _bitmap; + } + } + + public override void Dispose() + { + if (_skiaCanvas != null) + { + _skiaCanvas.Dispose(); + _skiaCanvas = null; + } + + if (_surface != null) + { + _surface.Dispose(); + _surface = null; + } + + if (_image != null) + { + _image.Dispose(); + _image = null; + } + + if (_bitmap != null && _disposeBitmap) + { + _bitmap.Dispose(); + _bitmap = null; + } + + _canvas = null; + + base.Dispose(); + } + + public override void WriteToStream(Stream stream) + { + using (var data = SKImage.Encode(SKEncodedImageFormat.Png, 100)) + { + data.SaveTo(stream); + } + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvas.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvas.cs new file mode 100644 index 000000000000..039c20dd4377 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvas.cs @@ -0,0 +1,904 @@ +using System; +using Microsoft.Maui.Graphics.Text; +using SkiaSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaCanvas : AbstractCanvas, IBlurrableCanvas + { + private static SKPaint _defaultFillPaint; + private static SKPaint _defaultFontPaint; + private static SKPaint _defaultStrokePaint; + + //private readonly SKMatrix _shaderMatrix = new SKMatrix(); + + private SKCanvas _canvas; + private float _displayScale = 1; + private SKShader _shader; + + public SkiaCanvas() : base(CreateNewState, CreateStateCopy) + { + } + + public override float DisplayScale => _displayScale; + + public SKCanvas Canvas + { + get => _canvas; + set + { + _canvas = null; + ResetState(); + _canvas = value; + } + } + + public override bool Antialias + { + set => CurrentState.AntiAlias = value; + } + + protected override float NativeStrokeSize + { + set => CurrentState.NativeStrokeSize = value; + } + + public override float MiterLimit + { + set => CurrentState.MiterLimit = value; + } + + public override float Alpha + { + set => CurrentState.Alpha = value; + } + + public override LineCap StrokeLineCap + { + set => CurrentState.StrokeLineCap = value; + } + + public override LineJoin StrokeLineJoin + { + set => CurrentState.StrokeLineJoin = value; + } + + public override Color StrokeColor + { + set => CurrentState.StrokeColor = value ?? Colors.Black; + } + + public override Color FontColor + { + set => CurrentState.FontColor = value ?? Colors.Black; + } + + public override string FontName + { + set + { + if (value != null) + CurrentState.FontName = value; + else + CurrentState.FontName = SkiaGraphicsService.Instance.SystemFontName; + } + } + + public override float FontSize + { + set => CurrentState.FontSize = value; + } + + public override Color FillColor + { + set + { + if (_shader != null) + { + CurrentState.SetFillPaintShader(null); + _shader.Dispose(); + _shader = null; + } + + CurrentState.FillColor = value ?? Colors.White; + } + } + + public override BlendMode BlendMode + { + set + { + /* todo: implement this + CGBlendMode blendMode = CGBlendMode.Normal; + + switch (value) + { + case BlendMode.Clear: + blendMode = CGBlendMode.Clear; + break; + case BlendMode.Color: + blendMode = CGBlendMode.Color; + break; + case BlendMode.ColorBurn: + blendMode = CGBlendMode.ColorBurn; + break; + case BlendMode.ColorDodge: + blendMode = CGBlendMode.ColorDodge; + break; + case BlendMode.Copy: + blendMode = CGBlendMode.Copy; + break; + case BlendMode.Darken: + blendMode = CGBlendMode.Darken; + break; + case BlendMode.DestinationAtop: + blendMode = CGBlendMode.DestinationAtop; + break; + case BlendMode.DestinationIn: + blendMode = CGBlendMode.DestinationIn; + break; + case BlendMode.DestinationOut: + blendMode = CGBlendMode.DestinationOut; + break; + case BlendMode.DestinationOver: + blendMode = CGBlendMode.DestinationOver; + break; + case BlendMode.Difference: + blendMode = CGBlendMode.Difference; + break; + case BlendMode.Exclusion: + blendMode = CGBlendMode.Exclusion; + break; + case BlendMode.HardLight: + blendMode = CGBlendMode.HardLight; + break; + case BlendMode.Hue: + blendMode = CGBlendMode.Hue; + break; + case BlendMode.Lighten: + blendMode = CGBlendMode.Lighten; + break; + case BlendMode.Luminosity: + blendMode = CGBlendMode.Luminosity; + break; + case BlendMode.Multiply: + blendMode = CGBlendMode.Multiply; + break; + case BlendMode.Normal: + blendMode = CGBlendMode.Normal; + break; + case BlendMode.Overlay: + blendMode = CGBlendMode.Overlay; + break; + case BlendMode.PlusDarker: + blendMode = CGBlendMode.PlusDarker; + break; + case BlendMode.PlusLighter: + blendMode = CGBlendMode.PlusLighter; + break; + case BlendMode.Saturation: + blendMode = CGBlendMode.Saturation; + break; + case BlendMode.Screen: + blendMode = CGBlendMode.Screen; + break; + case BlendMode.SoftLight: + blendMode = CGBlendMode.SoftLight; + break; + case BlendMode.SourceAtop: + blendMode = CGBlendMode.SourceAtop; + break; + case BlendMode.SourceIn: + blendMode = CGBlendMode.SourceIn; + break; + case BlendMode.SourceOut: + blendMode = CGBlendMode.SourceOut; + break; + case BlendMode.XOR: + blendMode = CGBlendMode.XOR; + break; + } + + canvas.SetBlendMode(blendMode);*/ + + //CurrentState.FillPaint.SetXfermode(new + } + } + + private static SkiaCanvasState CreateNewState(object context) + { + if (_defaultFillPaint == null) + { + _defaultFillPaint = new SKPaint + { + Color = SKColors.White, + IsStroke = false, + IsAntialias = true + }; + + _defaultStrokePaint = new SKPaint + { + Color = SKColors.Black, + StrokeWidth = 1, + StrokeMiter = CanvasDefaults.DefaultMiterLimit, + IsStroke = true, + IsAntialias = true + }; + + _defaultFontPaint = new SKPaint + { + Color = SKColors.Black, + IsAntialias = true, + Typeface = SKTypeface.FromFamilyName("Arial") + }; + } + + var state = new SkiaCanvasState + { + FillPaint = _defaultFillPaint.CreateCopy(), + StrokePaint = _defaultStrokePaint.CreateCopy(), + FontPaint = _defaultFontPaint.CreateCopy(), + FontName = SkiaGraphicsService.Instance.SystemFontName + }; + + return state; + } + + public void SetDisplayScale(float value) + { + _displayScale = value; + } + + private static SkiaCanvasState CreateStateCopy(SkiaCanvasState prototype) + { + return new SkiaCanvasState(prototype); + } + + public override void Dispose() + { + _defaultFillPaint.Dispose(); + _defaultStrokePaint.Dispose(); + _defaultFontPaint.Dispose(); + + base.Dispose(); + } + + protected override void NativeSetStrokeDashPattern( + float[] pattern, + float strokeSize) + { + CurrentState.SetStrokeDashPattern(pattern, strokeSize); + } + + public override void SetToSystemFont() + { + CurrentState.FontName = SkiaGraphicsService.Instance.SystemFontName; + } + + public override void SetToBoldSystemFont() + { + CurrentState.FontName = SkiaGraphicsService.Instance.BoldSystemFontName; + } + + public override void SetFillPaint(Paint paint, RectangleF rectangle) + { + if (paint == null) + paint = Colors.White.AsPaint(); + + if (_shader != null) + { + CurrentState.SetFillPaintShader(null); + _shader.Dispose(); + _shader = null; + } + + if (paint is LinearGradientPaint linearGradientPaint) + { + float x1 = (float)(linearGradientPaint.StartPoint.X * rectangle.Width) + rectangle.X; + float y1 = (float)(linearGradientPaint.StartPoint.Y * rectangle.Height) + rectangle.Y; + + float x2 = (float)(linearGradientPaint.EndPoint.X * rectangle.Width) + rectangle.X; + float y2 = (float)(linearGradientPaint.EndPoint.Y * rectangle.Height) + rectangle.Y; + + var colors = new SKColor[linearGradientPaint.GradientStops.Length]; + var stops = new float[colors.Length]; + + var vStops = linearGradientPaint.GetSortedStops(); + + for (var i = 0; i < vStops.Length; i++) + { + colors[i] = vStops[i].Color.ToColor(CurrentState.Alpha); + stops[i] = vStops[i].Offset; + } + + try + { + CurrentState.FillColor = Colors.White; + _shader = SKShader.CreateLinearGradient( + new SKPoint(x1, y1), + new SKPoint(x2, y2), + colors, + stops, + SKShaderTileMode.Clamp); + CurrentState.SetFillPaintShader(_shader); + } + catch (Exception exc) + { + Logger.Debug(exc); + FillColor = linearGradientPaint.BlendStartAndEndColors(); + } + } + else if (paint is RadialGradientPaint radialGradientPaint) + { + var colors = new SKColor[radialGradientPaint.GradientStops.Length]; + var stops = new float[colors.Length]; + + var vStops = radialGradientPaint.GetSortedStops(); + + for (var i = 0; i < vStops.Length; i++) + { + colors[i] = vStops[i].Color.ToColor(CurrentState.Alpha); + stops[i] = vStops[i].Offset; + } + + float centerX = (float)(radialGradientPaint.Center.X * rectangle.Width) + rectangle.X; + float centerY = (float)(radialGradientPaint.Center.Y * rectangle.Height) + rectangle.Y; + float radius = (float)radialGradientPaint.Radius * Math.Max(rectangle.Height, rectangle.Width); + + if (radius == 0) + radius = Geometry.GetDistance(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); + + try + { + CurrentState.FillColor = Colors.White; + _shader = SKShader.CreateRadialGradient( + new SKPoint(centerX, centerY), + radius, + colors, + stops, + SKShaderTileMode.Clamp); + CurrentState.SetFillPaintShader(_shader); + } + catch (Exception exc) + { + Logger.Debug(exc); + FillColor = radialGradientPaint.BlendStartAndEndColors(); + } + } + else if (paint is PatternPaint patternPaint) + { + SKBitmap bitmap = patternPaint.GetPatternBitmap(DisplayScale); + + if (bitmap != null) + { + try + { + CurrentState.FillColor = Colors.White; + CurrentState.SetFillPaintFilterBitmap(true); + + _shader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat); + + //_shaderMatrix.Reset (); + //_shaderMatrix.PreScale (CurrentState.ScaleX, CurrentState.ScaleY); + //_shader.SetLocalMatrix (shaderMatrix); + + CurrentState.SetFillPaintShader(_shader); + } + catch (Exception exc) + { + Logger.Debug(exc); + FillColor = paint.BackgroundColor; + } + } + else + { + FillColor = paint.BackgroundColor; + } + } + else if (paint is ImagePaint imagePaint) + { + var image = imagePaint.Image as SkiaImage; + if (image != null) + { + SKBitmap bitmap = image.NativeImage; + + if (bitmap != null) + { + try + { + CurrentState.FillColor = Colors.White; + CurrentState.SetFillPaintFilterBitmap(true); + + _shader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat); + //_shaderMatrix.Reset (); + //_shaderMatrix.PreScale (CurrentState.ScaleX, CurrentState.ScaleY); + //_shader.SetLocalMatrix (shaderMatrix); + + CurrentState.SetFillPaintShader(_shader); + } + catch (Exception exc) + { + Logger.Debug(exc); + FillColor = paint.BackgroundColor; + } + } + else + { + FillColor = Colors.White; + } + } + else + { + FillColor = Colors.White; + } + } + else + { + FillColor = paint.BackgroundColor; + } + } + + protected override void NativeDrawLine( + float x1, + float y1, + float x2, + float y2) + { + _canvas.DrawLine(x1, y1, x2, y2, CurrentState.StrokePaintWithAlpha); + } + + protected override void NativeDrawArc( + float x, + float y, + float width, + float height, + float startAngle, + float endAngle, + bool clockwise, + bool closed) + { + while (startAngle < 0) + startAngle += 360; + + while (endAngle < 0) + endAngle += 360; + + var rectX = x; + var rectY = y; + var rectWidth = width; + var rectHeight = height; + + var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); + + var rect = new SKRect(rectX, rectY, rectX + rectWidth, rectY + rectHeight); + + startAngle *= -1; + if (!clockwise) + sweep *= -1; + + if (closed) + { + var nativePath = new SKPath(); + nativePath.AddArc(rect, startAngle, sweep); + nativePath.Close(); + _canvas.DrawPath(nativePath, CurrentState.StrokePaintWithAlpha); + nativePath.Dispose(); + } + else + { + // todo: delete this after the api is bound + var nativePath = new SKPath(); + nativePath.AddArc(rect, startAngle, sweep); + _canvas.DrawPath(nativePath, CurrentState.StrokePaintWithAlpha); + nativePath.Dispose(); + + // todo: restore this when the api is bound. + //_canvas.DrawArc (rect, startAngle, sweep, false, CurrentState.StrokePaintWithAlpha); + } + } + + public override void FillArc( + float x, + float y, + float width, + float height, + float startAngle, + float endAngle, + bool clockwise) + { + while (startAngle < 0) + startAngle += 360; + + while (endAngle < 0) + endAngle += 360; + + var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); + var rect = new SKRect(x, y, x + width, y + height); + + startAngle *= -1; + if (!clockwise) + sweep *= -1; + + // todo: delete this after the api is bound + var nativePath = new SKPath(); + nativePath.AddArc(rect, startAngle, sweep); + _canvas.DrawPath(nativePath, CurrentState.FillPaintWithAlpha); + nativePath.Dispose(); + + // todo: restore this when the api is bound. + //_canvas.DrawArc (rect, startAngle, sweep, false, CurrentState.FillPaintWithAlpha); + } + + protected override void NativeDrawRectangle( + float x, + float y, + float width, + float height) + { + float rectX = 0, rectY = 0, rectWidth = 0, rectHeight = 0; + + var strokeSize = CurrentState.ScaledStrokeSize; + if (strokeSize <= 0) + return; + + rectX = x; + rectY = y; + rectWidth = width; + rectHeight = height; + + _canvas.DrawRect(rectX, rectY, rectWidth, rectHeight, CurrentState.StrokePaintWithAlpha); + } + + public override void FillRectangle( + float x, + float y, + float width, + float height) + { + var rectX = x; + var rectY = y; + var rectWidth = width; + var rectHeight = height; + + _canvas.DrawRect(rectX, rectY, rectWidth, rectHeight, CurrentState.FillPaintWithAlpha); + } + + protected override void NativeDrawRoundedRectangle( + float x, + float y, + float width, + float height, + float aCornerRadius) + { + // These values work for a stroke location of center. + var strokeSize = CurrentState.ScaledStrokeSize; + + var rectX = x; + var rectY = y; + var rectWidth = width; + var rectHeight = height; + var radius = aCornerRadius; + + _canvas.DrawRoundRect(rectX, rectY, rectWidth, rectHeight, radius, radius, CurrentState.StrokePaintWithAlpha); + } + + public override void FillRoundedRectangle( + float x, + float y, + float width, + float height, + float aCornerRadius) + { + var rectX = x; + var rectY = y; + var rectWidth = width; + var rectHeight = height; + var radius = aCornerRadius; + + var rect = new SKRect(rectX, rectY, rectX + rectWidth, rectY + rectHeight); + _canvas.DrawRoundRect(rect, radius, radius, CurrentState.FillPaintWithAlpha); + } + + protected override void NativeDrawEllipse( + float x, + float y, + float width, + float height) + { + // These values work for a stroke location of center. + var strokeSize = CurrentState.ScaledStrokeSize; + + var rectX = x; + var rectY = y; + var rectWidth = width; + var rectHeight = height; + + var rect = new SKRect(rectX, rectY, rectX + rectWidth, rectY + rectHeight); + _canvas.DrawOval(rect, CurrentState.StrokePaintWithAlpha); + } + + public override void FillEllipse( + float x, + float y, + float width, + float height) + { + // These values work for a stroke location of center. + var rectX = x; + var rectY = y; + var rectWidth = width; + var rectHeight = height; + + var rect = new SKRect(rectX, rectY, rectX + rectWidth, rectY + rectHeight); + _canvas.DrawOval(rect, CurrentState.FillPaintWithAlpha); + } + + public override void SubtractFromClip( + float x, + float y, + float width, + float height) + { + var rect = new SKRect(x, y, x + width, y + height); + _canvas.ClipRect(rect, SKClipOperation.Difference); + } + + protected override void NativeDrawPath( + PathF path) + { + var nativePath = path.AsSkiaPath(); + _canvas.DrawPath(nativePath, CurrentState.StrokePaintWithAlpha); + nativePath.Dispose(); + } + + public override void ClipPath(PathF path, + WindingMode windingMode = WindingMode.NonZero) + { + var nativePath = path.AsSkiaPath(); + nativePath.FillType = windingMode == WindingMode.NonZero ? SKPathFillType.Winding : SKPathFillType.EvenOdd; + _canvas.ClipPath(nativePath); + } + + public override void FillPath(PathF path, + WindingMode windingMode) + { + var nativePath = path.AsSkiaPath(); + nativePath.FillType = windingMode == WindingMode.NonZero ? SKPathFillType.Winding : SKPathFillType.EvenOdd; + _canvas.DrawPath(nativePath, CurrentState.FillPaintWithAlpha); + nativePath.Dispose(); + } + + public override void DrawString( + string value, + float x, + float y, + HorizontalAlignment horizAlignment) + { + if (string.IsNullOrEmpty(value)) + return; + + if (horizAlignment == HorizontalAlignment.Left) + { + _canvas.DrawText(value, x, y, CurrentState.FontPaint); + } + else if (horizAlignment == HorizontalAlignment.Right) + { + var paint = CurrentState.FontPaint; + var width = paint.MeasureText(value); + x -= width; + _canvas.DrawText(value, x, y, CurrentState.FontPaint); + } + else + { + var paint = CurrentState.FontPaint; + var width = paint.MeasureText(value); + x -= width / 2; + _canvas.DrawText(value, x, y, CurrentState.FontPaint); + } + } + + public override void DrawString( + string value, + float x, + float y, + float width, + float height, + HorizontalAlignment horizAlignment, + VerticalAlignment vertAlignment, + TextFlow textFlow = TextFlow.ClipBounds, + float lineSpacingAdjustment = 0) + { + if (string.IsNullOrEmpty(value)) + return; + + var rect = new RectangleF(x, y, width, height); + + var attributes = new StandardTextAttributes() + { + FontSize = CurrentState.FontPaint.TextSize, + FontName = CurrentState.FontName, + HorizontalAlignment = horizAlignment, + VerticalAlignment = vertAlignment, + }; + + LayoutLine callback = ( + point, + textual, + text, + ascent, + descent, + leading) => + { + _canvas.DrawText(text, point.X, point.Y, CurrentState.FontPaint); + }; + + using (var textLayout = new SkiaTextLayout(value, rect, attributes, callback, textFlow, CurrentState.FontPaint)) + { + textLayout.LayoutText(); + } + } + + public override void DrawText(IAttributedText value, float x, float y, float width, float height) + { + Logger.Debug("Not yet implemented."); + DrawString(value?.Text, x, y, width, height, HorizontalAlignment.Left, VerticalAlignment.Top); + } + + public override void ResetState() + { + base.ResetState(); + + if (_shader != null) + { + _shader.Dispose(); + _shader = null; + } + + CurrentState.Reset(_defaultFontPaint, _defaultFillPaint, _defaultStrokePaint); + } + + public override bool RestoreState() + { + if (_shader != null) + { + _shader.Dispose(); + _shader = null; + } + + return base.RestoreState(); + } + + protected override void StateRestored(SkiaCanvasState state) + { + _canvas?.Restore(); + } + + public override void SetShadow( + SizeF offset, + float blur, + Color color) + { + var actualOffset = offset; + if (actualOffset == null) + actualOffset = CanvasDefaults.DefaultShadowOffset; + + var sx = actualOffset.Width; + var sy = actualOffset.Height; + + if (color == null) + { + var actualColor = Colors.Black.AsSKColorMultiplyAlpha(CurrentState.Alpha); + CurrentState.SetShadow(blur, sx, sy, actualColor); + } + else + { + var actualColor = color.AsSKColorMultiplyAlpha(CurrentState.Alpha); + CurrentState.SetShadow(blur, sx, sy, actualColor); + } + } + + protected override void NativeRotate( + float degrees, + float radians, + float x, + float y) + { + _canvas.RotateDegrees(degrees, x, y); + } + + protected override void NativeRotate( + float degrees, + float radians) + { + _canvas.RotateDegrees(degrees); + } + + protected override void NativeScale( + float xFactor, + float yFactor) + { + //canvas.Scale((float)aXFactor, (float)aYFactor); + CurrentState.SetScale(Math.Abs(xFactor), Math.Abs(yFactor)); + if (xFactor < 0 || yFactor < 0) + _canvas.Scale(xFactor < 0 ? -1 : 1, yFactor < 0 ? -1 : 1); + } + + protected override void NativeTranslate( + float tx, + float ty) + { + _canvas.Translate(tx * CurrentState.ScaleX, ty * CurrentState.ScaleY); + } + + protected override void NativeConcatenateTransform(AffineTransform transform) + { + var matrix = new SKMatrix(); + + var values = new float[6]; + _canvas.TotalMatrix.GetValues(values); + matrix.Values = values; + + // todo: implement me + //matrix.PostConcat (transform.AsMatrix ()); + //canvas.Matrix = matrix; + } + + public override void SaveState() + { + _canvas.Save(); + base.SaveState(); + } + + public void SetBlur(float radius) + { + CurrentState.SetBlur(radius); + } + + public override void DrawImage( + IImage image, + float x, + float y, + float width, + float height) + { + var skiaImage = image as SkiaImage; + var bitmap = skiaImage?.NativeImage; + if (bitmap != null) + { + var scaleX = CurrentState.ScaleX < 0 ? -1 : 1; + var scaleY = CurrentState.ScaleY < 0 ? -1 : 1; + + _canvas.Save(); + //canvas.Scale (scaleX, scaleY); + var srcRect = new SKRect(0, 0, bitmap.Width, bitmap.Height); + + x *= scaleX; + y *= scaleY; + width *= scaleX; + height *= scaleY; + + var rx1 = Math.Min(x, x + width); + var ry1 = Math.Min(y, y + height); + var rx2 = Math.Max(x, x + width); + var ry2 = Math.Max(y, y + height); + + var destRect = new SKRect(rx1, ry1, rx2, ry2); + var paint = CurrentState.GetImagePaint(1, 1); + _canvas.DrawBitmap(bitmap, srcRect, destRect, paint); + paint?.Dispose(); + _canvas.Restore(); + } + } + + public override void ClipRectangle( + float x, + float y, + float width, + float height) + { + _canvas.ClipRect(new SKRect(x, y, x + width, y + height)); + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvasState.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvasState.cs new file mode 100644 index 000000000000..bfc38a10a8ca --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvasState.cs @@ -0,0 +1,451 @@ +using SkiaSharp; +using Color = SkiaSharp.SKColor; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaCanvasState : CanvasState, IBlurrableCanvas + { + public float Alpha = 1; + private SKPaint _fillPaint; + private SKPaint _strokePaint; + private string _fontName = "Arial"; + private SKPaint _fontPaint; + private float _fontSize = 10f; + private float _scaleX = 1; + private float _scaleY = 1; + private bool _typefaceInvalid; + private bool _isBlurred; + private float _blurRadius; + private SKMaskFilter _blurFilter; + private SKImageFilter _shadowFilter; + private bool _shadowed; + private SKColor _shadowColor; + private float _shadowX; + private float _shadowY; + private float _shadowBlur; + + private Color _strokeColor = Colors.Black; + private Color _fillColor = Colors.White; + private Color _fontColor = Colors.Black; + + public SkiaCanvasState() + { + } + + public SkiaCanvasState(SkiaCanvasState prototype) : base(prototype) + { + _strokeColor = prototype._strokeColor; + _fillColor = prototype._fillColor; + _fontColor = prototype._fontColor; + + _fontPaint = prototype.FontPaint.CreateCopy(); + _fillPaint = prototype.FillPaint.CreateCopy(); + _strokePaint = prototype.StrokePaint.CreateCopy(); + _fontName = prototype._fontName; + _fontSize = prototype._fontSize; + Alpha = prototype.Alpha; + _scaleX = prototype._scaleX; + _scaleY = prototype._scaleY; + _typefaceInvalid = false; + + _isBlurred = prototype._isBlurred; + _blurRadius = prototype._blurRadius; + + _shadowed = prototype._shadowed; + //_shadowFilter = prototype._shadowFilter; // There is no reason the copy really needs to know about this. + _shadowColor = prototype._shadowColor; + _shadowX = prototype._shadowX; + _shadowY = prototype._shadowY; + _shadowBlur = prototype._shadowBlur; + } + + public Color StrokeColor + { + get => _strokeColor; + set => _strokeColor = value; + } + + public Color FillColor + { + get => _fillColor; + set + { + FillPaint.Shader = null; + _fillColor = value; + } + } + + public Color FontColor + { + get => _fontColor; + set + { + _fontColor = value; + if (value != null) + FontPaint.Color = _fontColor.AsSKColor(); + else + FontPaint.Color = SKColors.Black; + } + } + + public LineCap StrokeLineCap + { + set + { + if (value == LineCap.Butt) + StrokePaint.StrokeCap = SKStrokeCap.Butt; + else if (value == LineCap.Round) + StrokePaint.StrokeCap = SKStrokeCap.Round; + else if (value == LineCap.Square) + StrokePaint.StrokeCap = SKStrokeCap.Square; + } + } + + public LineJoin StrokeLineJoin + { + set + { + if (value == LineJoin.Miter) + StrokePaint.StrokeJoin = SKStrokeJoin.Miter; + else if (value == LineJoin.Round) + StrokePaint.StrokeJoin = SKStrokeJoin.Round; + else if (value == LineJoin.Bevel) + StrokePaint.StrokeJoin = SKStrokeJoin.Bevel; + } + } + + public float MiterLimit + { + set => StrokePaint.StrokeMiter = value; + } + + public void SetStrokeDashPattern(float[] pattern, float strokeSize) + { + if (pattern == null || pattern.Length == 0 || strokeSize == 0) + { + StrokePaint.PathEffect = null; + } + else + { + float scaledStrokeSize = strokeSize * ScaleX; + + if (scaledStrokeSize > 1 || scaledStrokeSize < 1) + { + var scaledPattern = new float[pattern.Length]; + for (var i = 0; i < pattern.Length; i++) + scaledPattern[i] = pattern[i] * scaledStrokeSize; + StrokePaint.PathEffect = SKPathEffect.CreateDash(scaledPattern, 0); + } + else + { + StrokePaint.PathEffect = SKPathEffect.CreateDash(pattern, 0); + } + } + } + + public bool AntiAlias + { + set => StrokePaint.IsAntialias = value; + } + + public bool IsBlurred => _isBlurred; + + public float BlurRadius => _blurRadius; + + public void SetBlur(float radius) + { + if (radius != _blurRadius) + { + if (_blurFilter != null) + { + _blurFilter.Dispose(); + _blurFilter = null; + } + + if (radius > 0) + { + _isBlurred = true; + _blurRadius = radius; + _blurFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, _blurRadius); + + if (_fillPaint != null) _fillPaint.MaskFilter = _blurFilter; + if (_strokePaint != null) _strokePaint.MaskFilter = _blurFilter; + if (_fontPaint != null) _fontPaint.MaskFilter = _blurFilter; + } + else + { + _isBlurred = false; + _blurRadius = 0; + + if (_fillPaint != null) _fillPaint.MaskFilter = null; + if (_strokePaint != null) _strokePaint.MaskFilter = null; + if (_fontPaint != null) _fontPaint.MaskFilter = null; + } + } + } + + public float NativeStrokeSize + { + set => StrokePaint.StrokeWidth = value * _scaleX; + } + + public float FontSize + { + set + { + _fontSize = value; + FontPaint.TextSize = _fontSize * _scaleX; + } + } + + public string FontName + { + set + { + if (_fontName != value && (_fontName != null && !_fontName.Equals(value))) + { + _fontName = value; + _typefaceInvalid = true; + } + } + + get => _fontName; + } + + public SKPaint FontPaint + { + get + { + if (_fontPaint == null) + { + _fontPaint = new SKPaint + { + Color = SKColors.Black, + IsAntialias = true, + Typeface = SkiaDelegatingFontService.Instance.GetTypeface(SkiaGraphicsService.Instance.SystemFontName) + }; + } + + if (_typefaceInvalid) + { + _fontPaint.Typeface = SkiaDelegatingFontService.Instance.GetTypeface(_fontName); + _typefaceInvalid = false; + } + + return _fontPaint; + } + + set => _fontPaint = value; + } + + public SKPaint FillPaint + { + private get + { + return _fillPaint + ?? (_fillPaint = new SKPaint + { + Color = SKColors.White, + IsStroke = false, + IsAntialias = true + }); + } + + set { _fillPaint = value; } + } + + public SKPaint StrokePaint + { + private get + { + if (_strokePaint == null) + { + var paint = new SKPaint + { + Color = SKColors.Black, + StrokeWidth = 1, + StrokeMiter = CanvasDefaults.DefaultMiterLimit, + IsStroke = true, + IsAntialias = true + }; + + _strokePaint = paint; + + return paint; + } + + return _strokePaint; + } + + set { _strokePaint = value; } + } + + public SKPaint StrokePaintWithAlpha + { + get + { + var paint = StrokePaint; + + var r = (byte) (_strokeColor.Red * 255f); + var g = (byte) (_strokeColor.Green * 255f); + var b = (byte) (_strokeColor.Blue * 255f); + var a = (byte) (_strokeColor.Alpha * 255f * Alpha); + + paint.Color = new SKColor(r, g, b, a); + return paint; + } + } + + public SKPaint FillPaintWithAlpha + { + get + { + var paint = FillPaint; + + var r = (byte) (_fillColor.Red * 255f); + var g = (byte) (_fillColor.Green * 255f); + var b = (byte) (_fillColor.Blue * 255f); + var a = (byte) (_fillColor.Alpha * 255f * Alpha); + + paint.Color = new SKColor(r, g, b, a); + return paint; + } + } + + public void SetFillPaintShader(SKShader shader) + { + FillPaint.Shader = shader; + } + + public void SetFillPaintFilterBitmap(bool value) + { + // todo: restore this + //FillPaint.FilterBitmap = value; + } + + public float ScaledStrokeSize => StrokeSize * _scaleX; + + public float ScaledFontSize => _fontSize * _scaleX; + + public float ScaleX => _scaleX; + + public float ScaleY => _scaleY; + + #region IDisposable Members + + public override void Dispose() + { + _fontPaint?.Dispose(); + _fontPaint = null; + + _strokePaint?.Dispose(); + _strokePaint = null; + + _fillPaint?.Dispose(); + _fillPaint = null; + + _shadowFilter?.Dispose(); + _shadowFilter = null; + + _blurFilter?.Dispose(); + _blurFilter = null; + + base.Dispose(); + } + + #endregion + + public void SetShadow(float blur, float sx, float sy, SKColor color) + { +#pragma warning disable CS0618 + _shadowFilter = SKImageFilter.CreateDropShadow(sx, sy, blur, blur, color, SKDropShadowImageFilterShadowMode.DrawShadowAndForeground); +#pragma warning restore CS0618 + FillPaint.ImageFilter = _shadowFilter; + StrokePaint.ImageFilter = _shadowFilter; + FontPaint.ImageFilter = _shadowFilter; + + _shadowed = true; + _shadowBlur = blur; + _shadowX = sx; + _shadowY = sy; + _shadowColor = color; + } + + public SKPaint GetShadowPaint(float sx, float sy) + { + if (_shadowed) + { + var shadowPaint = new SKPaint + { + Color = SKColors.Black, + IsStroke = false, + IsAntialias = true + }; + + // todo: implement me + shadowPaint.ImageFilter = _shadowFilter; + //shadowPaint.SetShadowLayer(shadowBlur, shadowX * sx, shadowY * sy, shadowColor); + //shadowPaint.Alpha = (int) (Alpha*255f); + return shadowPaint; + } + + return null; + } + + public SKPaint GetImagePaint(float sx, float sy) + { + var imagePaint = new SKPaint + { + Color = SKColors.Black, + IsStroke = false, + IsAntialias = true + }; + + if (Alpha < 1) + { + var color = new SKColor(255, 255, 255, (byte) (Alpha * 255f)); + imagePaint.ColorFilter = SKColorFilter.CreateBlendMode(color, SKBlendMode.Modulate); + } + + if (_isBlurred) + imagePaint.MaskFilter = _blurFilter; + + return imagePaint; + } + + public void SetScale(float sx, float sy) + { + _scaleX = _scaleX * sx; + _scaleY = _scaleY * sy; + + StrokePaint.StrokeWidth = StrokeSize * _scaleX; + FontPaint.TextSize = _fontSize * _scaleX; + } + + public void Reset(SKPaint fontPaint, SKPaint fillPaint, SKPaint strokePaint) + { + _fontPaint?.Dispose(); + _fontPaint = fontPaint.CreateCopy(); + + _fillPaint?.Dispose(); + _fillPaint = fillPaint.CreateCopy(); + + _strokePaint?.Dispose(); + _strokePaint = strokePaint.CreateCopy(); + + _shadowFilter?.Dispose(); + _shadowFilter = null; + + _blurFilter?.Dispose(); + _blurFilter = null; + + _fontName = "Arial"; + _fontSize = 10f; + Alpha = 1; + _scaleX = 1; + _scaleY = 1; + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaDelegatingFontService.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaDelegatingFontService.cs new file mode 100644 index 000000000000..8b80b832ef66 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaDelegatingFontService.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using SkiaSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaDelegatingFontService : AbstractFontService + { + public static SkiaDelegatingFontService Instance = new SkiaDelegatingFontService(); + + private readonly Dictionary _typeFaces = new Dictionary(); + + public override IFontFamily[] GetFontFamilies() + { + var nativeFontService = Fonts.GlobalService; + return nativeFontService.GetFontFamilies(); + } + + public SKTypeface GetTypeface(string name) + { + var nativeFontService = Fonts.GlobalService; + + if (string.IsNullOrEmpty(name)) + { + var style = nativeFontService.GetDefaultFontStyle(); + name = style.Name; + } + + if (!_typeFaces.TryGetValue(name, out var typeface)) + { + try + { + var fontStyle = nativeFontService.GetFontStyleById(name); + + var stream = fontStyle?.OpenStream(); + if (stream != null) + { + typeface = SKTypeface.FromStream(new SKManagedStream(stream)); + } + else if (fontStyle != null) + { + var slant = SKFontStyleSlant.Upright; + if (fontStyle.StyleType == FontStyleType.Italic) + slant = SKFontStyleSlant.Italic; + else if (fontStyle.StyleType == FontStyleType.Oblique) + slant = SKFontStyleSlant.Oblique; + + typeface = SKTypeface.FromFamilyName(fontStyle.FontFamily.Name, fontStyle.Weight, (int) SKFontStyleWidth.Normal, slant); + } + + if (typeface != null) + _typeFaces[name] = typeface; + } + catch (Exception exc) + { + Logger.Info("Unable to load typeface [{0}]" + name, exc); + } + } + + return typeface; + } + + public void ClearFontCache() + { + foreach (var entry in _typeFaces) + { + try + { + entry.Value.Dispose(); + } + catch (Exception exc) + { + Logger.Info("Unable to dispose of a typeface", exc); + } + } + + _typeFaces.Clear(); + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontFamily.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontFamily.cs new file mode 100644 index 000000000000..4cf61b4492ea --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontFamily.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaFontFamily : IFontFamily, IComparable, IComparable + { + private readonly string _name; + private IFontStyle[] _fontStyles; + + public SkiaFontFamily(string name) + { + _name = name; + } + + public string Name => _name; + + public IFontStyle[] GetFontStyles() + { + return _fontStyles ?? (_fontStyles = InitializeFontStyles()); + } + + private IFontStyle[] InitializeFontStyles() + { + var styles = new List(); + + styles.Add( + new SkiaFontStyle( + this, + _name, + _name, + _name, + FontUtils.Normal, + FontStyleType.Normal)); + + styles.Sort(); + return styles.ToArray(); + } + + public override bool Equals(object obj) + { + if (obj == null) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != typeof(SkiaFontFamily)) + return false; + SkiaFontFamily other = (SkiaFontFamily) obj; + return _name == other._name; + } + + public override int GetHashCode() + { + return (_name != null ? _name.GetHashCode() : 0); + } + + public override string ToString() + { + return Name; + } + + public int CompareTo(IFontFamily other) + { + return string.Compare(_name, other.Name, StringComparison.Ordinal); + } + + public int CompareTo(object obj) + { + if (obj is IFontFamily other) + return CompareTo(other); + + return -1; + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontService.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontService.cs new file mode 100644 index 000000000000..dd322fa41437 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontService.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using SkiaSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaFontService : AbstractFontService + { + private readonly Dictionary _typeFaces = new Dictionary(); + private readonly IFontFamily[] _fontFamilies; + private readonly string _systemFontName; + private readonly string _boldSystemFontName; + + public SkiaFontService(string systemFontName, string boldSystemFontName) + { + _systemFontName = systemFontName; + _boldSystemFontName = boldSystemFontName; + + _fontFamilies = InitializeFontFamilies(); + } + + public override IFontFamily[] GetFontFamilies() + { + return _fontFamilies; + } + + public SKTypeface GetTypeface(string name) + { + if (string.IsNullOrEmpty(name)) + name = _systemFontName; + + if (!_typeFaces.TryGetValue(name, out var typeface)) + { + try + { + typeface = SKTypeface.FromFamilyName(name); + + if (typeface != null) + _typeFaces[name] = typeface; + } + catch (Exception exc) + { + typeface = SKTypeface.FromFamilyName(_systemFontName); + Logger.Info("Unable to load typeface [{0}]" + name, exc); + } + } + + return typeface; + } + + public void ClearFontCache() + { + foreach (var entry in _typeFaces) + { + try + { + entry.Value.Dispose(); + } + catch (Exception exc) + { + Logger.Info("Unable to dispose of a typeface", exc); + } + } + + _typeFaces.Clear(); + } + + public IFontFamily[] InitializeFontFamilies() + { + var familyNames = SKFontManager.Default.GetFontFamilies(); + + var families = new List(); + + foreach (var familyName in familyNames) + { + var family = new SkiaFontFamily(familyName); + if (family.GetFontStyles().Length > 0) + families.Add(family); + } + + families.Sort(); + return families.ToArray(); + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontStyle.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontStyle.cs new file mode 100644 index 000000000000..5a6ea9666f41 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontStyle.cs @@ -0,0 +1,74 @@ +using System; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaFontStyle : IFontStyle + { + private readonly SkiaFontFamily _family; + + public SkiaFontStyle(SkiaFontFamily family, string id, string name, string fullName, int weight, FontStyleType styleType) + { + _family = family; + Id = id; + Name = name; + FullName = fullName; + Weight = weight; + StyleType = styleType; + } + + public IFontFamily FontFamily => _family; + + public string Id { get; } + + public string Name { get; } + + public string FullName { get; } + + public int Weight { get; } + + public FontStyleType StyleType { get; } + + public override bool Equals(object obj) + { + if (obj == null) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != typeof(SkiaFontStyle)) + return false; + SkiaFontStyle other = (SkiaFontStyle) obj; + return Id == other.Id; + } + + public override int GetHashCode() + { + return (Id != null ? Id.GetHashCode() : 0); + } + + public override string ToString() + { + return Name; + } + + public int CompareTo(IFontStyle other) + { + if (Name.Equals("Regular") || Name.Equals("Plain") || Name.Equals("Normal")) + { + return -1; + } + else if (other.Name.Equals("Regular") || other.Name.Equals("Plain") || other.Name.Equals("Normal")) + { + return 1; + } + + return String.Compare(Name, other.Name, StringComparison.Ordinal); + } + + public System.IO.Stream OpenStream() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs new file mode 100644 index 000000000000..9ae7a864ac45 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs @@ -0,0 +1,94 @@ +using System.IO; +using SkiaSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaGraphicsService : IGraphicsService + { + public static readonly SkiaGraphicsService Instance = new SkiaGraphicsService(); + + private static SKPaint _strokePaint; + private static SKPaint _fillPaint; + private static SKBitmap _b; + + private SkiaGraphicsService() + { + if (_strokePaint == null) + { + _strokePaint = new SKPaint + { + Color = SKColors.White, + IsStroke = true + }; + + _fillPaint = new SKPaint + { + Color = SKColors.White, + IsStroke = false + }; + + _b = new SKBitmap(1, 1, SKColorType.Rgba8888, SKAlphaType.Premul); + } + } + + public string SystemFontName => "Arial"; + public string BoldSystemFontName => "Arial-Bold"; + + public IImage LoadImageFromStream(Stream stream, ImageFormat formatHint = ImageFormat.Png) + { + using (var s = new SKManagedStream(stream)) + { + using (var codec = SKCodec.Create(s)) + { + var info = codec.Info; + var bitmap = new SKBitmap(info.Width, info.Height, info.ColorType, info.IsOpaque ? SKAlphaType.Opaque : SKAlphaType.Premul); + + var result = codec.GetPixels(bitmap.Info, bitmap.GetPixels(out _)); + if (result == SKCodecResult.Success || result == SKCodecResult.IncompleteInput) + { + return new SkiaImage(bitmap); + } + } + } + + return null; + } + + public SizeF GetStringSize(string value, string fontName, float fontSize) + { + if (string.IsNullOrEmpty(value)) + return new SizeF(); + + var paint = new SKPaint + { + Typeface = SkiaDelegatingFontService.Instance.GetTypeface(fontName), + TextSize = fontSize + }; + var width = paint.MeasureText(value); + paint.Dispose(); + return new SizeF(width, fontSize); + } + + public SizeF GetStringSize(string value, string fontName, float fontSize, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) + { + if (string.IsNullOrEmpty(value)) + return new SizeF(); + + var paint = new SKPaint + { + TextSize = fontSize, + Typeface = SkiaDelegatingFontService.Instance.GetTypeface(fontName) + }; + var width = paint.MeasureText(value); + paint.Dispose(); + return new SizeF(width, fontSize); + } + + public BitmapExportContext CreateBitmapExportContext(int width, int height, float displayScale = 1) + { + return new SkiaBitmapExportContext(width, height, displayScale, 72, false); + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaImage.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaImage.cs new file mode 100644 index 000000000000..4bdd84e82b66 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaImage.cs @@ -0,0 +1,162 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using SkiaSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaImage : IImage + { + private SKBitmap _image; + + public SkiaImage(SKBitmap image) + { + _image = image; + } + + public float Width => _image.Width; + + public float Height => _image.Height; + + public IImage Downsize(float maxWidthOrHeight, bool disposeOriginal = false) + { + // todo: implement + /* + var downsizedImage = image.Downsize ((int)maxWidthOrHeight, disposeOriginal); + return new MDImage (downsizedImage); + */ + return null; + } + + public IImage Downsize(float maxWidth, float maxHeight, bool disposeOriginal = false) + { + /* + var downsizedImage = image.Downsize ((int)maxWidth, (int)maxHeight, disposeOriginal); + return new MDImage (downsizedImage); + */ + return null; + } + + public IImage Resize(float width, float height, ResizeMode resizeMode = ResizeMode.Fit, bool disposeOriginal = false) + { + using (var context = new SkiaBitmapExportContext((int) width, (int) height, 1)) + { + var fx = width / Width; + var fy = height / Height; + + var w = Width; + var h = Height; + + var x = 0f; + var y = 0f; + + if (resizeMode == ResizeMode.Fit) + { + if (fx < fy) + { + w *= fx; + h *= fx; + } + else + { + w *= fy; + h *= fy; + } + + x = (width - w) / 2; + y = (height - h) / 2; + } + else if (resizeMode == ResizeMode.Bleed) + { + if (fx > fy) + { + w *= fx; + h *= fx; + } + else + { + w *= fy; + h *= fy; + } + + x = (width - w) / 2; + y = (height - h) / 2; + } + else + { + w = width; + h = height; + } + + context.Canvas.DrawImage(this, x, y, w, h); + return context.Image; + } + } + + public SKBitmap NativeImage => _image; + + public void Save(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1) + { + throw new NotImplementedException(); + // todo: implement me + + /* + switch (format) + { + case ImageFormat.Jpeg: + image.Compress (Bitmap.CompressFormat.Jpeg, (int)(quality * 100), stream); + break; + default: + image.Compress (Bitmap.CompressFormat.Png, 100, stream); + break; + } + */ + } + + public Task SaveAsync(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1) + { + throw new NotImplementedException(); + // todo: implement me + + /* + switch (format) + { + case ImageFormat.Jpeg: + await image.CompressAsync (Bitmap.CompressFormat.Jpeg, (int)(quality * 100), stream); + break; + default: + await image.CompressAsync (Bitmap.CompressFormat.Png, 100, stream); + break; + } + */ + } + + public void Dispose() + { + var previousValue = Interlocked.Exchange(ref _image, null); + previousValue?.Dispose(); + } + + public void Draw(ICanvas canvas, RectangleF dirtyRect) + { + canvas.DrawImage(this, dirtyRect.Left, dirtyRect.Top, (float)Math.Round(dirtyRect.Width), (float)Math.Round(dirtyRect.Height)); + } + } + + public static class SkiaImageExtensions + { + public static SKBitmap AsBitmap(this IImage image) + { + if (image is SkiaImage skiaImage) + return skiaImage.NativeImage; + + if (image != null) + Logger.Warn("SkiaImageExtensions.AsBitmap: Unable to get SKBitmap from Image. Expected an image of type SkiaImage however an image of type {0} was received.", image.GetType()); + + return null; + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaTextLayout.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaTextLayout.cs new file mode 100644 index 000000000000..8178f6ee5db4 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaTextLayout.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections.Generic; +using SkiaSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia +{ + public class SkiaTextLayout : IDisposable + { + private readonly LayoutLine _callback; + private readonly RectangleF _rect; + private readonly ITextAttributes _textAttributes; + private readonly string _value; + private readonly TextFlow _textFlow; + private readonly SKPaint _paint; + private readonly bool _disposePaint; + private readonly float _lineHeight; + private readonly float _descent; + + public bool WordWrap { get; set; } = true; + + public SkiaTextLayout( + string value, + RectangleF rect, + ITextAttributes textAttributes, + LayoutLine callback, + TextFlow textFlow = TextFlow.ClipBounds, + SKPaint paint = null) + { + _value = value; + _textAttributes = textAttributes; + _rect = rect; + _callback = callback; + _textFlow = textFlow; + _paint = paint; + + if (paint == null) + { + _paint = new SKPaint() + { + Typeface = SkiaDelegatingFontService.Instance.GetTypeface(_textAttributes.FontName), + TextSize = _textAttributes.FontSize + }; + + _disposePaint = true; + } + + var metrics = _paint.FontMetrics; + _descent = metrics.Descent; + _lineHeight = _paint.FontSpacing; + } + + public void LayoutText() + { + if (string.IsNullOrEmpty(_value)) + return; + + var x = _rect.X; + var y = _rect.Y; + var width = _rect.Width; + var height = _rect.Height; + + x += _textAttributes.Margin; + y += _textAttributes.Margin; + width -= (_textAttributes.Margin * 2); + height -= (_textAttributes.Margin * 2); + + var top = y; + var bottom = y + height; + + if (_textAttributes.HorizontalAlignment == HorizontalAlignment.Right) + _paint.TextAlign = SKTextAlign.Right; + else if (_textAttributes.HorizontalAlignment == HorizontalAlignment.Center) + _paint.TextAlign = SKTextAlign.Center; + + var lines = CreateLines(y, bottom, width); + switch (_textAttributes.VerticalAlignment) + { + case VerticalAlignment.Center: + LayoutCenterAligned(lines, x, width, top, height); + break; + case VerticalAlignment.Bottom: + LayoutBottomAligned(lines, x, width, bottom, top); + break; + default: + LayoutTopAligned(lines, x, y, width); + break; + } + + _paint.TextAlign = SKTextAlign.Left; + } + + private void LayoutCenterAligned( + List lines, + float x, + float width, + float top, + float height) + { + var linesToDraw = lines.Count; + + if (_textFlow == TextFlow.ClipBounds) + { + var maxLines = Math.Floor(height / _lineHeight); + linesToDraw = (int) Math.Min(maxLines, lines.Count); + } + + // Figure out the vertical center of the rect + var y = top + height / 2; + + // Figure out the center index of the list, and the center point to start drawing from. + var startIndex = (lines.Count / 2); + if (linesToDraw % 2 == 0) + y -= _lineHeight / 2; + + // Figure out which index to draw first (of the range) and the point of the first line. + for (var i = 0; i < linesToDraw / 2; i++) + { + y -= _lineHeight; + startIndex--; + } + + y -= _descent; + + // Draw each line. + for (var i = 0; i < linesToDraw; i++) + { + y += _lineHeight; + var line = lines[i + startIndex]; + + var point = new PointF(x, y); + switch (_textAttributes.HorizontalAlignment) + { + case HorizontalAlignment.Center: + point.X = x + width / 2; + break; + case HorizontalAlignment.Right: + point.X = x + width; + break; + } + + _callback(point, _textAttributes, line.Value, 0, 0, 0); + } + } + + private void LayoutBottomAligned( + List lines, + float x, + float width, + float bottom, + float top) + { + var y = bottom - _descent; + + for (int i = lines.Count - 1; i >= 0; i--) + { + var line = lines[i]; + + if (_textFlow == TextFlow.ClipBounds && y - _lineHeight < top) + return; + + var point = new PointF(x, y); + switch (_textAttributes.HorizontalAlignment) + { + case HorizontalAlignment.Center: + point.X = x + width / 2; + break; + case HorizontalAlignment.Right: + point.X = x + width; + break; + } + + _callback(point, _textAttributes, line.Value, 0, 0, 0); + + y -= _lineHeight; + } + } + + private void LayoutTopAligned( + List lines, + float x, + float y, + float width) + { + y -= _descent; + + foreach (var line in lines) + { + y += _lineHeight; + + var point = new PointF(x, y); + switch (_textAttributes.HorizontalAlignment) + { + case HorizontalAlignment.Center: + point.X = x + width / 2; + break; + case HorizontalAlignment.Right: + point.X = x + width; + break; + } + + _callback(point, _textAttributes, line.Value, 0, 0, 0); + } + } + + private List CreateLines(float y, float bottom, float width) + { + var lines = new List(); + + var index = 0; + var length = _value.Length; + while (index < length) + { + y += _lineHeight; + + if (_textFlow == TextFlow.ClipBounds && _textAttributes.VerticalAlignment == VerticalAlignment.Top && y > bottom) + return lines; + + var count = (int) _paint.BreakText(_value.Substring(index), width, out var textWidth); + + var found = false; + if (WordWrap && index + count < length) + { + for (var i = index + count - 1; i >= index && !found; i--) + { + if (char.IsWhiteSpace(_value[i])) + { + count = i - index + 1; + found = true; + } + } + } + + var line = _value.Substring(index, count); + if (found) + textWidth = _paint.MeasureText(line); + lines.Add(new TextLine(line, textWidth)); + + index += count; + } + + return lines; + } + + public void Dispose() + { + if (_disposePaint) + _paint?.Dispose(); + } + } + + public class TextLine + { + public string Value { get; } + public float Width { get; } + + public TextLine( + string value, + float width) + { + Value = value; + Width = width; + } + } +} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/Views/SkiaGraphicsView.Tizen.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/Views/SkiaGraphicsView.Tizen.cs new file mode 100644 index 000000000000..43e5c97a88d4 --- /dev/null +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/Views/SkiaGraphicsView.Tizen.cs @@ -0,0 +1,45 @@ +using ElmSharp; +using SkiaSharp.Views.Tizen; +using Tizen.UIExtensions.ElmSharp; + +#nullable disable + +namespace Microsoft.Maui.Graphics.Skia.Views +{ + public class SkiaGraphicsView : SKCanvasView + { + private IDrawable _drawable; + private SkiaCanvas _canvas; + private ScalingCanvas _scalingCanvas; + + public SkiaGraphicsView(EvasObject parent, IDrawable drawable = null) : base(parent) + { + _canvas = new SkiaCanvas(); + _scalingCanvas = new ScalingCanvas(_canvas); + _scalingCanvas.Scale((float)DeviceInfo.ScalingFactor, (float)DeviceInfo.ScalingFactor); + Drawable = drawable; + PaintSurface += OnPaintSurface; + } + + public IDrawable Drawable + { + get => _drawable; + set + { + _drawable = value; + Invalidate(); + } + } + + protected virtual void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) + { + if (_drawable == null) return; + + var skiaCanvas = e.Surface.Canvas; + skiaCanvas.Clear(); + + _canvas.Canvas = skiaCanvas; + _drawable.Draw(_scalingCanvas, new RectangleF(0, 0, (float)GetSurfaceSize().Width.ToScaledDP(), (float)GetSurfaceSize().Height.ToScaledDP())); + } + } +} diff --git a/src/Core/src/Platform/Tizen/PageView.cs b/src/Core/src/Platform/Tizen/PageView.cs index 24ec2915c420..013f11775913 100644 --- a/src/Core/src/Platform/Tizen/PageView.cs +++ b/src/Core/src/Platform/Tizen/PageView.cs @@ -9,8 +9,5 @@ public class PageView : Page public PageView(ElmSharp.EvasObject parent) : base(parent) { } - - internal Func? CrossPlatformMeasure { get; set; } - internal Func? CrossPlatformArrange { get; set; } } } diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index bbd979f9adce..ec9870530b89 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -11,7 +11,13 @@ namespace Microsoft.Maui.Platform { - public partial class WrapperView : Canvas + + public interface IBackgroundCanvas + { + public SkiaGraphicsView BackgroundCanvas { get; } + } + + public partial class WrapperView : Canvas, IBackgroundCanvas { Lazy _drawableCanvas; Lazy _clipperView; From 3b770fa44d3ebd791621057818772019d4b1bd45 Mon Sep 17 00:00:00 2001 From: Jay Cho Date: Wed, 9 Jun 2021 17:30:42 +0900 Subject: [PATCH 006/266] Fix font and SingleProject to locate manifest --- .nuspec/Microsoft.Maui.Resizetizer.targets | 2 -- src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.nuspec/Microsoft.Maui.Resizetizer.targets b/.nuspec/Microsoft.Maui.Resizetizer.targets index e3d597213113..7a1d6686da6f 100644 --- a/.nuspec/Microsoft.Maui.Resizetizer.targets +++ b/.nuspec/Microsoft.Maui.Resizetizer.targets @@ -480,12 +480,10 @@ - $([System.IO.Path]::GetFileName(%(_MauiFontCopied.Identity))) $([System.IO.Path]::GetFileName(%(_MauiFontCopied.Identity))) - diff --git a/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs b/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs index 0559f47e702b..46172cf40cb5 100644 --- a/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs +++ b/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs @@ -13,6 +13,9 @@ public class TizenSplashUpdator : Task [Required] public ITaskItem[] MauiSplashScreen { get; set; } + [Required] + public string ManifestFile { get; set; } + [Required] public string IntermediateOutputPath { get; set; } @@ -108,7 +111,7 @@ public void UpdateColorAndMoveFile(string sourceFilePath, string destFilePath) public void UpdateManifest() { XmlDocument doc = new XmlDocument(); - var xmlPath = Environment.CurrentDirectory + "\\tizen-manifest.xml"; + var xmlPath = Path.Combine(Environment.CurrentDirectory, ManifestFile); try { doc.Load(xmlPath); From f5a7e3238a7d8f4ff34306249757da11c23299e4 Mon Sep 17 00:00:00 2001 From: Jay Cho Date: Mon, 14 Jun 2021 17:30:58 +0900 Subject: [PATCH 007/266] Update tizen manifest path --- .nuspec/Microsoft.Maui.Resizetizer.targets | 2 ++ src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.nuspec/Microsoft.Maui.Resizetizer.targets b/.nuspec/Microsoft.Maui.Resizetizer.targets index 7a1d6686da6f..e3d597213113 100644 --- a/.nuspec/Microsoft.Maui.Resizetizer.targets +++ b/.nuspec/Microsoft.Maui.Resizetizer.targets @@ -480,10 +480,12 @@ + $([System.IO.Path]::GetFileName(%(_MauiFontCopied.Identity))) $([System.IO.Path]::GetFileName(%(_MauiFontCopied.Identity))) + diff --git a/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs b/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs index 46172cf40cb5..f0ad58103327 100644 --- a/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs +++ b/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs @@ -13,12 +13,11 @@ public class TizenSplashUpdator : Task [Required] public ITaskItem[] MauiSplashScreen { get; set; } - [Required] - public string ManifestFile { get; set; } - [Required] public string IntermediateOutputPath { get; set; } + public string ManifestFile { get; set; } = "tizen-manifest.xml"; + public ILogger Logger { get; private set; } public override bool Execute() From 67ee593bcd1528b5cd4706d96502b507c88ee71c Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 17 Jun 2021 20:19:07 +0900 Subject: [PATCH 008/266] Bump to latest - Adds the GraphicsViewHandler and ShapeViewHandler - Apply one stop shop UseMauiControls (#1157) - Implements new APIs for each IView - and so on --- .../Core/src/Tizen/HandlerToRendererShim.cs | 1 + .../Handlers/Editor/EditorHandler.Tizen.cs | 5 ++ .../src/Handlers/Entry/EntryHandler.Tizen.cs | 47 +++++++++++++++++++ .../SearchBar/SearchBarHandler.Tizen.cs | 5 ++ .../src/Platform/Tizen/EntryExtensions.cs | 45 ++++++++++++++++++ .../src/Platform/Tizen/HandlerExtensions.cs | 11 ++++- src/Core/src/Platform/Tizen/PageView.cs | 13 ----- 7 files changed, 113 insertions(+), 14 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/PageView.cs diff --git a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs index d90ff96b622e..15ac51e58bd3 100644 --- a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs +++ b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Graphics; diff --git a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs index 3ffcb6365dac..6728f484bb47 100644 --- a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs +++ b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs @@ -113,6 +113,11 @@ public static void MapSelectionLength(IEditorHandler handler, ITextInput editor) handler.PlatformView?.UpdateSelectionLength(editor); } + public static void MapKeyboard(EditorHandler handler, IEditor editor) + { + handler.NativeView?.UpdateKeyboard(editor); + } + [MissingMapper] public static void MapCharacterSpacing(IEditorHandler handler, IEditor editor) { } diff --git a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs index 7de35a8909ce..cca13b0441e3 100644 --- a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs +++ b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs @@ -1,5 +1,6 @@ using System; using Tizen.UIExtensions.ElmSharp; +using SmartEvent = ElmSharp.SmartEvent; using EEntry = ElmSharp.Entry; namespace Microsoft.Maui.Handlers @@ -155,6 +156,21 @@ public static void MapKeyboard(EditorHandler handler, IEntry entry) handler.PlatformView?.UpdateKeyboard(entry); } + public static void MapSelectionLength(EntryHandler handler, IEntry entry) + { + handler.NativeView?.UpdateSelectionLength(entry); + } + + public static void MapCursorPosition(EntryHandler handler, IEntry entry) + { + handler.NativeView?.UpdateSelectionLength(entry); + } + + public static void MapKeyboard(EditorHandler handler, IEditor editor) + { + handler.NativeView?.UpdateKeyboard(editor); + } + [MissingMapper] public static void MapCharacterSpacing(IEntryHandler handler, IEntry entry) { } @@ -208,6 +224,37 @@ void OnSelectionCleared(object? sender, EventArgs e) } } + void OnCursorChanged(object? sender, EventArgs e) + { + if (VirtualView == null || NativeView == null) + return; + + var position = NativeView.CursorPosition; + + NativeView.GetSelectRegion(out int start, out int end); + + if (start > -1) + { + position = (start < end) ? start : end; + var selectionLength = Math.Abs(end - start); + VirtualView.SelectionLength = selectionLength; + } + + VirtualView.CursorPosition = position; + } + + void OnSelectionCleared(object sender, EventArgs e) + { + if (VirtualView == null || NativeView == null) + return; + + if (NativeView.IsFocused) + { + VirtualView.SelectionLength = 0; + VirtualView.CursorPosition = NativeView.CursorPosition; + } + } + void OnCompleted(object? sender, EventArgs e) { if (PlatformView == null) diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs index 50dfb7f23a35..514e50d84a36 100644 --- a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs @@ -120,6 +120,11 @@ public static void MapCancelButtonColor(ISearchBarHandler handler, ISearchBar se handler.PlatformView?.UpdateCancelButtonColor(searchBar); } + public static void MapCancelButtonColor(SearchBarHandler handler, ISearchBar searchBar) + { + handler.NativeView?.UpdateCancelButtonColor(searchBar); + } + [MissingMapper] public static void MapCharacterSpacing(ISearchBarHandler handler, ISearchBar searchBar) { } diff --git a/src/Core/src/Platform/Tizen/EntryExtensions.cs b/src/Core/src/Platform/Tizen/EntryExtensions.cs index 93f68f5d7438..dc8a2f1ed8ac 100644 --- a/src/Core/src/Platform/Tizen/EntryExtensions.cs +++ b/src/Core/src/Platform/Tizen/EntryExtensions.cs @@ -141,6 +141,51 @@ static int GetSelectionEnd(Entry platformEntry, ITextInput entry, int start) return end; } + /* Updates both the IEntry.CursorPosition and IEntry.SelectionLength properties. */ + [PortHandler] + public static void UpdateSelectionLength(this Entry nativeEntry, IEntry entry) + { + var start = GetSelectionStart(nativeEntry, entry); + var end = GetSelectionEnd(nativeEntry, entry, start); + var selectionLength = end - start; + + if (selectionLength != entry.SelectionLength) + entry.SelectionLength = selectionLength; + + if (selectionLength > 0) + { + nativeEntry.SetSelectionRegion(start, end); + } + else + { + nativeEntry.CursorPosition = entry.CursorPosition; + } + } + + static int GetSelectionStart(Entry nativeEntry, IEntry entry) + { + var start = entry.Text?.Length ?? 0; + var cursorPosition = entry.CursorPosition; + + if (entry.CursorPosition > 0) + start = Math.Min(start, cursorPosition); + + if (start != cursorPosition) + entry.CursorPosition = start; + + return start; + } + + static int GetSelectionEnd(Entry nativeEntry, IEntry entry, int start) + { + var end = start; + + if (entry.SelectionLength > 0) + end = Math.Min((start + entry.SelectionLength), entry.Text?.Length ?? 0); + + return end; + } + public static InputPanelReturnKeyType ToInputPanelReturnKeyType(this ReturnType returnType) { switch (returnType) diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index eb58125d4f4c..e55243bcb187 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -16,6 +16,12 @@ public static EvasObject ToNative(this IView view, IMauiContext context) var handler = view.Handler; + if (handler?.MauiContext != null && + handler.MauiContext != context) + { + handler = null; + } + if (handler == null) { handler = context.Handlers.GetHandler(view.GetType()); @@ -24,10 +30,13 @@ public static EvasObject ToNative(this IView view, IMauiContext context) throw new Exception($"Handler not found for view {view}"); handler.SetMauiContext(context); - handler.SetVirtualView(view); view.Handler = handler; } + if (handler.VirtualView != view) + handler.SetVirtualView(view); + + if (((INativeViewHandler)handler).NativeView is not EvasObject result) { throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); diff --git a/src/Core/src/Platform/Tizen/PageView.cs b/src/Core/src/Platform/Tizen/PageView.cs deleted file mode 100644 index 013f11775913..000000000000 --- a/src/Core/src/Platform/Tizen/PageView.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using Microsoft.Maui.Graphics; -using Tizen.UIExtensions.ElmSharp; - -namespace Microsoft.Maui -{ - public class PageView : Page - { - public PageView(ElmSharp.EvasObject parent) : base(parent) - { - } - } -} From 26b38856bb764e546fefb479856db28d23db6f9c Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 22 Jun 2021 06:49:16 +0900 Subject: [PATCH 009/266] Bump to latest - Apply to start adding in APIs for adding legacy renderers via assembly scanning (#1333) - Update to IMauiContext (#1357) - and so on --- .../Core/src/AppHostBuilderExtensions.cs | 1 + src/Core/src/IMauiContext.cs | 2 +- src/Core/src/Platform/MauiContext.Tizen.cs | 37 +++++++++++++++++++ src/Core/src/Platform/Tizen/MauiContext.cs | 32 ---------------- 4 files changed, 39 insertions(+), 33 deletions(-) create mode 100644 src/Core/src/Platform/MauiContext.Tizen.cs delete mode 100644 src/Core/src/Platform/Tizen/MauiContext.cs diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs index 74d3ef3b694d..b0aeb898259e 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs @@ -42,6 +42,7 @@ using DefaultRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.DefaultRenderer; using StreamImagesourceHandler = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.StreamImageSourceHandler; using ImageLoaderSourceHandler = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.UriImageSourceHandler; +using DefaultRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.DefaultRenderer; #endif namespace Microsoft.Maui.Controls.Compatibility.Hosting diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index 824a47332e78..11b1593bb241 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -11,7 +11,7 @@ public interface IMauiContext #if __ANDROID__ Android.Content.Context? Context { get; } #elif TIZEN - CoreUIAppContext Context { get; } + CoreUIAppContext? Context { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/Platform/MauiContext.Tizen.cs b/src/Core/src/Platform/MauiContext.Tizen.cs new file mode 100644 index 000000000000..3a0b26c4b7cc --- /dev/null +++ b/src/Core/src/Platform/MauiContext.Tizen.cs @@ -0,0 +1,37 @@ +using System; + +namespace Microsoft.Maui +{ + public partial class MauiContext + { + readonly WeakReference? _context; + + public MauiContext(CoreUIAppContext context) : this() + { + _context = new WeakReference(context ?? throw new ArgumentNullException(nameof(context))); + } + + public MauiContext(IServiceProvider services, CoreUIAppContext context) : this(services) + { + _context = new WeakReference(context ?? throw new ArgumentNullException(nameof(context))); + } + + public CoreUIAppContext? Context + { + get + { + if (_context == null) + return null; + + CoreUIAppContext? context; + if (_context.TryGetTarget(out context)) + { + return context; + } + + return null; + } + } + + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiContext.cs b/src/Core/src/Platform/Tizen/MauiContext.cs deleted file mode 100644 index 7b248d30ecb5..000000000000 --- a/src/Core/src/Platform/Tizen/MauiContext.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.Maui -{ - public class MauiContext : IMauiContext - { - readonly CoreUIAppContext _context; - readonly IServiceProvider? _services; - readonly IMauiHandlersServiceProvider? _mauiHandlersServiceProvider; - - public MauiContext(CoreUIAppContext context) - { - _context = context ?? throw new ArgumentNullException(nameof(context)); - } - - public MauiContext(IServiceProvider services, CoreUIAppContext context) - { - _services = services ?? throw new ArgumentNullException(nameof(services)); - _context = context ?? throw new ArgumentNullException(nameof(context)); - _mauiHandlersServiceProvider = Services.GetRequiredService(); - } - - public CoreUIAppContext Context => _context; - - public IServiceProvider Services => - _services ?? throw new InvalidOperationException($"No service provider was specified during construction."); - - public IMauiHandlersServiceProvider Handlers => - _mauiHandlersServiceProvider ?? throw new InvalidOperationException($"No service provider was specified during construction."); - } -} \ No newline at end of file From c71d8068d62cc51d471b518cc065dff24c218862 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 23 Jun 2021 16:28:14 +0900 Subject: [PATCH 010/266] Adds Microsoft.Maui.Tizen.sln --- Microsoft.Maui.Tizen.sln | 914 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 914 insertions(+) create mode 100644 Microsoft.Maui.Tizen.sln diff --git a/Microsoft.Maui.Tizen.sln b/Microsoft.Maui.Tizen.sln new file mode 100644 index 000000000000..4e8bf48e8000 --- /dev/null +++ b/Microsoft.Maui.Tizen.sln @@ -0,0 +1,914 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30503.244 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Controls", "Controls", "{9AD757F5-E57A-459D-A0A7-E0675E045B84}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compatibility", "Compatibility", "{29AC50BF-B4FB-450B-9386-0C5AD4B84226}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuspec", ".nuspec", "{7E12C50D-A570-4DF1-94E1-8599843FA87C}" + ProjectSection(SolutionItems) = preProject + eng\dogfood.ps1 = eng\dogfood.ps1 + .nuspec\Microsoft.Maui.Controls.Compatibility.AppLinks.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.AppLinks.nuspec + .nuspec\Microsoft.Maui.Controls.Compatibility.GTK.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.GTK.nuspec + .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.GTK.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.GTK.nuspec + .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.nuspec + .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.WPF.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.WPF.nuspec + .nuspec\Microsoft.Maui.Controls.Compatibility.Visual.Material.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.Visual.Material.nuspec + .nuspec\Microsoft.Maui.Controls.Compatibility.Visual.Material.targets = .nuspec\Microsoft.Maui.Controls.Compatibility.Visual.Material.targets + .nuspec\Microsoft.Maui.Controls.Compatibility.WPF.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.WPF.nuspec + .nuspec\Microsoft.Maui.Controls.Debug.targets = .nuspec\Microsoft.Maui.Controls.Debug.targets + .nuspec\Microsoft.Maui.Controls.DefaultItems.props = .nuspec\Microsoft.Maui.Controls.DefaultItems.props + .nuspec\Microsoft.Maui.Controls.DefaultItems.targets = .nuspec\Microsoft.Maui.Controls.DefaultItems.targets + .nuspec\Microsoft.Maui.Controls.DualScreen.nuspec = .nuspec\Microsoft.Maui.Controls.DualScreen.nuspec + .nuspec\Microsoft.Maui.Controls.MultiTargeting.targets = .nuspec\Microsoft.Maui.Controls.MultiTargeting.targets + .nuspec\Microsoft.Maui.Controls.nuspec = .nuspec\Microsoft.Maui.Controls.nuspec + .nuspec\Microsoft.Maui.Controls.props = .nuspec\Microsoft.Maui.Controls.props + .nuspec\Microsoft.Maui.Controls.SingleProject.props = .nuspec\Microsoft.Maui.Controls.SingleProject.props + .nuspec\Microsoft.Maui.Controls.SingleProject.targets = .nuspec\Microsoft.Maui.Controls.SingleProject.targets + .nuspec\Microsoft.Maui.Controls.targets = .nuspec\Microsoft.Maui.Controls.targets + .nuspec\Microsoft.Maui.Resizetizer.targets = .nuspec\Microsoft.Maui.Resizetizer.targets + eng\package.ps1 = eng\package.ps1 + .nuspec\proguard.cfg = .nuspec\proguard.cfg + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Core", "src\Controls\src\Core\Controls.Core.csproj", "{57B8B73D-C3B5-4C42-869E-7B2F17D354AC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{31721EFD-3238-462B-B501-41F3D2B50E92}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Controls", "Controls", "{97FA536A-675D-41C7-A90E-97E2F79D1AE2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{423C21C8-84CB-4A3C-BEB9-1C23D752D90F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\src\Core.csproj", "{29913989-0F70-48D8-8EDE-B1DD217F21D1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D5B986A3-7FC9-437E-8030-349AA4698DFD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{75A2CD30-BB85-4CA6-AC95-86A8A538A690}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Core.UnitTests", "src\Controls\tests\Core.UnitTests\Controls.Core.UnitTests.csproj", "{00259593-A283-47A5-ACB7-9C3819B16364}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Xaml", "src\Controls\src\Xaml\Controls.Xaml.csproj", "{BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Build.Tasks", "src\Controls\src\Build.Tasks\Controls.Build.Tasks.csproj", "{C328C538-B69F-43D2-80EE-3C1EB8254CBA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.UnitTests", "src\Core\tests\UnitTests\Core.UnitTests.csproj", "{7A753001-1C3D-404D-A421-2E052A545EAC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.DeviceTests", "src\Core\tests\DeviceTests\Core.DeviceTests.csproj", "{DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Essentials", "Essentials", "{DFD73007-5DB1-43AD-87A8-BD8622C2B192}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7E12E071-51C0-4668-9FF3-E2DE9DC51962}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials", "src\Essentials\src\Essentials.csproj", "{8CB95D25-8442-42BC-82BE-319D21138549}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.UnitTests", "src\Essentials\test\UnitTests\Essentials.UnitTests.csproj", "{2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials.DeviceTests.iOS", "src\Essentials\test\DeviceTests.iOS\Essentials.DeviceTests.iOS.csproj", "{B73EB308-70BE-49FD-91A7-1D1495663D6D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.DeviceTests.Shared", "src\Essentials\test\DeviceTests.Shared\Essentials.DeviceTests.Shared.csproj", "{81128D28-CFC8-4EA4-B68D-9939339C461A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5817A848-0B04-4035-9F7E-B8621B61CBDD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.Samples", "src\Essentials\samples\Samples\Essentials.Samples.csproj", "{2C69EB76-02C4-4921-96A1-4D70CB7CE744}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.Sample.Server.WebAuthenticator", "src\Essentials\samples\Sample.Server.WebAuthenticator\Essentials.Sample.Server.WebAuthenticator.csproj", "{0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Benchmarks", "src\Core\tests\Benchmarks\Core.Benchmarks.csproj", "{73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{806499EB-C2CC-4E85-BC19-613F3DE5E0C3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Sample", "src\Controls\samples\Controls.Sample\Controls.Sample.csproj", "{90B727DD-4C7B-4462-950F-61842A87DE8A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Maps", "src\Controls\Maps\src\Controls.Maps.csproj", "{F2379E0F-524F-47BC-877C-0428E4C836D4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Xaml.UnitTests", "src\Controls\tests\Xaml.UnitTests\Controls.Xaml.UnitTests.csproj", "{F905B72C-4DF7-408B-8B2B-50F9B8246A5E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestUtils", "TestUtils", "{0F9BA970-11B1-4ACA-AF41-1021AFC0F29C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils", "src\TestUtils\TestUtils\src\TestUtils.csproj", "{E4CB9988-7348-4D55-A08E-85907732F8DA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils.DeviceTests", "src\TestUtils\TestUtils.DeviceTests\src\TestUtils.DeviceTests.csproj", "{551B2209-4298-4D60-B55C-79077B8BC244}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resizetizer", "Resizetizer", "{4A3BAF64-E9D9-4036-9FDA-8B326C382667}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F83AC93C-9694-4A01-B9CB-7AA8E514B01F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{08F720FF-7530-43BF-A252-8946927669E3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resizetizer", "src\SingleProject\Resizetizer\src\Resizetizer.csproj", "{3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resizetizer.UnitTests", "src\SingleProject\Resizetizer\test\UnitTests\Resizetizer.UnitTests.csproj", "{BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SingleProject", "SingleProject", "{15878D2D-B0F1-4EE9-875D-4A643DB0C842}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.CustomAttributes", "src\Controls\tests\CustomAttributes\Controls.CustomAttributes.csproj", "{D816B818-F58F-4738-93AE-924EFAB7A07F}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Compatibility.ControlGallery.Issues.Shared", "src\Compatibility\ControlGallery\src\Issues.Shared\Compatibility.ControlGallery.Issues.Shared.shproj", "{AE2513CB-4E5E-4E5C-8237-88954D4C9433}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Compatibility.ControlGallery.Core", "src\Compatibility\ControlGallery\src\Core\Compatibility.ControlGallery.Core.csproj", "{B5F94CCB-5868-43BD-89B5-B66C97C3A741}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Compatibility", "src\Compatibility\Core\src\Compatibility.csproj", "{9FAA9654-80E6-4664-9702-47998A04E8FE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.SourceGen", "src\Controls\src\SourceGen\Controls.SourceGen.csproj", "{061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Sample.Tizen", "src\Controls\samples\Controls.Sample.Tizen\Controls.Sample.Tizen.csproj", "{4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}" +EndProject +Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + src\Compatibility\ControlGallery\src\Issues.Shared\Compatibility.ControlGallery.Issues.Shared.projitems*{ae2513cb-4e5e-4e5c-8237-88954d4c9433}*SharedItemsImports = 13 + src\Compatibility\ControlGallery\src\Issues.Shared\Compatibility.ControlGallery.Issues.Shared.projitems*{b5f94ccb-5868-43bd-89b5-b66c97c3a741}*SharedItemsImports = 5 + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|iPhone = Debug|iPhone + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|ARM.ActiveCfg = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|ARM.Build.0 = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|ARM64.Build.0 = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|iPhone.Build.0 = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|x64.ActiveCfg = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|x64.Build.0 = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|x86.ActiveCfg = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|x86.Build.0 = Debug|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|Any CPU.Build.0 = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|ARM.ActiveCfg = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|ARM.Build.0 = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|ARM64.ActiveCfg = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|ARM64.Build.0 = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|iPhone.ActiveCfg = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|iPhone.Build.0 = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|x64.ActiveCfg = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|x64.Build.0 = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|x86.ActiveCfg = Release|Any CPU + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|x86.Build.0 = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|ARM.ActiveCfg = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|ARM.Build.0 = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|ARM64.Build.0 = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|iPhone.Build.0 = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|x64.ActiveCfg = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|x64.Build.0 = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|x86.ActiveCfg = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|x86.Build.0 = Debug|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|Any CPU.Build.0 = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|ARM.ActiveCfg = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|ARM.Build.0 = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|ARM64.ActiveCfg = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|ARM64.Build.0 = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|iPhone.ActiveCfg = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|iPhone.Build.0 = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|x64.ActiveCfg = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|x64.Build.0 = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|x86.ActiveCfg = Release|Any CPU + {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|x86.Build.0 = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|ARM.ActiveCfg = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|ARM.Build.0 = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|ARM64.Build.0 = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|iPhone.Build.0 = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|x64.ActiveCfg = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|x64.Build.0 = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|x86.ActiveCfg = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|x86.Build.0 = Debug|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|Any CPU.Build.0 = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|ARM.ActiveCfg = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|ARM.Build.0 = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|ARM64.ActiveCfg = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|ARM64.Build.0 = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|iPhone.ActiveCfg = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|iPhone.Build.0 = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|x64.ActiveCfg = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|x64.Build.0 = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|x86.ActiveCfg = Release|Any CPU + {00259593-A283-47A5-ACB7-9C3819B16364}.Release|x86.Build.0 = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|ARM.ActiveCfg = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|ARM.Build.0 = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|ARM64.Build.0 = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|iPhone.Build.0 = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|x64.ActiveCfg = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|x64.Build.0 = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|x86.ActiveCfg = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|x86.Build.0 = Debug|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|Any CPU.Build.0 = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|ARM.ActiveCfg = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|ARM.Build.0 = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|ARM64.ActiveCfg = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|ARM64.Build.0 = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|iPhone.ActiveCfg = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|iPhone.Build.0 = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|x64.ActiveCfg = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|x64.Build.0 = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|x86.ActiveCfg = Release|Any CPU + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|x86.Build.0 = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|ARM.Build.0 = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|ARM64.Build.0 = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|iPhone.Build.0 = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|x64.ActiveCfg = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|x64.Build.0 = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|x86.ActiveCfg = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|x86.Build.0 = Debug|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|Any CPU.Build.0 = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|ARM.ActiveCfg = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|ARM.Build.0 = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|ARM64.ActiveCfg = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|ARM64.Build.0 = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|iPhone.ActiveCfg = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|iPhone.Build.0 = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|x64.ActiveCfg = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|x64.Build.0 = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|x86.ActiveCfg = Release|Any CPU + {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|x86.Build.0 = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|ARM.ActiveCfg = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|ARM.Build.0 = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|ARM64.Build.0 = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|iPhone.Build.0 = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|x64.ActiveCfg = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|x64.Build.0 = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|x86.ActiveCfg = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|x86.Build.0 = Debug|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|Any CPU.Build.0 = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|ARM.ActiveCfg = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|ARM.Build.0 = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|ARM64.ActiveCfg = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|ARM64.Build.0 = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|iPhone.ActiveCfg = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|iPhone.Build.0 = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|x64.ActiveCfg = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|x64.Build.0 = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|x86.ActiveCfg = Release|Any CPU + {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|x86.Build.0 = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|ARM.ActiveCfg = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|ARM.Build.0 = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|ARM64.Build.0 = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|iPhone.Build.0 = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|x64.ActiveCfg = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|x64.Build.0 = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|x86.ActiveCfg = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|x86.Build.0 = Debug|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|Any CPU.Build.0 = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|ARM.ActiveCfg = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|ARM.Build.0 = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|ARM64.ActiveCfg = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|ARM64.Build.0 = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|iPhone.ActiveCfg = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|iPhone.Build.0 = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|x64.ActiveCfg = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|x64.Build.0 = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|x86.ActiveCfg = Release|Any CPU + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|x86.Build.0 = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|ARM.ActiveCfg = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|ARM.Build.0 = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|ARM64.Build.0 = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|iPhone.Build.0 = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|x64.ActiveCfg = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|x64.Build.0 = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|x86.ActiveCfg = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|x86.Build.0 = Debug|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|Any CPU.Build.0 = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|ARM.ActiveCfg = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|ARM.Build.0 = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|ARM64.ActiveCfg = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|ARM64.Build.0 = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|iPhone.ActiveCfg = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|iPhone.Build.0 = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|x64.ActiveCfg = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|x64.Build.0 = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|x86.ActiveCfg = Release|Any CPU + {8CB95D25-8442-42BC-82BE-319D21138549}.Release|x86.Build.0 = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|ARM.ActiveCfg = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|ARM.Build.0 = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|ARM64.Build.0 = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|iPhone.Build.0 = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|x64.ActiveCfg = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|x64.Build.0 = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|x86.ActiveCfg = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|x86.Build.0 = Debug|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|Any CPU.Build.0 = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|ARM.ActiveCfg = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|ARM.Build.0 = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|ARM64.ActiveCfg = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|ARM64.Build.0 = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|iPhone.ActiveCfg = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|iPhone.Build.0 = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x64.ActiveCfg = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x64.Build.0 = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x86.ActiveCfg = Release|Any CPU + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x86.Build.0 = Release|Any CPU + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|ARM.ActiveCfg = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|ARM64.ActiveCfg = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhone.ActiveCfg = Debug|iPhone + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhone.Build.0 = Debug|iPhone + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhone.Deploy.0 = Debug|iPhone + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|x64.ActiveCfg = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|x64.Build.0 = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|x64.Deploy.0 = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|ARM.ActiveCfg = Release|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|ARM64.ActiveCfg = Release|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|iPhone.ActiveCfg = Release|iPhone + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|iPhone.Build.0 = Release|iPhone + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|x64.ActiveCfg = Release|iPhoneSimulator + {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|x86.ActiveCfg = Release|iPhoneSimulator + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|ARM.Build.0 = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|ARM64.Build.0 = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|iPhone.Build.0 = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|x64.ActiveCfg = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|x64.Build.0 = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|x86.ActiveCfg = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|x86.Build.0 = Debug|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|Any CPU.Build.0 = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|ARM.ActiveCfg = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|ARM.Build.0 = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|ARM64.ActiveCfg = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|ARM64.Build.0 = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|iPhone.ActiveCfg = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|iPhone.Build.0 = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|x64.ActiveCfg = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|x64.Build.0 = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|x86.ActiveCfg = Release|Any CPU + {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|x86.Build.0 = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|ARM.ActiveCfg = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|ARM.Build.0 = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|ARM64.Build.0 = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|iPhone.Build.0 = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|x64.ActiveCfg = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|x64.Build.0 = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|x86.ActiveCfg = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|x86.Build.0 = Debug|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|Any CPU.Build.0 = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|ARM.ActiveCfg = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|ARM.Build.0 = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|ARM64.ActiveCfg = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|ARM64.Build.0 = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|iPhone.ActiveCfg = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|iPhone.Build.0 = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|x64.ActiveCfg = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|x64.Build.0 = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|x86.ActiveCfg = Release|Any CPU + {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|x86.Build.0 = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|ARM.Build.0 = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|ARM64.Build.0 = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|iPhone.Build.0 = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|x64.ActiveCfg = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|x64.Build.0 = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|x86.ActiveCfg = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|x86.Build.0 = Debug|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|Any CPU.Build.0 = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|ARM.ActiveCfg = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|ARM.Build.0 = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|ARM64.ActiveCfg = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|ARM64.Build.0 = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|iPhone.ActiveCfg = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|iPhone.Build.0 = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x64.ActiveCfg = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x64.Build.0 = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x86.ActiveCfg = Release|Any CPU + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x86.Build.0 = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|ARM.ActiveCfg = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|ARM.Build.0 = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|ARM64.Build.0 = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|iPhone.Build.0 = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|x64.ActiveCfg = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|x64.Build.0 = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|x86.ActiveCfg = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|x86.Build.0 = Debug|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|Any CPU.Build.0 = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|ARM.ActiveCfg = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|ARM.Build.0 = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|ARM64.ActiveCfg = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|ARM64.Build.0 = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|iPhone.ActiveCfg = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|iPhone.Build.0 = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|x64.ActiveCfg = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|x64.Build.0 = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|x86.ActiveCfg = Release|Any CPU + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|x86.Build.0 = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|ARM.Build.0 = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|ARM64.Build.0 = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|iPhone.Build.0 = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|x64.ActiveCfg = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|x64.Build.0 = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|x86.ActiveCfg = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|x86.Build.0 = Debug|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|Any CPU.Build.0 = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|ARM.ActiveCfg = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|ARM.Build.0 = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|ARM64.ActiveCfg = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|ARM64.Build.0 = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|iPhone.ActiveCfg = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|iPhone.Build.0 = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|x64.ActiveCfg = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|x64.Build.0 = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|x86.ActiveCfg = Release|Any CPU + {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|x86.Build.0 = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|ARM.Build.0 = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|ARM64.Build.0 = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|iPhone.Build.0 = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|x64.ActiveCfg = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|x64.Build.0 = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|x86.ActiveCfg = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|x86.Build.0 = Debug|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|Any CPU.Build.0 = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|ARM.ActiveCfg = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|ARM.Build.0 = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|ARM64.ActiveCfg = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|ARM64.Build.0 = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|iPhone.ActiveCfg = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|iPhone.Build.0 = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|x64.ActiveCfg = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|x64.Build.0 = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|x86.ActiveCfg = Release|Any CPU + {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|x86.Build.0 = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|ARM.Build.0 = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|ARM64.Build.0 = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|iPhone.Build.0 = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|x64.ActiveCfg = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|x64.Build.0 = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|x86.ActiveCfg = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|x86.Build.0 = Debug|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|Any CPU.Build.0 = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|ARM.ActiveCfg = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|ARM.Build.0 = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|ARM64.ActiveCfg = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|ARM64.Build.0 = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|iPhone.ActiveCfg = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|iPhone.Build.0 = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|x64.ActiveCfg = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|x64.Build.0 = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|x86.ActiveCfg = Release|Any CPU + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|x86.Build.0 = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|ARM.Build.0 = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|ARM64.Build.0 = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|iPhone.Build.0 = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|x64.ActiveCfg = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|x64.Build.0 = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|x86.ActiveCfg = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|x86.Build.0 = Debug|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|Any CPU.Build.0 = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|ARM.ActiveCfg = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|ARM.Build.0 = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|ARM64.ActiveCfg = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|ARM64.Build.0 = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|iPhone.ActiveCfg = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|iPhone.Build.0 = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|x64.ActiveCfg = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|x64.Build.0 = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|x86.ActiveCfg = Release|Any CPU + {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|x86.Build.0 = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|Any CPU.Build.0 = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|ARM.ActiveCfg = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|ARM.Build.0 = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|ARM64.Build.0 = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|iPhone.Build.0 = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|x64.ActiveCfg = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|x64.Build.0 = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|x86.ActiveCfg = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|x86.Build.0 = Debug|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|Any CPU.ActiveCfg = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|Any CPU.Build.0 = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|ARM.ActiveCfg = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|ARM.Build.0 = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|ARM64.ActiveCfg = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|ARM64.Build.0 = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|iPhone.ActiveCfg = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|iPhone.Build.0 = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|x64.ActiveCfg = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|x64.Build.0 = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|x86.ActiveCfg = Release|Any CPU + {551B2209-4298-4D60-B55C-79077B8BC244}.Release|x86.Build.0 = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|ARM.Build.0 = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|ARM64.Build.0 = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|iPhone.Build.0 = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|x64.ActiveCfg = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|x64.Build.0 = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|x86.ActiveCfg = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|x86.Build.0 = Debug|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|Any CPU.Build.0 = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|ARM.ActiveCfg = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|ARM.Build.0 = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|ARM64.ActiveCfg = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|ARM64.Build.0 = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|iPhone.ActiveCfg = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|iPhone.Build.0 = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|x64.ActiveCfg = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|x64.Build.0 = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|x86.ActiveCfg = Release|Any CPU + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|x86.Build.0 = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|ARM.ActiveCfg = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|ARM.Build.0 = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|ARM64.Build.0 = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|iPhone.Build.0 = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|x64.ActiveCfg = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|x64.Build.0 = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|x86.ActiveCfg = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|x86.Build.0 = Debug|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|Any CPU.Build.0 = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|ARM.ActiveCfg = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|ARM.Build.0 = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|ARM64.ActiveCfg = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|ARM64.Build.0 = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|iPhone.ActiveCfg = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|iPhone.Build.0 = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|x64.ActiveCfg = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|x64.Build.0 = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|x86.ActiveCfg = Release|Any CPU + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|x86.Build.0 = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|ARM.ActiveCfg = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|ARM.Build.0 = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|ARM64.Build.0 = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|iPhone.Build.0 = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|x64.ActiveCfg = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|x64.Build.0 = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|x86.ActiveCfg = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|x86.Build.0 = Debug|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|Any CPU.Build.0 = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|ARM.ActiveCfg = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|ARM.Build.0 = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|ARM64.ActiveCfg = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|ARM64.Build.0 = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|iPhone.ActiveCfg = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|iPhone.Build.0 = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|x64.ActiveCfg = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|x64.Build.0 = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|x86.ActiveCfg = Release|Any CPU + {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|x86.Build.0 = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|ARM.ActiveCfg = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|ARM.Build.0 = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|ARM64.Build.0 = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|iPhone.Build.0 = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|x64.ActiveCfg = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|x64.Build.0 = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|x86.ActiveCfg = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|x86.Build.0 = Debug|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|Any CPU.Build.0 = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|ARM.ActiveCfg = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|ARM.Build.0 = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|ARM64.ActiveCfg = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|ARM64.Build.0 = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|iPhone.ActiveCfg = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|iPhone.Build.0 = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|x64.ActiveCfg = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|x64.Build.0 = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|x86.ActiveCfg = Release|Any CPU + {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|x86.Build.0 = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|ARM.ActiveCfg = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|ARM.Build.0 = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|ARM64.Build.0 = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|iPhone.Build.0 = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|x64.ActiveCfg = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|x64.Build.0 = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|x86.ActiveCfg = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|x86.Build.0 = Debug|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|Any CPU.Build.0 = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|ARM.ActiveCfg = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|ARM.Build.0 = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|ARM64.ActiveCfg = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|ARM64.Build.0 = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|iPhone.ActiveCfg = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|iPhone.Build.0 = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|x64.ActiveCfg = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|x64.Build.0 = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|x86.ActiveCfg = Release|Any CPU + {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|x86.Build.0 = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|ARM.ActiveCfg = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|ARM.Build.0 = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|ARM64.Build.0 = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|iPhone.Build.0 = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|x64.ActiveCfg = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|x64.Build.0 = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|x86.ActiveCfg = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|x86.Build.0 = Debug|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|Any CPU.Build.0 = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|ARM.ActiveCfg = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|ARM.Build.0 = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|ARM64.ActiveCfg = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|ARM64.Build.0 = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|iPhone.ActiveCfg = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|iPhone.Build.0 = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|x64.ActiveCfg = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|x64.Build.0 = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|x86.ActiveCfg = Release|Any CPU + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|x86.Build.0 = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|ARM.ActiveCfg = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|ARM.Build.0 = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|ARM64.Build.0 = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|iPhone.Build.0 = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|x64.ActiveCfg = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|x64.Build.0 = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|x86.ActiveCfg = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|x86.Build.0 = Debug|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|Any CPU.Build.0 = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|ARM.ActiveCfg = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|ARM.Build.0 = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|ARM64.ActiveCfg = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|ARM64.Build.0 = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|iPhone.ActiveCfg = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|iPhone.Build.0 = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x64.ActiveCfg = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x64.Build.0 = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x86.ActiveCfg = Release|Any CPU + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9AD757F5-E57A-459D-A0A7-E0675E045B84} = {97FA536A-675D-41C7-A90E-97E2F79D1AE2} + {29AC50BF-B4FB-450B-9386-0C5AD4B84226} = {97FA536A-675D-41C7-A90E-97E2F79D1AE2} + {57B8B73D-C3B5-4C42-869E-7B2F17D354AC} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} + {423C21C8-84CB-4A3C-BEB9-1C23D752D90F} = {31721EFD-3238-462B-B501-41F3D2B50E92} + {2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA} = {31721EFD-3238-462B-B501-41F3D2B50E92} + {29913989-0F70-48D8-8EDE-B1DD217F21D1} = {423C21C8-84CB-4A3C-BEB9-1C23D752D90F} + {D5B986A3-7FC9-437E-8030-349AA4698DFD} = {9AD757F5-E57A-459D-A0A7-E0675E045B84} + {75A2CD30-BB85-4CA6-AC95-86A8A538A690} = {9AD757F5-E57A-459D-A0A7-E0675E045B84} + {00259593-A283-47A5-ACB7-9C3819B16364} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} + {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} + {C328C538-B69F-43D2-80EE-3C1EB8254CBA} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} + {7A753001-1C3D-404D-A421-2E052A545EAC} = {2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA} + {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6} = {2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA} + {7E12E071-51C0-4668-9FF3-E2DE9DC51962} = {DFD73007-5DB1-43AD-87A8-BD8622C2B192} + {8CB95D25-8442-42BC-82BE-319D21138549} = {7E12E071-51C0-4668-9FF3-E2DE9DC51962} + {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} = {DFD73007-5DB1-43AD-87A8-BD8622C2B192} + {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886} = {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} + {B73EB308-70BE-49FD-91A7-1D1495663D6D} = {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} + {81128D28-CFC8-4EA4-B68D-9939339C461A} = {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} + {5817A848-0B04-4035-9F7E-B8621B61CBDD} = {DFD73007-5DB1-43AD-87A8-BD8622C2B192} + {2C69EB76-02C4-4921-96A1-4D70CB7CE744} = {5817A848-0B04-4035-9F7E-B8621B61CBDD} + {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C} = {5817A848-0B04-4035-9F7E-B8621B61CBDD} + {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424} = {2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA} + {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} = {9AD757F5-E57A-459D-A0A7-E0675E045B84} + {90B727DD-4C7B-4462-950F-61842A87DE8A} = {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} + {F2379E0F-524F-47BC-877C-0428E4C836D4} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} + {F905B72C-4DF7-408B-8B2B-50F9B8246A5E} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} + {E4CB9988-7348-4D55-A08E-85907732F8DA} = {0F9BA970-11B1-4ACA-AF41-1021AFC0F29C} + {551B2209-4298-4D60-B55C-79077B8BC244} = {0F9BA970-11B1-4ACA-AF41-1021AFC0F29C} + {4A3BAF64-E9D9-4036-9FDA-8B326C382667} = {15878D2D-B0F1-4EE9-875D-4A643DB0C842} + {F83AC93C-9694-4A01-B9CB-7AA8E514B01F} = {4A3BAF64-E9D9-4036-9FDA-8B326C382667} + {08F720FF-7530-43BF-A252-8946927669E3} = {4A3BAF64-E9D9-4036-9FDA-8B326C382667} + {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C} = {08F720FF-7530-43BF-A252-8946927669E3} + {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5} = {F83AC93C-9694-4A01-B9CB-7AA8E514B01F} + {D816B818-F58F-4738-93AE-924EFAB7A07F} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} + {AE2513CB-4E5E-4E5C-8237-88954D4C9433} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} + {B5F94CCB-5868-43BD-89B5-B66C97C3A741} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} + {9FAA9654-80E6-4664-9702-47998A04E8FE} = {29AC50BF-B4FB-450B-9386-0C5AD4B84226} + {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} + {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6} = {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {650AE971-2F29-46A8-822C-FB4FCDC6A9A0} + EndGlobalSection +EndGlobal From 9a026424a3a23f366f164fe99d974a58bc61440f Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 24 Jun 2021 10:56:50 +0900 Subject: [PATCH 011/266] InitialzationOption for MauiApp --- src/Controls/samples/Controls.Sample/MauiProgram.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Controls/samples/Controls.Sample/MauiProgram.cs b/src/Controls/samples/Controls.Sample/MauiProgram.cs index f759d00e285e..1a681c14a4b3 100644 --- a/src/Controls/samples/Controls.Sample/MauiProgram.cs +++ b/src/Controls/samples/Controls.Sample/MauiProgram.cs @@ -113,6 +113,17 @@ public static MauiApp CreateMauiApp() logging.AddConsole(); #endif }); +#if TIZEN + services.AddTransient((_) => + { + var option = new InitializationOptions + { + DisplayResolutionUnit = DisplayResolutionUnit.DP(true), + UseSkiaSharp = true + }; + return option; + }); +#endif services.AddSingleton(); services.AddTransient(); From 9c27d5d3366e744bf87e91efb9ed5832ef9d2855 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 29 Jun 2021 10:22:31 +0900 Subject: [PATCH 012/266] Bump to latest - Apply to patch related to Animation (#1436) - Apply to register Microsoft.Maui.Graphics Platforms (#1441) - and so on. --- .../ModalNavigationService.Tizen.cs | 22 ++++++++++ src/Core/src/Animations/NativeTicker.Tizen.cs | 42 +++++++++++++++++++ .../src/Platform/Tizen/MauiApplication.cs | 5 ++- .../SkiaGraphicsService.cs | 5 +++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs create mode 100644 src/Core/src/Animations/NativeTicker.Tizen.cs diff --git a/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs b/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs new file mode 100644 index 000000000000..f9800c51b6d9 --- /dev/null +++ b/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs @@ -0,0 +1,22 @@ +#nullable enable + +using System; +using System.Threading.Tasks; + +namespace Microsoft.Maui.Controls.Platform +{ + internal partial class ModalNavigationService + { + public Task PopModalAsync(bool animated) + { + // TODO: Need to implementation + throw new NotImplementedException(); + } + + public Task PushModalAsync(Page modal, bool animated) + { + // TODO: Need to implementation + throw new NotImplementedException(); + } + } +} diff --git a/src/Core/src/Animations/NativeTicker.Tizen.cs b/src/Core/src/Animations/NativeTicker.Tizen.cs new file mode 100644 index 000000000000..6d7fc0495fae --- /dev/null +++ b/src/Core/src/Animations/NativeTicker.Tizen.cs @@ -0,0 +1,42 @@ +using System.Threading; +using Tizen.Applications; + +namespace Microsoft.Maui.Animations +{ + public class NativeTicker : Ticker + { + readonly Timer _timer; + readonly SynchronizationContext? _context; + bool _isRunning; + + public override bool IsRunning => _isRunning; + + public NativeTicker() + { + if (SynchronizationContext.Current == null) + { + TizenSynchronizationContext.Initialize(); + } + + _context = SynchronizationContext.Current; + _timer = new Timer((object o) => HandleElapsed(o), this, Timeout.Infinite, Timeout.Infinite); + } + + public override void Start() + { + _timer.Change(16, 16); + _isRunning = true; + } + + public override void Stop() + { + _timer.Change(-1, -1); + _isRunning = false; + } + + void HandleElapsed(object state) + { + _context?.Post((o) => Fire?.Invoke(), null); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index 91dea59856e7..74acecfe7aa5 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -38,7 +38,10 @@ protected override void OnPreCreate() Services = _applicationContext.Services; - Current.Services?.InvokeLifecycleEvents(del => del(this)); + if (Services == null) + throw new InvalidOperationException($"The {nameof(IServiceProvider)} instance was not found."); + + Current.Services.InvokeLifecycleEvents(del => del(this)); } protected override void OnCreate() diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs index 9ae7a864ac45..a1f7b6644cb8 100644 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs +++ b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs @@ -90,5 +90,10 @@ public BitmapExportContext CreateBitmapExportContext(int width, int height, floa { return new SkiaBitmapExportContext(width, height, displayScale, 72, false); } + + public RectangleF GetPathBounds(PathF path) + { + return path.GetBoundsByFlattening(); + } } } From 098d95e21418388f5072e9b0e11e50c0377d6b19 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 29 Jun 2021 17:06:00 +0900 Subject: [PATCH 013/266] Enable to DisplayResolutionUnit --- .../Controls/BordelessEntry/BordelessEntryHandler.cs | 5 +++++ src/Controls/samples/Controls.Sample/MauiProgram.cs | 2 +- src/Core/src/Platform/Tizen/CoreUIAppContext.cs | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs index 6cf29c51de81..2c2b66abf197 100644 --- a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs +++ b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs @@ -41,6 +41,11 @@ public static void MapBorder(BordelessEntryHandler handler, BordelessEntry borde #else public static void MapBorder(BordelessEntryHandler handler, BordelessEntry borderlessEntry) { + } +#elif TIZEN + public static void MapBorder(BordelessEntryHandler handler, BordelessEntry borderlessEntry) + { + } #endif } diff --git a/src/Controls/samples/Controls.Sample/MauiProgram.cs b/src/Controls/samples/Controls.Sample/MauiProgram.cs index 1a681c14a4b3..65ebde44cfd5 100644 --- a/src/Controls/samples/Controls.Sample/MauiProgram.cs +++ b/src/Controls/samples/Controls.Sample/MauiProgram.cs @@ -107,7 +107,7 @@ public static MauiApp CreateMauiApp() services.AddLogging(logging => { -#if WINDOWS +#if WINDOWS || TIZEN logging.AddDebug(); #else logging.AddConsole(); diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index f321eeaf1dcc..d035a45ff363 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -23,6 +23,7 @@ public static CoreUIAppContext GetInstance(CoreApplication application, Window? if (IsInitialized) return _instance!; + _instance = (window == null) ? new CoreUIAppContext(application) : new CoreUIAppContext(application, window); return _instance; } @@ -154,6 +155,7 @@ void InitializeMainWindow() // TODO : should update later }; + // TODO : Fix Backbutton later MainWindow.BackButtonPressed += (sender, e) => CurrentApplication.Exit(); } } From 83584fa507e63c6bcd5275408a9fdc0d5fdd9e80 Mon Sep 17 00:00:00 2001 From: Seungkeun Lee Date: Tue, 29 Jun 2021 19:15:48 +0900 Subject: [PATCH 014/266] Implement Clip --- .../Controls.Sample.Tizen/res/crimson.jpg | Bin 0 -> 79109 bytes .../Controls.Sample.Tizen/res/dotnet_bot.png | Bin 0 -> 114419 bytes .../src/Handlers/Image/ImageHandler.Tizen.cs | 1 - src/Core/src/Platform/Tizen/WrapperView.cs | 55 ++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/Controls/samples/Controls.Sample.Tizen/res/crimson.jpg create mode 100644 src/Controls/samples/Controls.Sample.Tizen/res/dotnet_bot.png diff --git a/src/Controls/samples/Controls.Sample.Tizen/res/crimson.jpg b/src/Controls/samples/Controls.Sample.Tizen/res/crimson.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3db7bb21380210276a4d3dae7e30a46e58b3339b GIT binary patch literal 79109 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 OK~q&uWL1qA8tR$@u%{$~CC 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 + /// A clipper area drawing view, it used for clipping + /// + public class SKClipperView : SKCanvasView + { + ///

+ /// Initializes a new instance of the class. + /// + /// Parent of this instance. + public SKClipperView(EvasObject parent) : base(parent) { } + + public bool ClippingRequired { get; set; } + + /// + /// Invalidate clipping area + /// + public new void Invalidate() + { + ClippingRequired = true; + OnDrawFrame(); + ClippingRequired = false; + } + } + + public static class ClipperExtension + { + /// + /// Set Clipper canvas + /// + /// A target view to clip + /// A clip area + public static void SetClipperCanvas(this EvasObject target, SKClipperView clipper) + { + if (target != null && clipper.ClippingRequired) + { + var realHandle = elm_object_part_content_get(clipper, "elm.swallow.content"); + + target.SetClip(null); // To restore original image + evas_object_clip_set(target, realHandle); + } + } + + [DllImport("libevas.so.1")] + internal static extern void evas_object_clip_set(IntPtr obj, IntPtr clip); + + [DllImport("libelementary.so.1")] + internal static extern IntPtr elm_object_part_content_get(IntPtr obj, string part); + } } From f6a54b24474494f7afc248fc60bde42592395fd4 Mon Sep 17 00:00:00 2001 From: Seungkeun Lee Date: Wed, 30 Jun 2021 16:11:31 +0900 Subject: [PATCH 015/266] Implement ModalNavigationService --- .../ModalNavigationService.Tizen.cs | 45 ++++++++++++++++--- .../src/Platform/Tizen/CoreUIAppContext.cs | 38 ++++++++++++++-- 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs b/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs index f9800c51b6d9..c02e54e0f0ea 100644 --- a/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs +++ b/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs @@ -1,22 +1,57 @@ #nullable enable -using System; using System.Threading.Tasks; namespace Microsoft.Maui.Controls.Platform { internal partial class ModalNavigationService { + ModalStack _modalStack => MauiContext.Context!.ModalStack; + IPageController CurrentPageController => _navModel.CurrentPage; + + partial void OnPageAttachedHandler() + { + MauiContext.Context!.SetBackButtonPressedHandler(OnBackButtonPressed); + } + public Task PopModalAsync(bool animated) { - // TODO: Need to implementation - throw new NotImplementedException(); + Page modal = _navModel.PopModal(); + ((IPageController)modal).SendDisappearing(); + var source = new TaskCompletionSource(); + + var modalRenderer = modal.Handler as INativeViewHandler; + if (modalRenderer != null) + { + // TODO. Need to implement animated + _modalStack.Pop(); + source.TrySetResult(modal); + CurrentPageController?.SendAppearing(); + } + return source.Task; } public Task PushModalAsync(Page modal, bool animated) { - // TODO: Need to implementation - throw new NotImplementedException(); + CurrentPageController?.SendDisappearing(); + _navModel.PushModal(modal); + + var nativeView = modal.ToNative(MauiContext); + _modalStack.Push(nativeView); + + // Verify that the modal is still on the stack + if (_navModel.CurrentPage == modal) + ((IPageController)modal).SendAppearing(); + + return Task.CompletedTask; + } + + bool OnBackButtonPressed() + { + Page root = _navModel.LastRoot; + bool handled = root?.SendBackButtonPressed() ?? false; + + return handled; } } } diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index d035a45ff363..bd886466e733 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -16,6 +16,8 @@ public class CoreUIAppContext static CoreUIAppContext? _instance = null; + Func? _handleBackButtonPressed; + public static bool IsInitialized { get; private set; } public static CoreUIAppContext GetInstance(CoreApplication application, Window? window = null) @@ -38,6 +40,8 @@ public static CoreUIAppContext GetInstance(CoreApplication application, Window? public ELayout BaseLayout { get; set; } + public ModalStack ModalStack { get; private set; } + public CircleSurface? BaseCircleSurface { get; set; } public DeviceType DeviceType => DeviceInfo.GetDeviceType(); @@ -58,7 +62,8 @@ public double ViewportWidth set { _viewPortWidth = value; - ViewportWidth = _viewPortWidth; + // TODO. DeviceInfo.ViewportWidth is readonly, fix it + //ViewportWidth = _viewPortWidth; } } @@ -88,6 +93,16 @@ protected CoreUIAppContext(CoreApplication application, Window window) Environment.SetEnvironmentVariable("XDG_DATA_HOME", CurrentApplication.DirectoryInfo.Data); } + ModalStack = new ModalStack(NativeParent) + { + AlignmentX = -1, + AlignmentY = -1, + WeightX = 1, + WeightY= 1, + }; + ModalStack.Show(); + BaseLayout.SetContent(ModalStack); + IsInitialized = true; } @@ -96,7 +111,12 @@ public void SetContent(EvasObject content) content.SetAlignment(-1, -1); content.SetWeight(1, 1); content.Show(); - BaseLayout.SetContent(content); + ModalStack.Push(content); + } + + public void SetBackButtonPressedHandler(Func handler) + { + _handleBackButtonPressed = handler; } static Window CreateDefaultWindow() @@ -155,8 +175,18 @@ void InitializeMainWindow() // TODO : should update later }; - // TODO : Fix Backbutton later - MainWindow.BackButtonPressed += (sender, e) => CurrentApplication.Exit(); + MainWindow.BackButtonPressed += OnBackButtonPressed; + + + + } + + void OnBackButtonPressed(object sender, EventArgs e) + { + if (!(_handleBackButtonPressed?.Invoke() ?? false)) + { + CurrentApplication.Exit(); + } } } } From 2e74581e165e51430f83e40de9af9364e7100ff0 Mon Sep 17 00:00:00 2001 From: Jay Cho Date: Thu, 1 Jul 2021 10:20:55 +0900 Subject: [PATCH 016/266] Update build targets for single project --- .nuspec/Microsoft.Maui.Controls.MultiTargeting.targets | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets index cb2665ca33ea..d93d10790ec0 100644 --- a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets +++ b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets @@ -30,10 +30,8 @@
- - - - + + From 654ed22f493a26c832a97d237bab900ec78756e3 Mon Sep 17 00:00:00 2001 From: Seungkeun Lee Date: Thu, 1 Jul 2021 10:45:25 +0900 Subject: [PATCH 017/266] Remove comment --- src/Core/src/Platform/Tizen/WrapperView.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index 4586d0fba07f..efb0664f346c 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -11,7 +11,6 @@ namespace Microsoft.Maui.Platform { - public interface IBackgroundCanvas { public SkiaGraphicsView BackgroundCanvas { get; } @@ -320,22 +319,12 @@ public static void SetClipperCanvas(this EvasObject target, SKClipperView clippe internal static extern IntPtr elm_object_part_content_get(IntPtr obj, string part); } - /// - /// A clipper area drawing view, it used for clipping - /// public class SKClipperView : SKCanvasView { - /// - /// Initializes a new instance of the class. - /// - /// Parent of this instance. public SKClipperView(EvasObject parent) : base(parent) { } public bool ClippingRequired { get; set; } - /// - /// Invalidate clipping area - /// public new void Invalidate() { ClippingRequired = true; @@ -346,11 +335,6 @@ public SKClipperView(EvasObject parent) : base(parent) { } public static class ClipperExtension { - /// - /// Set Clipper canvas - /// - /// A target view to clip - /// A clip area public static void SetClipperCanvas(this EvasObject target, SKClipperView clipper) { if (target != null && clipper.ClippingRequired) From 634a7ea152051587b82e319468c1417045572827 Mon Sep 17 00:00:00 2001 From: Seungkeun Lee Date: Thu, 1 Jul 2021 11:01:40 +0900 Subject: [PATCH 018/266] Remove image resource on Tizen project --- .../Controls.Sample.Tizen/res/crimson.jpg | Bin 79109 -> 0 bytes .../Controls.Sample.Tizen/res/dotnet_bot.png | Bin 114419 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/Controls/samples/Controls.Sample.Tizen/res/crimson.jpg delete mode 100644 src/Controls/samples/Controls.Sample.Tizen/res/dotnet_bot.png diff --git a/src/Controls/samples/Controls.Sample.Tizen/res/crimson.jpg b/src/Controls/samples/Controls.Sample.Tizen/res/crimson.jpg deleted file mode 100644 index 3db7bb21380210276a4d3dae7e30a46e58b3339b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79109 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 + /// The native widget that is configured with an header and an list of items to be used in NavigationDrawer. + /// + public class NavigationView : Background, INavigationView + { + static readonly EColor s_defaultBackgroundColor = ElmSharp.ThemeConstants.Shell.ColorClass.DefaultNavigationViewBackgroundColor; + + EBox _mainLayout; + + EvasObject _header; + EvasObject _footer; + EvasObject _content; + + EvasObject _backgroundImage; + EColor _backgroundColor; + + /// + /// Initializes a new instance of the class. + /// + /// Parent evas object. + public NavigationView(EvasObject parent) : base(parent) + { + InitializeComponent(parent); + } + + /// + /// Gets or sets the background color of the NavigtiaonView. + /// + public override EColor BackgroundColor + { + get => _backgroundColor; + set + { + _backgroundColor = value; + EColor effectiveColor = _backgroundColor.IsDefault ? s_defaultBackgroundColor : _backgroundColor; + base.BackgroundColor = effectiveColor; + } + } + + /// + /// Gets or sets the background image of the NavigtiaonView. + /// + public EvasObject BackgroundImage + { + get => _backgroundImage; + set + { + _backgroundImage = value; + this.SetBackgroundPart(_backgroundImage); + } + } + + /// + /// Gets or sets the header view of the NavigtiaonView. + /// + public EvasObject Header + { + get => _header; + set => UpdateHeader(value); + } + + /// + /// Gets or sets the footer view of the NavigtiaonView. + /// + public EvasObject Footer + { + get => _footer; + set => UpdateFooter(value); + } + + public EvasObject Content + { + get => _content; + set => UpdateContent(value); + } + + /// + /// Gets or sets the target view of the NavigtiaonView. + /// + public EvasObject TargetView => this; + + /// + /// Notifies that the layout has been updated. + /// + public event EventHandler LayoutUpdated; + + void InitializeComponent(EvasObject parent) + { + base.BackgroundColor = s_defaultBackgroundColor; + + _mainLayout = new EBox(parent) + { + AlignmentX = -1, + AlignmentY = -1, + WeightX = 1, + WeightY = 1 + }; + _mainLayout.SetLayoutCallback(OnLayout); + _mainLayout.Show(); + + SetContent(_mainLayout); + } + + void OnLayout() + { + if (Geometry.Width == 0 || Geometry.Height == 0) + return; + + var bound = Geometry; + int headerHeight = 0; + int footerHeight = 0; + + if (_header != null) + { + var headerBound = bound; + headerHeight = _header.MinimumHeight; + headerBound.Height = headerHeight; + _header.Geometry = headerBound; + } + + if (_footer != null) + { + var footerbound = bound; + footerHeight = _footer.MinimumHeight; + footerbound.Y = bound.Y + bound.Height - footerHeight; + footerbound.Height = footerHeight; + _footer.Geometry = footerbound; + } + + if (_content != null) + { + bound.Y += headerHeight; + bound.Height = bound.Height - headerHeight - footerHeight; + _content.Geometry = bound; + } + + NotifyOnLayout(); + } + + void NotifyOnLayout() + { + LayoutUpdated?.Invoke(this, new LayoutEventArgs() { Geometry = Geometry.ToCommon() }); + } + + void UpdateHeader(EvasObject header) + { + if (_header != null) + { + _mainLayout.UnPack(_header); + _header.Unrealize(); + _header = null; + } + + if (header != null) + { + _mainLayout.PackStart(header); + } + _header = header; + _header?.Show(); + } + + void UpdateFooter(EvasObject footer) + { + if (_footer != null) + { + _mainLayout.UnPack(_footer); + _footer.Unrealize(); + _footer = null; + } + + if (footer != null) + { + _mainLayout.PackEnd(footer); + } + _footer = footer; + _footer?.Show(); + } + + void UpdateContent(EvasObject content) + { + if (_content != null) + { + _mainLayout.UnPack(_content); + _content.Unrealize(); + _content = null; + } + + if (content != null) + { + _mainLayout.PackEnd(content); + } + _content = content; + _content?.Show(); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs new file mode 100644 index 000000000000..0046969b13cb --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs @@ -0,0 +1,35 @@ +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; +using EToolbar = ElmSharp.Toolbar; + +namespace Tizen.UIExtensions.Shell +{ + public class Tabs : EToolbar, ITabs + { + TabsType _type; + + public Tabs(EvasObject parent) : base(parent) + { + Style = ElmSharp.ThemeConstants.Toolbar.Styles.Material; + SelectionMode = ToolbarSelectionMode.Always; + } + + public TabsType Scrollable + { + get => _type; + set + { + switch (value) + { + case TabsType.Fixed: + this.ShrinkMode = ToolbarShrinkMode.Expand; + break; + case TabsType.Scrollable: + this.ShrinkMode = ToolbarShrinkMode.Scroll; + break; + } + _type = value; + } + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs new file mode 100644 index 000000000000..b91c87d53211 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs @@ -0,0 +1,25 @@ +using EColor = ElmSharp.Color; + +namespace Tizen.UIExtensions.Shell +{ + public class ThemeConstants + { + public class Shell + { + public class ColorClass + { + public static readonly EColor DefaultBackgroundColor = EColor.FromRgb(33, 150, 243); + public static readonly EColor DefaultForegroundColor = EColor.White; + public static readonly EColor DefaultTitleColor = EColor.White; + } + + public class Resources + { + // The source of icon resources is https://materialdesignicons.com/ + public const string MenuIcon = "Platform.Tizen.Resources.menu.png"; + public const string BackIcon = "Platform.Tizen.Resources.arrow_left.png"; + public const string DotsIcon = "Platform.Tizen.Resources.dots_horizontal.png"; + } + } + } +} From a5e4ac5d712e8bbf5806cb3e4729b7f693e75991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 26 Aug 2021 10:39:25 +0900 Subject: [PATCH 048/266] MAUI workload for Tizen (#66) --- .../MauiApp1/Platforms/Tizen/Main.cs | 21 +++++++++++++++++++ .../Platforms/Tizen/tizen-manifest.xml | 15 +++++++++++++ .../MauiApp1/Platforms/Tizen/Main.cs | 21 +++++++++++++++++++ .../Platforms/Tizen/tizen-manifest.xml | 15 +++++++++++++ .../Microsoft.Maui.Dependencies.csproj | 2 +- .../WorkloadManifest.in.json | 15 +++++++++++++ 6 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs create mode 100644 src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml create mode 100644 src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs create mode 100644 src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs new file mode 100644 index 000000000000..731ac52155eb --- /dev/null +++ b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Compatibility; + +namespace MauiApp1 +{ + class Program : MauiApplication + { + protected override void OnCreate() + { + base.OnCreate(); + } + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 000000000000..5847c71b195d --- /dev/null +++ b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml @@ -0,0 +1,15 @@ + + + + + + appicon.xhigh.png + + + + + http://tizen.org/privilege/internet + + + + \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs new file mode 100644 index 000000000000..731ac52155eb --- /dev/null +++ b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Compatibility; + +namespace MauiApp1 +{ + class Program : MauiApplication + { + protected override void OnCreate() + { + base.OnCreate(); + } + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 000000000000..5847c71b195d --- /dev/null +++ b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml @@ -0,0 +1,15 @@ + + + + + + appicon.xhigh.png + + + + + http://tizen.org/privilege/internet + + + + \ No newline at end of file diff --git a/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj b/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj index b37ce29104e2..4b29e672015f 100644 --- a/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj +++ b/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj @@ -38,4 +38,4 @@

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 OK~q&uWL1qA8tR$@u%{$~CC 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 Date: Thu, 1 Jul 2021 11:13:58 +0900 Subject: [PATCH 019/266] Remove space --- src/Core/src/Platform/Tizen/CoreUIAppContext.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index bd886466e733..f0ef2e8b0d26 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -176,9 +176,6 @@ void InitializeMainWindow() }; MainWindow.BackButtonPressed += OnBackButtonPressed; - - - } void OnBackButtonPressed(object sender, EventArgs e) From 12637d2a886148f558ac9a23ee86816a2080625e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 2 Jul 2021 13:38:59 +0900 Subject: [PATCH 020/266] Fix compatibility issue (#41) * Fix compatibility issue * Fix Compatibility Resource path --- .../Core/src/Tizen/HandlerToRendererShim.cs | 1 - src/Compatibility/Core/src/Tizen/Platform.cs | 11 ++++++++++- .../Core/src/Tizen/Resources/arrow_left.png | Bin 0 -> 490 bytes .../Core/src/Tizen/Resources/dots_horizontal.png | Bin 0 -> 419 bytes .../Core/src/Tizen/Resources/menu.png | Bin 0 -> 417 bytes .../Core/src/Tizen/Resources/refresh_48dp.png | Bin 0 -> 876 bytes .../Core/src/Tizen/Resources/wc_visual_cue.png | Bin 0 -> 433 bytes .../src/Handlers/Layout/LayoutHandler.Tizen.cs | 5 +++++ 8 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 src/Compatibility/Core/src/Tizen/Resources/arrow_left.png create mode 100644 src/Compatibility/Core/src/Tizen/Resources/dots_horizontal.png create mode 100644 src/Compatibility/Core/src/Tizen/Resources/menu.png create mode 100644 src/Compatibility/Core/src/Tizen/Resources/refresh_48dp.png create mode 100644 src/Compatibility/Core/src/Tizen/Resources/wc_visual_cue.png diff --git a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs index 15ac51e58bd3..d90ff96b622e 100644 --- a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs +++ b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel; -using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Graphics; diff --git a/src/Compatibility/Core/src/Tizen/Platform.cs b/src/Compatibility/Core/src/Tizen/Platform.cs index 0ef8670bf924..c9aca6bcb231 100644 --- a/src/Compatibility/Core/src/Tizen/Platform.cs +++ b/src/Compatibility/Core/src/Tizen/Platform.cs @@ -92,7 +92,16 @@ internal static IVisualElementRenderer CreateRenderer(VisualElement element) { vh.SetParent(nvh); } - renderer = new HandlerToRendererShim(vh); + + if (handler is LayoutHandler layoutHandler) + { + renderer = new LayoutHandlerToRendererShim(layoutHandler); + } + else + { + renderer = new HandlerToRendererShim(vh); + } + element.Handler = handler; } } diff --git a/src/Compatibility/Core/src/Tizen/Resources/arrow_left.png b/src/Compatibility/Core/src/Tizen/Resources/arrow_left.png new file mode 100644 index 0000000000000000000000000000000000000000..923dfeb34fef7636cd416788a5e63a0e782c54b9 GIT binary patch literal 490 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+K*nlM7srr@!*8$K^D#O~w0$ghaeB$4mmL1u zN=VndfR%Ua@l1g#AZBg%d{)IqvO18)$c9z>fY|)pqQz=^8N{xpsHQv z%kvz39g0e`{Wh?wRqfd{wXPslUi_7!$tjJ+ObZ^>9NIVI%9>E0)F8vU<~hYP&*>kV z_bY3$OEu8hswJ)wB`Jv|saDBFsX&Us$iUE2*T7iU$Rfnh$ja2f%Gg}nz`)ADK-@hP z6dVW*x%nxXX_dG&q)EMP0BX|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+Kt_tEi(^Q{;kTCzxf%=vTrMU|+8nJAKfQsj&e~cXmcv2Erg#_GFs<>6xUFz`3Ul>!lrT4@f-?e^I zZ`)~H4$XMEWAD_R;m2m25{PcDoikCz^VbE&TR(+f`^(mWoTFOe8c~vxSdwa$T$Bo= z7>o=IEp-iyb&V`S42`TzO{@$Iv<(b^WN6D7Z4?c;`6-!cmAEyi+$@<6)Sv;fp|~vF zDk-rzRkyS#lOZiLC)G+{U%w=`KtDGzJu^95*V54?(BCLOE4y2A9Z(O0r>mdKI;Vst E0GM@v1^@s6 literal 0 HcmV?d00001 diff --git a/src/Compatibility/Core/src/Tizen/Resources/menu.png b/src/Compatibility/Core/src/Tizen/Resources/menu.png new file mode 100644 index 0000000000000000000000000000000000000000..6dcfc0575a1d6c10f34cf6df4933ce31b21ccf02 GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+Kt__Mi(^Q{;kVZUxf&D%S{~kfk#J9^|Jm7P z*M&HpZnXS+UnrO^DKLeB;e1Z`^Od##zLheb)@M1>RhO{aL(B80uF|d24g7qfp6*GS z+gqnqe_Pyk>$bOAO4`HqKkC-(6JS_S%+#a$)V%xH<2;~kswJ)wB`Jv|saDBFsX&Us z$iUE2*T7iU$Rfnh$ja2%%Gglbz`)ADVE%&JAnzkI>Kms6W9c%CLbv5?y>lcGmG9$4EYK8l7-o zfCt%5&_vEG;B#z+(*j(;8iLx8AqB)q^mJB$I7Sgvo_Hw)l4$Izz#9ZrRX8lwofIIG zCD_^#FNH*Pa8uw1Y!k_pLZUo4DL^JGF>T}`7xA?Ue1`2;H}SO!jKnmD6gTlz3UCRw zFQiZ?0WJ&tiD?a4uHx$y7=o$1yZ8zPIEw9Yf{UXY!kL?Z7LK-VDZRA2x#4XqssD3u`z2@SsjSMDYdr$jq zuozo=;+1xtyI`B9{@Kp!S{ocTY7%s>Xd{jhA#5?lQ<9(-5(X}04MAoRtzpSy4Ug_$K~_E{6E{sPH_nr4P%TNoSet-uh_@lezJv#6owRZ z*n=eQrv~fDNqdq+fzG(iO?$^}QaPE6xs{J;%Q|9dOrp3!0@ct~o;Y!dr&)=X4ZJSy zaXLNGFpTr%&>)TvSWjWh=XI@1$Nk{zDt;tQ6zGf|k0w86@q@-HtNY<^m_<46C;o6A zzrS_w`2BEZvk`#pOrse;@i?c663_EI&+|Ob^Sm9?3(oMoN8C*S0000VM%xNb!1@J z*w6hZkrl}2EbxddW??NMQuI!IEm{={W z*VeIw15H)*ba4#v@P2#M*NfRvpzUE`jFhRAt9cc>ZDW%{M~8yq@eA4<_YSqrXmBd~ zH^*U5i+5n>f*qxa68HVpolE^yTW+#k3G#989r6krBDY-7e?Ftx{B==x?VAUZX74M0SDsls`)2EQ_r~a+ zGY>=x-)(40y|YSSX{Xj6+v2>7Hx4Q1?6Nq_B>DD+YPLH{%LfM|K{x*(15SP5a2jgC&a{>o=T;IrNOV{l~wXa+9j~7evm^ zX4!jCX>&)o#`lQk>*hV78T_vIr>U~o9z3+-F^_1lcDB&1)rna<|JNVhU)P}WlWB*o WRE1^#Dj{I_F?hQAxvX Date: Tue, 6 Jul 2021 17:57:42 +0900 Subject: [PATCH 021/266] Bump to latest - Modal Navigation Manager (#1563) - Implement the basic WindowHandler (#1468) - Don't extract native defaults, meaning users can no longer reset a color back to a platform theme (#1485) - Implement Alerts (Alert, Prompt and ActionSheet) (#1328) - And so on. --- .../src/Core/HandlerImpl/Window.Tizen.cs | 12 ++++ .../ModalNavigationService.Tizen.cs | 57 ------------------- src/Core/src/IMauiContext.cs | 1 + src/Core/src/Platform/MauiContext.Tizen.cs | 2 + .../src/Platform/Tizen/CoreUIAppContext.cs | 1 - .../src/Platform/Tizen/HandlerExtensions.cs | 44 +++++++++----- .../src/Platform/Tizen/MauiApplication.cs | 14 ++++- 7 files changed, 57 insertions(+), 74 deletions(-) create mode 100644 src/Controls/src/Core/HandlerImpl/Window.Tizen.cs delete mode 100644 src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs diff --git a/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs new file mode 100644 index 000000000000..12dcf19a25ea --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs @@ -0,0 +1,12 @@ +#nullable enable +using System; +using EWindow = ElmSharp.Window; + +namespace Microsoft.Maui.Controls +{ + public partial class Window + { + internal EWindow NativeWindow => + (Handler?.NativeView as EWindow) ?? throw new InvalidOperationException("Window should have a ElmSharp.Window set."); + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs b/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs deleted file mode 100644 index c02e54e0f0ea..000000000000 --- a/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs +++ /dev/null @@ -1,57 +0,0 @@ -#nullable enable - -using System.Threading.Tasks; - -namespace Microsoft.Maui.Controls.Platform -{ - internal partial class ModalNavigationService - { - ModalStack _modalStack => MauiContext.Context!.ModalStack; - IPageController CurrentPageController => _navModel.CurrentPage; - - partial void OnPageAttachedHandler() - { - MauiContext.Context!.SetBackButtonPressedHandler(OnBackButtonPressed); - } - - public Task PopModalAsync(bool animated) - { - Page modal = _navModel.PopModal(); - ((IPageController)modal).SendDisappearing(); - var source = new TaskCompletionSource(); - - var modalRenderer = modal.Handler as INativeViewHandler; - if (modalRenderer != null) - { - // TODO. Need to implement animated - _modalStack.Pop(); - source.TrySetResult(modal); - CurrentPageController?.SendAppearing(); - } - return source.Task; - } - - public Task PushModalAsync(Page modal, bool animated) - { - CurrentPageController?.SendDisappearing(); - _navModel.PushModal(modal); - - var nativeView = modal.ToNative(MauiContext); - _modalStack.Push(nativeView); - - // Verify that the modal is still on the stack - if (_navModel.CurrentPage == modal) - ((IPageController)modal).SendAppearing(); - - return Task.CompletedTask; - } - - bool OnBackButtonPressed() - { - Page root = _navModel.LastRoot; - bool handled = root?.SendBackButtonPressed() ?? false; - - return handled; - } - } -} diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index 11b1593bb241..e1648772dffa 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -12,6 +12,7 @@ public interface IMauiContext Android.Content.Context? Context { get; } #elif TIZEN CoreUIAppContext? Context { get; } + ElmSharp.Window? Window { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/Platform/MauiContext.Tizen.cs b/src/Core/src/Platform/MauiContext.Tizen.cs index 3a0b26c4b7cc..231f6a27583f 100644 --- a/src/Core/src/Platform/MauiContext.Tizen.cs +++ b/src/Core/src/Platform/MauiContext.Tizen.cs @@ -1,4 +1,5 @@ using System; +using ElmSharp; namespace Microsoft.Maui { @@ -33,5 +34,6 @@ public CoreUIAppContext? Context } } + public Window? Window => Context?.MainWindow; } } \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index f0ef2e8b0d26..f6eca62286bf 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -25,7 +25,6 @@ public static CoreUIAppContext GetInstance(CoreApplication application, Window? if (IsInitialized) return _instance!; - _instance = (window == null) ? new CoreUIAppContext(application) : new CoreUIAppContext(application, window); return _instance; } diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index e55243bcb187..f69811a80726 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -1,4 +1,5 @@ using System; +using Tizen.Applications; using ElmSharp; namespace Microsoft.Maui @@ -15,34 +16,47 @@ public static EvasObject ToNative(this IView view, IMauiContext context) view = ir.ReplacedView; var handler = view.Handler; - - if (handler?.MauiContext != null && - handler.MauiContext != context) - { + if (handler?.MauiContext != null && handler.MauiContext != context) handler = null; - } if (handler == null) - { - handler = context.Handlers.GetHandler(view.GetType()); + handler = context.Handlers.GetHandler(view.GetType()) as IViewHandler; + + if (handler == null) + throw new Exception($"Handler not found for view {view} or was not {nameof(IViewHandler)}."); - if (handler == null) - throw new Exception($"Handler not found for view {view}"); + handler.SetMauiContext(context); - handler.SetMauiContext(context); - view.Handler = handler; - } + view.Handler = handler; if (handler.VirtualView != view) handler.SetVirtualView(view); - if (((INativeViewHandler)handler).NativeView is not EvasObject result) - { throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); - } return result; } + + public static void SetWindow(this Window nativeWindow, IWindow window, IMauiContext mauiContext) + { + _ = nativeWindow ?? throw new ArgumentNullException(nameof(nativeWindow)); + _ = window ?? throw new ArgumentNullException(nameof(window)); + _ = mauiContext ?? throw new ArgumentNullException(nameof(mauiContext)); + + var handler = window.Handler as IWindowHandler; + if (handler == null) + handler = mauiContext.Handlers.GetHandler(window.GetType()) as IWindowHandler; + + if (handler == null) + throw new Exception($"Handler not found for view {window} or was not {nameof(IWindowHandler)}'"); + + handler.SetMauiContext(mauiContext); + + window.Handler = handler; + + if (handler.VirtualView != window) + handler.SetVirtualView(window); + } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index 74acecfe7aa5..b8a0f94391d5 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -54,7 +54,17 @@ protected override void OnCreate() this.CreatePlatformWindow(Application); - Current.Services?.InvokeLifecycleEvents(del => del(this)); + var tizenWindow = mauiContext.Window; + + if (tizenWindow == null) + throw new InvalidOperationException($"The {nameof(tizenWindow)} instance was not found."); + + var activationState = new ActivationState(mauiContext); + var window = Application.CreateWindow(activationState); + + tizenWindow.SetWindow(window, mauiContext); + + return tizenWindow; } protected override void OnAppControlReceived(AppControlReceivedEventArgs e) @@ -113,6 +123,8 @@ protected override void OnTerminate() public static new MauiApplication Current { get; private set; } = null!; + public Window MainWindow { get; protected set; } = null!; + public IServiceProvider Services { get; protected set; } = null!; public IApplication Application { get; protected set; } = null!; From 4f6a099a8bdc2849edfeea6e6edce095965199f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 9 Jul 2021 11:05:31 +0900 Subject: [PATCH 022/266] [SingleProject] Fix Issues (#50) --- .../src/TizenIconManifestUpdator.cs | 56 ------ .../Resizetizer/src/TizenSplashUpdator.cs | 162 ------------------ 2 files changed, 218 deletions(-) delete mode 100644 src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs delete mode 100644 src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs diff --git a/src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs b/src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs deleted file mode 100644 index b8ea28316b95..000000000000 --- a/src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Xml; - -namespace Microsoft.Maui.Resizetizer -{ - internal class TizenIconManifestUpdator - { - const string namespaceURI = "http://tizen.org/ns/packages"; - - public TizenIconManifestUpdator(string appIconName, DpiPath[] dpis, ILogger logger) - { - AppIconName = appIconName; - Dpis = dpis; - Logger = logger; - } - - public string AppIconName { get; private set; } - - public DpiPath[] Dpis { get; } - - public ILogger Logger { get; private set; } - - public void Update() - { - XmlDocument doc = new XmlDocument(); - var xmlPath = Environment.CurrentDirectory + "\\tizen-manifest.xml"; - try - { - doc.Load(xmlPath); - } - catch - { - Logger.Log($"Failed to load tizen-manifest.xml"); - return; - } - - var nsmgr = new XmlNamespaceManager(doc.NameTable); - nsmgr.AddNamespace("manifest", namespaceURI); - var uiApplicationNode = doc.SelectSingleNode("//manifest:ui-application", nsmgr); - if (uiApplicationNode == null) - { - Logger.Log($"Failed to find "); - return; - } - var IconNode = doc.SelectSingleNode("//manifest:icon", nsmgr); - if (IconNode == null) - { - IconNode = doc.CreateElement("icon", namespaceURI); - uiApplicationNode.AppendChild(IconNode); - } - IconNode.InnerText = AppIconName + Dpis[1].FileSuffix + ".png"; - - doc.Save(xmlPath); - } - } -} diff --git a/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs b/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs deleted file mode 100644 index f0ad58103327..000000000000 --- a/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Xml; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using SkiaSharp; - -namespace Microsoft.Maui.Resizetizer -{ - public class TizenSplashUpdator : Task - { - [Required] - public ITaskItem[] MauiSplashScreen { get; set; } - - [Required] - public string IntermediateOutputPath { get; set; } - - public string ManifestFile { get; set; } = "tizen-manifest.xml"; - - public ILogger Logger { get; private set; } - - public override bool Execute() - { - if (UpdateSplashImage()) - UpdateManifest(); - return !Log.HasLoggedErrors; - } - - const string namespaceURI = "http://tizen.org/ns/packages"; - const string splashDirectoryName = "splash"; - List orientations = new List() { "portrait", "landscape" }; - Dictionary splashDpiMap = new Dictionary(); - - public bool UpdateSplashImage() - { - var splash = MauiSplashScreen[0]; - var image = Path.GetFileNameWithoutExtension(splash.ItemSpec) + ".png"; - var sharedResFullPath = Path.GetFullPath(Path.Combine(IntermediateOutputPath, "shared/res/")); - var splashFullPath = Path.Combine(sharedResFullPath, splashDirectoryName); - - if (Directory.Exists(splashFullPath)) - { - Directory.Delete(splashFullPath, true); - } - Directory.CreateDirectory(splashFullPath); - - foreach (var dpi in DpiPath.Tizen) - { - var imageOutputPath = Path.GetFullPath(Path.Combine(IntermediateOutputPath, dpi.Path)); - var imageFullPath = Path.Combine(imageOutputPath, image); - if (File.Exists(imageFullPath)) - { - var resolution = dpi.Path.Split('-')[1].ToLower(); - var newImage = Path.GetFileNameWithoutExtension(splash.ItemSpec) + "." + resolution + ".png"; - splashDpiMap.Add(resolution, $"{splashDirectoryName}/{ newImage }"); - UpdateColorAndMoveFile(imageFullPath, Path.Combine(splashFullPath, newImage)); - } - else - { - Log.LogWarning($"Unable to find splash image at {imageFullPath}."); - return false; - } - } - return true; - } - - public void UpdateColorAndMoveFile(string sourceFilePath, string destFilePath) - { - var splash = MauiSplashScreen[0]; - var colorMetadata = splash.GetMetadata("Color"); - var color = Utils.ParseColorString(colorMetadata); - if (color == null) - { - if (!string.IsNullOrEmpty(colorMetadata)) - { - Log.LogWarning($"Unable to parse color value '{colorMetadata}' for '{splash.ItemSpec}'."); - } - color = SKColors.White; - } - - using (SKBitmap bmp = SKBitmap.Decode(sourceFilePath)) - { - SKImageInfo info = new SKImageInfo(bmp.Width, bmp.Height); - using (SKSurface surface = SKSurface.Create(info)) - { - SKCanvas canvas = surface.Canvas; - canvas.Clear(color.Value); - using SKPaint paint = new SKPaint - { - IsAntialias = true, - FilterQuality = SKFilterQuality.High - }; - canvas.DrawBitmap(bmp, info.Rect, paint); - canvas.Flush(); - - var updatedsplash = surface.Snapshot(); - using (var data = updatedsplash.Encode(SKEncodedImageFormat.Png, 100)) - { - using (var stream = File.Create(destFilePath)) - { - data.SaveTo(stream); - } - } - } - } - File.Delete(sourceFilePath); - } - - public void UpdateManifest() - { - XmlDocument doc = new XmlDocument(); - var xmlPath = Path.Combine(Environment.CurrentDirectory, ManifestFile); - try - { - doc.Load(xmlPath); - } - catch - { - Log.LogWarning($"Failed to load tizen-manifest.xml"); - return; - } - - var nsmgr = new XmlNamespaceManager(doc.NameTable); - nsmgr.AddNamespace("manifest", namespaceURI); - var uiApplicationNode = doc.SelectSingleNode("//manifest:ui-application", nsmgr); - if (uiApplicationNode == null) - { - Log.LogWarning($"Failed to find "); - return; - } - var splashScreensNodeList = doc.SelectNodes("//manifest:splash-screens", nsmgr); - if (splashScreensNodeList != null) - { - foreach (XmlNode node in splashScreensNodeList) - { - uiApplicationNode.RemoveChild(node); - } - } - - var splashScreensNode = doc.CreateElement("splash-screens", namespaceURI); - uiApplicationNode.AppendChild(splashScreensNode); - - foreach(var image in splashDpiMap) - { - foreach (var orientation in orientations) - { - var splashScreenNode = doc.CreateElement("splash-screen", namespaceURI); - splashScreenNode.SetAttribute("src", image.Value); - splashScreenNode.SetAttribute("type", "img"); - splashScreenNode.SetAttribute("dpi", image.Key); - splashScreenNode.SetAttribute("orientation", orientation); - splashScreenNode.SetAttribute("indicator-display", "false"); - splashScreenNode.SetAttribute("app-control-operation", "http://tizen.org/appcontrol/operation/default"); - splashScreensNode.AppendChild(splashScreenNode); - } - } - - doc.Save(xmlPath); - } - } -} From 9f4168ef45942bb5ea8feea371d816660b72df85 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 14 Jul 2021 10:04:16 +0900 Subject: [PATCH 023/266] Bumt to latest - Effects (#1574) - Improve Window and AnimationManager (#1653) - and so on --- src/Core/src/Platform/Tizen/HandlerExtensions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index f69811a80726..43df1d04043b 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -6,7 +6,7 @@ namespace Microsoft.Maui { public static class HandlerExtensions { - public static EvasObject ToNative(this IView view, IMauiContext context) + public static EvasObject ToNative(this IElement view, IMauiContext context) { _ = view ?? throw new ArgumentNullException(nameof(view)); _ = context ?? throw new ArgumentNullException(nameof(context)); @@ -44,12 +44,12 @@ public static void SetWindow(this Window nativeWindow, IWindow window, IMauiCont _ = window ?? throw new ArgumentNullException(nameof(window)); _ = mauiContext ?? throw new ArgumentNullException(nameof(mauiContext)); - var handler = window.Handler as IWindowHandler; + var handler = window.Handler; if (handler == null) - handler = mauiContext.Handlers.GetHandler(window.GetType()) as IWindowHandler; + handler = mauiContext.Handlers.GetHandler(window.GetType()); if (handler == null) - throw new Exception($"Handler not found for view {window} or was not {nameof(IWindowHandler)}'"); + throw new Exception($"Handler not found for view {window}."); handler.SetMauiContext(mauiContext); From 989858125047203e7ef3988bb5ec6f2c7f850e29 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 14 Jul 2021 19:35:24 +0900 Subject: [PATCH 024/266] Add Microsoft.Maui.Graphics.Skia as PackageReference --- .../SKColorExtensions.cs | 17 - .../SKGraphicsExtensions.cs | 402 -------- .../SKPaintExtensions.cs | 39 - .../SkiaBitmapExportContext.cs | 112 --- .../SkiaCanvas.cs | 904 ------------------ .../SkiaCanvasState.cs | 451 --------- .../SkiaDelegatingFontService.cs | 82 -- .../SkiaFontFamily.cs | 77 -- .../SkiaFontService.cs | 87 -- .../SkiaFontStyle.cs | 74 -- .../SkiaGraphicsService.cs | 99 -- .../Microsoft.Maui.Graphics.Skia/SkiaImage.cs | 162 ---- .../SkiaTextLayout.cs | 266 ------ .../Views/SkiaGraphicsView.Tizen.cs | 45 - 14 files changed, 2817 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKColorExtensions.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKGraphicsExtensions.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKPaintExtensions.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaBitmapExportContext.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvas.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvasState.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaDelegatingFontService.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontFamily.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontService.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontStyle.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaImage.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaTextLayout.cs delete mode 100644 src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/Views/SkiaGraphicsView.Tizen.cs diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKColorExtensions.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKColorExtensions.cs deleted file mode 100644 index c069806ecdae..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKColorExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using SkiaSharp; - -namespace Microsoft.Maui.Graphics.Skia -{ - public static class SKColorExtensions - { - public static SKColor ToColor(this Color target, float alpha = 1) - { - var r = (byte) (target.Red * 255f); - var g = (byte) (target.Green * 255f); - var b = (byte) (target.Blue * 255f); - var a = (byte) (target.Alpha * 255f * alpha); - - return new SKColor(r, g, b, a); - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKGraphicsExtensions.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKGraphicsExtensions.cs deleted file mode 100644 index c1edc743cf6a..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKGraphicsExtensions.cs +++ /dev/null @@ -1,402 +0,0 @@ -using System; -using SkiaSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public static class SKGraphicsExtensions - { - public static SKColor AsSKColorMultiplyAlpha(this Color target, float alpha) - { - var r = (byte) (target.Red * 255f); - var g = (byte) (target.Green * 255f); - var b = (byte) (target.Blue * 255f); - var a = (byte) (target.Alpha * alpha * 255f); - - if (a > 255) - a = 255; - - var color = new SKColor(r, g, b, a); - return color; - } - - public static int ToArgb(this Color target) - { - var a = (int) (target.Alpha * 255f); - var r = (int) (target.Red * 255f); - var g = (int) (target.Green * 255f); - var b = (int) (target.Blue * 255f); - - var argb = a << 24 | r << 16 | g << 8 | b; - return argb; - } - - public static int ToArgb(this Color target, float alpha) - { - var a = (int) (target.Alpha * 255f * alpha); - var r = (int) (target.Red * 255f); - var g = (int) (target.Green * 255f); - var b = (int) (target.Blue * 255f); - - var argb = a << 24 | r << 16 | g << 8 | b; - return argb; - } - - public static SKColor AsSKColor(this Color target) - { - var r = (byte) (target.Red * 255f); - var g = (byte) (target.Green * 255f); - var b = (byte) (target.Blue * 255f); - var a = (byte) (target.Alpha * 255f); - return new SKColor(r, g, b, a); - } - - public static Color AsColor(this SKColor target) - { - var r = (int) target.Red; - var g = (int) target.Green; - var b = (int) target.Blue; - var a = (int) target.Alpha; - return new Color(r, g, b, a); - } - - public static SKRect AsSKRect(this RectangleF target) - { - return new SKRect(target.Left, target.Top, target.Right, target.Bottom); - } - - public static RectangleF AsRectangleF(this SKRect target) - { - return new RectangleF(target.Left, target.Top, Math.Abs(target.Right - target.Left), Math.Abs(target.Bottom - target.Top)); - } - - public static SKPoint ToSKPoint(this PointF target) - { - return new SKPoint(target.X, target.Y); - } - - public static SKMatrix AsMatrix(this AffineTransform transform) - { - var matrix = new SKMatrix - { - ScaleX = transform.ScaleX, - SkewX = transform.ShearX, - TransX = transform.TranslateX, - SkewY = transform.ShearY, - ScaleY = transform.ScaleY, - TransY = transform.TranslateY, - Persp0 = 0, - Persp1 = 0, - Persp2 = 1 - }; - return matrix; - } - - public static SKPath AsSkiaPath(this PathF target) - { - return AsSkiaPath(target, 1); - } - - public static SKPath AsSkiaPath(this PathF path, float ppu) - { - return AsSkiaPath(path, ppu, 0, 0, 1, 1); - } - - public static SKPath AsSkiaPath( - this PathF path, - float ppu, - float ox, - float oy, - float fx, - float fy) - { - var nativePath = new SKPath(); - - var ppux = ppu * fx; - var ppuy = ppu * fy; - - var pointIndex = 0; - var arcAngleIndex = 0; - var arcClockwiseIndex = 0; - - foreach (var type in path.SegmentTypes) - { - if (type == PathOperation.Move) - { - var point = path[pointIndex++]; - nativePath.MoveTo((ox + point.X * ppux), (oy + point.Y * ppuy)); - } - else if (type == PathOperation.Line) - { - var point = path[pointIndex++]; - nativePath.LineTo((ox + point.X * ppux), (oy + point.Y * ppuy)); - } - - else if (type == PathOperation.Quad) - { - var controlPoint = path[pointIndex++]; - var point = path[pointIndex++]; - nativePath.QuadTo((ox + controlPoint.X * ppux), (oy + controlPoint.Y * ppuy), (ox + point.X * ppux), (oy + point.Y * ppuy)); - } - else if (type == PathOperation.Cubic) - { - var controlPoint1 = path[pointIndex++]; - var controlPoint2 = path[pointIndex++]; - var point = path[pointIndex++]; - nativePath.CubicTo((ox + controlPoint1.X * ppux), (oy + controlPoint1.Y * ppuy), (ox + controlPoint2.X * ppux), (oy + controlPoint2.Y * ppuy), (ox + point.X * ppux), - (oy + point.Y * ppuy)); - } - else if (type == PathOperation.Arc) - { - var topLeft = path[pointIndex++]; - var bottomRight = path[pointIndex++]; - var startAngle = path.GetArcAngle(arcAngleIndex++); - var endAngle = path.GetArcAngle(arcAngleIndex++); - var clockwise = path.GetArcClockwise(arcClockwiseIndex++); - - while (startAngle < 0) - { - startAngle += 360; - } - - while (endAngle < 0) - { - endAngle += 360; - } - - var rect = new SKRect(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); - var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); - - startAngle *= -1; - if (!clockwise) - sweep *= -1; - - nativePath.AddArc(rect, startAngle, sweep); - } - else if (type == PathOperation.Close) - { - nativePath.Close(); - } - } - - return nativePath; - } - - public static SKPath AsSkiaPath(this PathF path, float ppu, float zoom) - { - return AsSkiaPath(path, ppu * zoom); - } - - public static SKPath AsSkiaPathFromSegment(this PathF target, int segmentIndex, float ppu, float zoom) - { - ppu = zoom * ppu; - - var path = new SKPath(); - - var type = target.GetSegmentType(segmentIndex); - if (type == PathOperation.Line) - { - var pointIndex = target.GetSegmentPointIndex(segmentIndex); - var startPoint = target[pointIndex - 1]; - path.MoveTo(startPoint.X * ppu, startPoint.Y * ppu); - - var endPoint = target[pointIndex]; - path.LineTo(endPoint.X * ppu, endPoint.Y * ppu); - } - else if (type == PathOperation.Quad) - { - var pointIndex = target.GetSegmentPointIndex(segmentIndex); - var startPoint = target[pointIndex - 1]; - path.MoveTo(startPoint.X * ppu, startPoint.Y * ppu); - - var controlPoint = target[pointIndex++]; - var endPoint = target[pointIndex]; - path.QuadTo(controlPoint.X * ppu, controlPoint.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); - } - else if (type == PathOperation.Cubic) - { - var pointIndex = target.GetSegmentPointIndex(segmentIndex); - var startPoint = target[pointIndex - 1]; - path.MoveTo(startPoint.X * ppu, startPoint.Y * ppu); - - var controlPoint1 = target[pointIndex++]; - var controlPoint2 = target[pointIndex++]; - var endPoint = target[pointIndex]; - path.CubicTo(controlPoint1.X * ppu, controlPoint1.Y * ppu, controlPoint2.X * ppu, controlPoint2.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); - } - else if (type == PathOperation.Arc) - { - target.GetSegmentInfo(segmentIndex, out var pointIndex, out var arcAngleIndex, out var arcClockwiseIndex); - - var topLeft = target[pointIndex++]; - var bottomRight = target[pointIndex]; - var startAngle = target.GetArcAngle(arcAngleIndex++); - var endAngle = target.GetArcAngle(arcAngleIndex); - var clockwise = target.GetArcClockwise(arcClockwiseIndex); - - while (startAngle < 0) - { - startAngle += 360; - } - - while (endAngle < 0) - { - endAngle += 360; - } - - var rect = new SKRect(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); - var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); - - startAngle *= -1; - if (!clockwise) - sweep *= -1; - - path.AddArc(rect, startAngle, sweep); - } - - return path; - } - - public static SKPath AsRotatedAndroidPath(this PathF target, PointF center, float ppu, float zoom, float angle) - { - ppu = zoom * ppu; - - var path = new SKPath(); - - var pointIndex = 0; - var arcAngleIndex = 0; - var arcClockwiseIndex = 0; - - foreach (var type in target.SegmentTypes) - { - if (type == PathOperation.Move) - { - var point = target.GetRotatedPoint(pointIndex++, center, angle); - path.MoveTo(point.X * ppu, point.Y * ppu); - } - else if (type == PathOperation.Line) - { - var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); - path.LineTo(endPoint.X * ppu, endPoint.Y * ppu); - } - else if (type == PathOperation.Quad) - { - var controlPoint1 = target.GetRotatedPoint(pointIndex++, center, angle); - var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); - path.QuadTo( - controlPoint1.X * ppu, - controlPoint1.Y * ppu, - endPoint.X * ppu, - endPoint.Y * ppu); - } - else if (type == PathOperation.Cubic) - { - var controlPoint1 = target.GetRotatedPoint(pointIndex++, center, angle); - var controlPoint2 = target.GetRotatedPoint(pointIndex++, center, angle); - var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); - path.CubicTo( - controlPoint1.X * ppu, - controlPoint1.Y * ppu, - controlPoint2.X * ppu, - controlPoint2.Y * ppu, - endPoint.X * ppu, - endPoint.Y * ppu); - } - else if (type == PathOperation.Arc) - { - var topLeft = target[pointIndex++]; - var bottomRight = target[pointIndex++]; - var startAngle = target.GetArcAngle(arcAngleIndex++); - var endAngle = target.GetArcAngle(arcAngleIndex++); - var clockwise = target.GetArcClockwise(arcClockwiseIndex++); - - while (startAngle < 0) - { - startAngle += 360; - } - - while (endAngle < 0) - { - endAngle += 360; - } - - var rect = new SKRect(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); - var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); - - startAngle *= -1; - if (!clockwise) - sweep *= -1; - - path.AddArc(rect, startAngle, sweep); - } - else if (type == PathOperation.Close) - { - path.Close(); - } - } - - return path; - } - - public static SizeF AsSize(this SKSize target) - { - return new SizeF(target.Width, target.Height); - } - - public static SKSize AsSizeF(this SizeF target) - { - return new SKSize(target.Width, target.Height); - } - - public static PointF AsPointF(this SKPoint target) - { - return new PointF(target.X, target.Y); - } - - public static SKBitmap GetPatternBitmap(this PatternPaint patternPaint, float scale = 1) - { - var pattern = patternPaint?.Pattern; - if (pattern == null) - return null; - - using (var context = new SkiaBitmapExportContext((int) (pattern.Width * scale), (int) (pattern.Height * scale), scale, disposeBitmap: false)) - { - var canvas = context.Canvas; - - canvas.Scale(scale, scale); - pattern.Draw(canvas); - - return context.Bitmap; - } - } - - public static SKBitmap GetPatternBitmap(this PatternPaint patternPaint, float scaleX, float scaleY, object currentFigure) - { - var pattern = patternPaint?.Pattern; - if (pattern == null) - return null; - - using (var context = new SkiaBitmapExportContext((int) (pattern.Width * scaleX), (int) (pattern.Height * scaleY), 1, disposeBitmap: false)) - { - var canvas = context.Canvas; - - if (currentFigure != null) - { - } - - canvas.Scale(scaleX, scaleY); - pattern.Draw(canvas); - - if (currentFigure != null) - { - } - - //var filename = "/storage/emulated/0/" + pattern.GetType().Name + ".png"; - //System.Console.WriteLine("Writing to :{0}",filename); - //context.WriteToFile (filename); - return context.Bitmap; - } - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKPaintExtensions.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKPaintExtensions.cs deleted file mode 100644 index b9d407a6e574..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SKPaintExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using SkiaSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public static class SKPaintExtensions - { - public static SKPaint CreateCopy(this SKPaint paint) - { - if (paint == null) - return null; - - var copy = new SKPaint - { - BlendMode = paint.BlendMode, - Color = paint.Color, - ColorFilter = paint.ColorFilter, - ImageFilter = paint.ImageFilter, - IsAntialias = paint.IsAntialias, - IsStroke = paint.IsStroke, - MaskFilter = paint.MaskFilter, - Shader = paint.Shader, - StrokeCap = paint.StrokeCap, - StrokeJoin = paint.StrokeJoin, - StrokeMiter = paint.StrokeMiter, - StrokeWidth = paint.StrokeWidth, - TextAlign = paint.TextAlign, - TextEncoding = paint.TextEncoding, - TextScaleX = paint.TextScaleX, - TextSize = paint.TextSize, - TextSkewX = paint.TextSkewX, - Typeface = paint.Typeface, - }; - - return copy; - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaBitmapExportContext.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaBitmapExportContext.cs deleted file mode 100644 index 0b1824503d61..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaBitmapExportContext.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System.IO; -using SkiaSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaBitmapExportContext : BitmapExportContext - { - private readonly bool _disposeBitmap; - - private SKBitmap _bitmap; - private SKImage _image; - private SKSurface _surface; - private SKCanvas _skiaCanvas; - private ScalingCanvas _canvas; - - public SkiaBitmapExportContext( - int width, - int height, - float displayScale, - int dpi = 72, - bool disposeBitmap = true, - bool transparent = true) : base(width, height, dpi) - { - if (transparent) - { - var imageInfo = new SKImageInfo(width, height, SKColorType.Rgba8888, SKAlphaType.Premul); - _surface = SKSurface.Create(imageInfo); - } - else - { - var imageInfo = new SKImageInfo(width, height, SKColorType.Rgb565, SKAlphaType.Opaque); - _surface = SKSurface.Create(imageInfo); - } - - if (_surface == null) - { - Logger.Warn("Unable to create a Skia surface"); - return; - } - - _skiaCanvas = _surface.Canvas; - var nativeCanvas = new SkiaCanvas - { - Canvas = _skiaCanvas, - DisplayScale = displayScale - }; - _canvas = new ScalingCanvas(nativeCanvas); - _disposeBitmap = disposeBitmap; - } - - public override ICanvas Canvas => _canvas; - - public override IImage Image => new SkiaImage(Bitmap); - - public SKImage SKImage => _image ?? (_image = _surface.Snapshot()); - - public SKBitmap Bitmap - { - get - { - if (_bitmap == null) - { - var data = SKImage.Encode(); - _bitmap = SKBitmap.Decode(data); - } - - return _bitmap; - } - } - - public override void Dispose() - { - if (_skiaCanvas != null) - { - _skiaCanvas.Dispose(); - _skiaCanvas = null; - } - - if (_surface != null) - { - _surface.Dispose(); - _surface = null; - } - - if (_image != null) - { - _image.Dispose(); - _image = null; - } - - if (_bitmap != null && _disposeBitmap) - { - _bitmap.Dispose(); - _bitmap = null; - } - - _canvas = null; - - base.Dispose(); - } - - public override void WriteToStream(Stream stream) - { - using (var data = SKImage.Encode(SKEncodedImageFormat.Png, 100)) - { - data.SaveTo(stream); - } - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvas.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvas.cs deleted file mode 100644 index 039c20dd4377..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvas.cs +++ /dev/null @@ -1,904 +0,0 @@ -using System; -using Microsoft.Maui.Graphics.Text; -using SkiaSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaCanvas : AbstractCanvas, IBlurrableCanvas - { - private static SKPaint _defaultFillPaint; - private static SKPaint _defaultFontPaint; - private static SKPaint _defaultStrokePaint; - - //private readonly SKMatrix _shaderMatrix = new SKMatrix(); - - private SKCanvas _canvas; - private float _displayScale = 1; - private SKShader _shader; - - public SkiaCanvas() : base(CreateNewState, CreateStateCopy) - { - } - - public override float DisplayScale => _displayScale; - - public SKCanvas Canvas - { - get => _canvas; - set - { - _canvas = null; - ResetState(); - _canvas = value; - } - } - - public override bool Antialias - { - set => CurrentState.AntiAlias = value; - } - - protected override float NativeStrokeSize - { - set => CurrentState.NativeStrokeSize = value; - } - - public override float MiterLimit - { - set => CurrentState.MiterLimit = value; - } - - public override float Alpha - { - set => CurrentState.Alpha = value; - } - - public override LineCap StrokeLineCap - { - set => CurrentState.StrokeLineCap = value; - } - - public override LineJoin StrokeLineJoin - { - set => CurrentState.StrokeLineJoin = value; - } - - public override Color StrokeColor - { - set => CurrentState.StrokeColor = value ?? Colors.Black; - } - - public override Color FontColor - { - set => CurrentState.FontColor = value ?? Colors.Black; - } - - public override string FontName - { - set - { - if (value != null) - CurrentState.FontName = value; - else - CurrentState.FontName = SkiaGraphicsService.Instance.SystemFontName; - } - } - - public override float FontSize - { - set => CurrentState.FontSize = value; - } - - public override Color FillColor - { - set - { - if (_shader != null) - { - CurrentState.SetFillPaintShader(null); - _shader.Dispose(); - _shader = null; - } - - CurrentState.FillColor = value ?? Colors.White; - } - } - - public override BlendMode BlendMode - { - set - { - /* todo: implement this - CGBlendMode blendMode = CGBlendMode.Normal; - - switch (value) - { - case BlendMode.Clear: - blendMode = CGBlendMode.Clear; - break; - case BlendMode.Color: - blendMode = CGBlendMode.Color; - break; - case BlendMode.ColorBurn: - blendMode = CGBlendMode.ColorBurn; - break; - case BlendMode.ColorDodge: - blendMode = CGBlendMode.ColorDodge; - break; - case BlendMode.Copy: - blendMode = CGBlendMode.Copy; - break; - case BlendMode.Darken: - blendMode = CGBlendMode.Darken; - break; - case BlendMode.DestinationAtop: - blendMode = CGBlendMode.DestinationAtop; - break; - case BlendMode.DestinationIn: - blendMode = CGBlendMode.DestinationIn; - break; - case BlendMode.DestinationOut: - blendMode = CGBlendMode.DestinationOut; - break; - case BlendMode.DestinationOver: - blendMode = CGBlendMode.DestinationOver; - break; - case BlendMode.Difference: - blendMode = CGBlendMode.Difference; - break; - case BlendMode.Exclusion: - blendMode = CGBlendMode.Exclusion; - break; - case BlendMode.HardLight: - blendMode = CGBlendMode.HardLight; - break; - case BlendMode.Hue: - blendMode = CGBlendMode.Hue; - break; - case BlendMode.Lighten: - blendMode = CGBlendMode.Lighten; - break; - case BlendMode.Luminosity: - blendMode = CGBlendMode.Luminosity; - break; - case BlendMode.Multiply: - blendMode = CGBlendMode.Multiply; - break; - case BlendMode.Normal: - blendMode = CGBlendMode.Normal; - break; - case BlendMode.Overlay: - blendMode = CGBlendMode.Overlay; - break; - case BlendMode.PlusDarker: - blendMode = CGBlendMode.PlusDarker; - break; - case BlendMode.PlusLighter: - blendMode = CGBlendMode.PlusLighter; - break; - case BlendMode.Saturation: - blendMode = CGBlendMode.Saturation; - break; - case BlendMode.Screen: - blendMode = CGBlendMode.Screen; - break; - case BlendMode.SoftLight: - blendMode = CGBlendMode.SoftLight; - break; - case BlendMode.SourceAtop: - blendMode = CGBlendMode.SourceAtop; - break; - case BlendMode.SourceIn: - blendMode = CGBlendMode.SourceIn; - break; - case BlendMode.SourceOut: - blendMode = CGBlendMode.SourceOut; - break; - case BlendMode.XOR: - blendMode = CGBlendMode.XOR; - break; - } - - canvas.SetBlendMode(blendMode);*/ - - //CurrentState.FillPaint.SetXfermode(new - } - } - - private static SkiaCanvasState CreateNewState(object context) - { - if (_defaultFillPaint == null) - { - _defaultFillPaint = new SKPaint - { - Color = SKColors.White, - IsStroke = false, - IsAntialias = true - }; - - _defaultStrokePaint = new SKPaint - { - Color = SKColors.Black, - StrokeWidth = 1, - StrokeMiter = CanvasDefaults.DefaultMiterLimit, - IsStroke = true, - IsAntialias = true - }; - - _defaultFontPaint = new SKPaint - { - Color = SKColors.Black, - IsAntialias = true, - Typeface = SKTypeface.FromFamilyName("Arial") - }; - } - - var state = new SkiaCanvasState - { - FillPaint = _defaultFillPaint.CreateCopy(), - StrokePaint = _defaultStrokePaint.CreateCopy(), - FontPaint = _defaultFontPaint.CreateCopy(), - FontName = SkiaGraphicsService.Instance.SystemFontName - }; - - return state; - } - - public void SetDisplayScale(float value) - { - _displayScale = value; - } - - private static SkiaCanvasState CreateStateCopy(SkiaCanvasState prototype) - { - return new SkiaCanvasState(prototype); - } - - public override void Dispose() - { - _defaultFillPaint.Dispose(); - _defaultStrokePaint.Dispose(); - _defaultFontPaint.Dispose(); - - base.Dispose(); - } - - protected override void NativeSetStrokeDashPattern( - float[] pattern, - float strokeSize) - { - CurrentState.SetStrokeDashPattern(pattern, strokeSize); - } - - public override void SetToSystemFont() - { - CurrentState.FontName = SkiaGraphicsService.Instance.SystemFontName; - } - - public override void SetToBoldSystemFont() - { - CurrentState.FontName = SkiaGraphicsService.Instance.BoldSystemFontName; - } - - public override void SetFillPaint(Paint paint, RectangleF rectangle) - { - if (paint == null) - paint = Colors.White.AsPaint(); - - if (_shader != null) - { - CurrentState.SetFillPaintShader(null); - _shader.Dispose(); - _shader = null; - } - - if (paint is LinearGradientPaint linearGradientPaint) - { - float x1 = (float)(linearGradientPaint.StartPoint.X * rectangle.Width) + rectangle.X; - float y1 = (float)(linearGradientPaint.StartPoint.Y * rectangle.Height) + rectangle.Y; - - float x2 = (float)(linearGradientPaint.EndPoint.X * rectangle.Width) + rectangle.X; - float y2 = (float)(linearGradientPaint.EndPoint.Y * rectangle.Height) + rectangle.Y; - - var colors = new SKColor[linearGradientPaint.GradientStops.Length]; - var stops = new float[colors.Length]; - - var vStops = linearGradientPaint.GetSortedStops(); - - for (var i = 0; i < vStops.Length; i++) - { - colors[i] = vStops[i].Color.ToColor(CurrentState.Alpha); - stops[i] = vStops[i].Offset; - } - - try - { - CurrentState.FillColor = Colors.White; - _shader = SKShader.CreateLinearGradient( - new SKPoint(x1, y1), - new SKPoint(x2, y2), - colors, - stops, - SKShaderTileMode.Clamp); - CurrentState.SetFillPaintShader(_shader); - } - catch (Exception exc) - { - Logger.Debug(exc); - FillColor = linearGradientPaint.BlendStartAndEndColors(); - } - } - else if (paint is RadialGradientPaint radialGradientPaint) - { - var colors = new SKColor[radialGradientPaint.GradientStops.Length]; - var stops = new float[colors.Length]; - - var vStops = radialGradientPaint.GetSortedStops(); - - for (var i = 0; i < vStops.Length; i++) - { - colors[i] = vStops[i].Color.ToColor(CurrentState.Alpha); - stops[i] = vStops[i].Offset; - } - - float centerX = (float)(radialGradientPaint.Center.X * rectangle.Width) + rectangle.X; - float centerY = (float)(radialGradientPaint.Center.Y * rectangle.Height) + rectangle.Y; - float radius = (float)radialGradientPaint.Radius * Math.Max(rectangle.Height, rectangle.Width); - - if (radius == 0) - radius = Geometry.GetDistance(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); - - try - { - CurrentState.FillColor = Colors.White; - _shader = SKShader.CreateRadialGradient( - new SKPoint(centerX, centerY), - radius, - colors, - stops, - SKShaderTileMode.Clamp); - CurrentState.SetFillPaintShader(_shader); - } - catch (Exception exc) - { - Logger.Debug(exc); - FillColor = radialGradientPaint.BlendStartAndEndColors(); - } - } - else if (paint is PatternPaint patternPaint) - { - SKBitmap bitmap = patternPaint.GetPatternBitmap(DisplayScale); - - if (bitmap != null) - { - try - { - CurrentState.FillColor = Colors.White; - CurrentState.SetFillPaintFilterBitmap(true); - - _shader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat); - - //_shaderMatrix.Reset (); - //_shaderMatrix.PreScale (CurrentState.ScaleX, CurrentState.ScaleY); - //_shader.SetLocalMatrix (shaderMatrix); - - CurrentState.SetFillPaintShader(_shader); - } - catch (Exception exc) - { - Logger.Debug(exc); - FillColor = paint.BackgroundColor; - } - } - else - { - FillColor = paint.BackgroundColor; - } - } - else if (paint is ImagePaint imagePaint) - { - var image = imagePaint.Image as SkiaImage; - if (image != null) - { - SKBitmap bitmap = image.NativeImage; - - if (bitmap != null) - { - try - { - CurrentState.FillColor = Colors.White; - CurrentState.SetFillPaintFilterBitmap(true); - - _shader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat); - //_shaderMatrix.Reset (); - //_shaderMatrix.PreScale (CurrentState.ScaleX, CurrentState.ScaleY); - //_shader.SetLocalMatrix (shaderMatrix); - - CurrentState.SetFillPaintShader(_shader); - } - catch (Exception exc) - { - Logger.Debug(exc); - FillColor = paint.BackgroundColor; - } - } - else - { - FillColor = Colors.White; - } - } - else - { - FillColor = Colors.White; - } - } - else - { - FillColor = paint.BackgroundColor; - } - } - - protected override void NativeDrawLine( - float x1, - float y1, - float x2, - float y2) - { - _canvas.DrawLine(x1, y1, x2, y2, CurrentState.StrokePaintWithAlpha); - } - - protected override void NativeDrawArc( - float x, - float y, - float width, - float height, - float startAngle, - float endAngle, - bool clockwise, - bool closed) - { - while (startAngle < 0) - startAngle += 360; - - while (endAngle < 0) - endAngle += 360; - - var rectX = x; - var rectY = y; - var rectWidth = width; - var rectHeight = height; - - var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); - - var rect = new SKRect(rectX, rectY, rectX + rectWidth, rectY + rectHeight); - - startAngle *= -1; - if (!clockwise) - sweep *= -1; - - if (closed) - { - var nativePath = new SKPath(); - nativePath.AddArc(rect, startAngle, sweep); - nativePath.Close(); - _canvas.DrawPath(nativePath, CurrentState.StrokePaintWithAlpha); - nativePath.Dispose(); - } - else - { - // todo: delete this after the api is bound - var nativePath = new SKPath(); - nativePath.AddArc(rect, startAngle, sweep); - _canvas.DrawPath(nativePath, CurrentState.StrokePaintWithAlpha); - nativePath.Dispose(); - - // todo: restore this when the api is bound. - //_canvas.DrawArc (rect, startAngle, sweep, false, CurrentState.StrokePaintWithAlpha); - } - } - - public override void FillArc( - float x, - float y, - float width, - float height, - float startAngle, - float endAngle, - bool clockwise) - { - while (startAngle < 0) - startAngle += 360; - - while (endAngle < 0) - endAngle += 360; - - var sweep = Geometry.GetSweep(startAngle, endAngle, clockwise); - var rect = new SKRect(x, y, x + width, y + height); - - startAngle *= -1; - if (!clockwise) - sweep *= -1; - - // todo: delete this after the api is bound - var nativePath = new SKPath(); - nativePath.AddArc(rect, startAngle, sweep); - _canvas.DrawPath(nativePath, CurrentState.FillPaintWithAlpha); - nativePath.Dispose(); - - // todo: restore this when the api is bound. - //_canvas.DrawArc (rect, startAngle, sweep, false, CurrentState.FillPaintWithAlpha); - } - - protected override void NativeDrawRectangle( - float x, - float y, - float width, - float height) - { - float rectX = 0, rectY = 0, rectWidth = 0, rectHeight = 0; - - var strokeSize = CurrentState.ScaledStrokeSize; - if (strokeSize <= 0) - return; - - rectX = x; - rectY = y; - rectWidth = width; - rectHeight = height; - - _canvas.DrawRect(rectX, rectY, rectWidth, rectHeight, CurrentState.StrokePaintWithAlpha); - } - - public override void FillRectangle( - float x, - float y, - float width, - float height) - { - var rectX = x; - var rectY = y; - var rectWidth = width; - var rectHeight = height; - - _canvas.DrawRect(rectX, rectY, rectWidth, rectHeight, CurrentState.FillPaintWithAlpha); - } - - protected override void NativeDrawRoundedRectangle( - float x, - float y, - float width, - float height, - float aCornerRadius) - { - // These values work for a stroke location of center. - var strokeSize = CurrentState.ScaledStrokeSize; - - var rectX = x; - var rectY = y; - var rectWidth = width; - var rectHeight = height; - var radius = aCornerRadius; - - _canvas.DrawRoundRect(rectX, rectY, rectWidth, rectHeight, radius, radius, CurrentState.StrokePaintWithAlpha); - } - - public override void FillRoundedRectangle( - float x, - float y, - float width, - float height, - float aCornerRadius) - { - var rectX = x; - var rectY = y; - var rectWidth = width; - var rectHeight = height; - var radius = aCornerRadius; - - var rect = new SKRect(rectX, rectY, rectX + rectWidth, rectY + rectHeight); - _canvas.DrawRoundRect(rect, radius, radius, CurrentState.FillPaintWithAlpha); - } - - protected override void NativeDrawEllipse( - float x, - float y, - float width, - float height) - { - // These values work for a stroke location of center. - var strokeSize = CurrentState.ScaledStrokeSize; - - var rectX = x; - var rectY = y; - var rectWidth = width; - var rectHeight = height; - - var rect = new SKRect(rectX, rectY, rectX + rectWidth, rectY + rectHeight); - _canvas.DrawOval(rect, CurrentState.StrokePaintWithAlpha); - } - - public override void FillEllipse( - float x, - float y, - float width, - float height) - { - // These values work for a stroke location of center. - var rectX = x; - var rectY = y; - var rectWidth = width; - var rectHeight = height; - - var rect = new SKRect(rectX, rectY, rectX + rectWidth, rectY + rectHeight); - _canvas.DrawOval(rect, CurrentState.FillPaintWithAlpha); - } - - public override void SubtractFromClip( - float x, - float y, - float width, - float height) - { - var rect = new SKRect(x, y, x + width, y + height); - _canvas.ClipRect(rect, SKClipOperation.Difference); - } - - protected override void NativeDrawPath( - PathF path) - { - var nativePath = path.AsSkiaPath(); - _canvas.DrawPath(nativePath, CurrentState.StrokePaintWithAlpha); - nativePath.Dispose(); - } - - public override void ClipPath(PathF path, - WindingMode windingMode = WindingMode.NonZero) - { - var nativePath = path.AsSkiaPath(); - nativePath.FillType = windingMode == WindingMode.NonZero ? SKPathFillType.Winding : SKPathFillType.EvenOdd; - _canvas.ClipPath(nativePath); - } - - public override void FillPath(PathF path, - WindingMode windingMode) - { - var nativePath = path.AsSkiaPath(); - nativePath.FillType = windingMode == WindingMode.NonZero ? SKPathFillType.Winding : SKPathFillType.EvenOdd; - _canvas.DrawPath(nativePath, CurrentState.FillPaintWithAlpha); - nativePath.Dispose(); - } - - public override void DrawString( - string value, - float x, - float y, - HorizontalAlignment horizAlignment) - { - if (string.IsNullOrEmpty(value)) - return; - - if (horizAlignment == HorizontalAlignment.Left) - { - _canvas.DrawText(value, x, y, CurrentState.FontPaint); - } - else if (horizAlignment == HorizontalAlignment.Right) - { - var paint = CurrentState.FontPaint; - var width = paint.MeasureText(value); - x -= width; - _canvas.DrawText(value, x, y, CurrentState.FontPaint); - } - else - { - var paint = CurrentState.FontPaint; - var width = paint.MeasureText(value); - x -= width / 2; - _canvas.DrawText(value, x, y, CurrentState.FontPaint); - } - } - - public override void DrawString( - string value, - float x, - float y, - float width, - float height, - HorizontalAlignment horizAlignment, - VerticalAlignment vertAlignment, - TextFlow textFlow = TextFlow.ClipBounds, - float lineSpacingAdjustment = 0) - { - if (string.IsNullOrEmpty(value)) - return; - - var rect = new RectangleF(x, y, width, height); - - var attributes = new StandardTextAttributes() - { - FontSize = CurrentState.FontPaint.TextSize, - FontName = CurrentState.FontName, - HorizontalAlignment = horizAlignment, - VerticalAlignment = vertAlignment, - }; - - LayoutLine callback = ( - point, - textual, - text, - ascent, - descent, - leading) => - { - _canvas.DrawText(text, point.X, point.Y, CurrentState.FontPaint); - }; - - using (var textLayout = new SkiaTextLayout(value, rect, attributes, callback, textFlow, CurrentState.FontPaint)) - { - textLayout.LayoutText(); - } - } - - public override void DrawText(IAttributedText value, float x, float y, float width, float height) - { - Logger.Debug("Not yet implemented."); - DrawString(value?.Text, x, y, width, height, HorizontalAlignment.Left, VerticalAlignment.Top); - } - - public override void ResetState() - { - base.ResetState(); - - if (_shader != null) - { - _shader.Dispose(); - _shader = null; - } - - CurrentState.Reset(_defaultFontPaint, _defaultFillPaint, _defaultStrokePaint); - } - - public override bool RestoreState() - { - if (_shader != null) - { - _shader.Dispose(); - _shader = null; - } - - return base.RestoreState(); - } - - protected override void StateRestored(SkiaCanvasState state) - { - _canvas?.Restore(); - } - - public override void SetShadow( - SizeF offset, - float blur, - Color color) - { - var actualOffset = offset; - if (actualOffset == null) - actualOffset = CanvasDefaults.DefaultShadowOffset; - - var sx = actualOffset.Width; - var sy = actualOffset.Height; - - if (color == null) - { - var actualColor = Colors.Black.AsSKColorMultiplyAlpha(CurrentState.Alpha); - CurrentState.SetShadow(blur, sx, sy, actualColor); - } - else - { - var actualColor = color.AsSKColorMultiplyAlpha(CurrentState.Alpha); - CurrentState.SetShadow(blur, sx, sy, actualColor); - } - } - - protected override void NativeRotate( - float degrees, - float radians, - float x, - float y) - { - _canvas.RotateDegrees(degrees, x, y); - } - - protected override void NativeRotate( - float degrees, - float radians) - { - _canvas.RotateDegrees(degrees); - } - - protected override void NativeScale( - float xFactor, - float yFactor) - { - //canvas.Scale((float)aXFactor, (float)aYFactor); - CurrentState.SetScale(Math.Abs(xFactor), Math.Abs(yFactor)); - if (xFactor < 0 || yFactor < 0) - _canvas.Scale(xFactor < 0 ? -1 : 1, yFactor < 0 ? -1 : 1); - } - - protected override void NativeTranslate( - float tx, - float ty) - { - _canvas.Translate(tx * CurrentState.ScaleX, ty * CurrentState.ScaleY); - } - - protected override void NativeConcatenateTransform(AffineTransform transform) - { - var matrix = new SKMatrix(); - - var values = new float[6]; - _canvas.TotalMatrix.GetValues(values); - matrix.Values = values; - - // todo: implement me - //matrix.PostConcat (transform.AsMatrix ()); - //canvas.Matrix = matrix; - } - - public override void SaveState() - { - _canvas.Save(); - base.SaveState(); - } - - public void SetBlur(float radius) - { - CurrentState.SetBlur(radius); - } - - public override void DrawImage( - IImage image, - float x, - float y, - float width, - float height) - { - var skiaImage = image as SkiaImage; - var bitmap = skiaImage?.NativeImage; - if (bitmap != null) - { - var scaleX = CurrentState.ScaleX < 0 ? -1 : 1; - var scaleY = CurrentState.ScaleY < 0 ? -1 : 1; - - _canvas.Save(); - //canvas.Scale (scaleX, scaleY); - var srcRect = new SKRect(0, 0, bitmap.Width, bitmap.Height); - - x *= scaleX; - y *= scaleY; - width *= scaleX; - height *= scaleY; - - var rx1 = Math.Min(x, x + width); - var ry1 = Math.Min(y, y + height); - var rx2 = Math.Max(x, x + width); - var ry2 = Math.Max(y, y + height); - - var destRect = new SKRect(rx1, ry1, rx2, ry2); - var paint = CurrentState.GetImagePaint(1, 1); - _canvas.DrawBitmap(bitmap, srcRect, destRect, paint); - paint?.Dispose(); - _canvas.Restore(); - } - } - - public override void ClipRectangle( - float x, - float y, - float width, - float height) - { - _canvas.ClipRect(new SKRect(x, y, x + width, y + height)); - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvasState.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvasState.cs deleted file mode 100644 index bfc38a10a8ca..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaCanvasState.cs +++ /dev/null @@ -1,451 +0,0 @@ -using SkiaSharp; -using Color = SkiaSharp.SKColor; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaCanvasState : CanvasState, IBlurrableCanvas - { - public float Alpha = 1; - private SKPaint _fillPaint; - private SKPaint _strokePaint; - private string _fontName = "Arial"; - private SKPaint _fontPaint; - private float _fontSize = 10f; - private float _scaleX = 1; - private float _scaleY = 1; - private bool _typefaceInvalid; - private bool _isBlurred; - private float _blurRadius; - private SKMaskFilter _blurFilter; - private SKImageFilter _shadowFilter; - private bool _shadowed; - private SKColor _shadowColor; - private float _shadowX; - private float _shadowY; - private float _shadowBlur; - - private Color _strokeColor = Colors.Black; - private Color _fillColor = Colors.White; - private Color _fontColor = Colors.Black; - - public SkiaCanvasState() - { - } - - public SkiaCanvasState(SkiaCanvasState prototype) : base(prototype) - { - _strokeColor = prototype._strokeColor; - _fillColor = prototype._fillColor; - _fontColor = prototype._fontColor; - - _fontPaint = prototype.FontPaint.CreateCopy(); - _fillPaint = prototype.FillPaint.CreateCopy(); - _strokePaint = prototype.StrokePaint.CreateCopy(); - _fontName = prototype._fontName; - _fontSize = prototype._fontSize; - Alpha = prototype.Alpha; - _scaleX = prototype._scaleX; - _scaleY = prototype._scaleY; - _typefaceInvalid = false; - - _isBlurred = prototype._isBlurred; - _blurRadius = prototype._blurRadius; - - _shadowed = prototype._shadowed; - //_shadowFilter = prototype._shadowFilter; // There is no reason the copy really needs to know about this. - _shadowColor = prototype._shadowColor; - _shadowX = prototype._shadowX; - _shadowY = prototype._shadowY; - _shadowBlur = prototype._shadowBlur; - } - - public Color StrokeColor - { - get => _strokeColor; - set => _strokeColor = value; - } - - public Color FillColor - { - get => _fillColor; - set - { - FillPaint.Shader = null; - _fillColor = value; - } - } - - public Color FontColor - { - get => _fontColor; - set - { - _fontColor = value; - if (value != null) - FontPaint.Color = _fontColor.AsSKColor(); - else - FontPaint.Color = SKColors.Black; - } - } - - public LineCap StrokeLineCap - { - set - { - if (value == LineCap.Butt) - StrokePaint.StrokeCap = SKStrokeCap.Butt; - else if (value == LineCap.Round) - StrokePaint.StrokeCap = SKStrokeCap.Round; - else if (value == LineCap.Square) - StrokePaint.StrokeCap = SKStrokeCap.Square; - } - } - - public LineJoin StrokeLineJoin - { - set - { - if (value == LineJoin.Miter) - StrokePaint.StrokeJoin = SKStrokeJoin.Miter; - else if (value == LineJoin.Round) - StrokePaint.StrokeJoin = SKStrokeJoin.Round; - else if (value == LineJoin.Bevel) - StrokePaint.StrokeJoin = SKStrokeJoin.Bevel; - } - } - - public float MiterLimit - { - set => StrokePaint.StrokeMiter = value; - } - - public void SetStrokeDashPattern(float[] pattern, float strokeSize) - { - if (pattern == null || pattern.Length == 0 || strokeSize == 0) - { - StrokePaint.PathEffect = null; - } - else - { - float scaledStrokeSize = strokeSize * ScaleX; - - if (scaledStrokeSize > 1 || scaledStrokeSize < 1) - { - var scaledPattern = new float[pattern.Length]; - for (var i = 0; i < pattern.Length; i++) - scaledPattern[i] = pattern[i] * scaledStrokeSize; - StrokePaint.PathEffect = SKPathEffect.CreateDash(scaledPattern, 0); - } - else - { - StrokePaint.PathEffect = SKPathEffect.CreateDash(pattern, 0); - } - } - } - - public bool AntiAlias - { - set => StrokePaint.IsAntialias = value; - } - - public bool IsBlurred => _isBlurred; - - public float BlurRadius => _blurRadius; - - public void SetBlur(float radius) - { - if (radius != _blurRadius) - { - if (_blurFilter != null) - { - _blurFilter.Dispose(); - _blurFilter = null; - } - - if (radius > 0) - { - _isBlurred = true; - _blurRadius = radius; - _blurFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, _blurRadius); - - if (_fillPaint != null) _fillPaint.MaskFilter = _blurFilter; - if (_strokePaint != null) _strokePaint.MaskFilter = _blurFilter; - if (_fontPaint != null) _fontPaint.MaskFilter = _blurFilter; - } - else - { - _isBlurred = false; - _blurRadius = 0; - - if (_fillPaint != null) _fillPaint.MaskFilter = null; - if (_strokePaint != null) _strokePaint.MaskFilter = null; - if (_fontPaint != null) _fontPaint.MaskFilter = null; - } - } - } - - public float NativeStrokeSize - { - set => StrokePaint.StrokeWidth = value * _scaleX; - } - - public float FontSize - { - set - { - _fontSize = value; - FontPaint.TextSize = _fontSize * _scaleX; - } - } - - public string FontName - { - set - { - if (_fontName != value && (_fontName != null && !_fontName.Equals(value))) - { - _fontName = value; - _typefaceInvalid = true; - } - } - - get => _fontName; - } - - public SKPaint FontPaint - { - get - { - if (_fontPaint == null) - { - _fontPaint = new SKPaint - { - Color = SKColors.Black, - IsAntialias = true, - Typeface = SkiaDelegatingFontService.Instance.GetTypeface(SkiaGraphicsService.Instance.SystemFontName) - }; - } - - if (_typefaceInvalid) - { - _fontPaint.Typeface = SkiaDelegatingFontService.Instance.GetTypeface(_fontName); - _typefaceInvalid = false; - } - - return _fontPaint; - } - - set => _fontPaint = value; - } - - public SKPaint FillPaint - { - private get - { - return _fillPaint - ?? (_fillPaint = new SKPaint - { - Color = SKColors.White, - IsStroke = false, - IsAntialias = true - }); - } - - set { _fillPaint = value; } - } - - public SKPaint StrokePaint - { - private get - { - if (_strokePaint == null) - { - var paint = new SKPaint - { - Color = SKColors.Black, - StrokeWidth = 1, - StrokeMiter = CanvasDefaults.DefaultMiterLimit, - IsStroke = true, - IsAntialias = true - }; - - _strokePaint = paint; - - return paint; - } - - return _strokePaint; - } - - set { _strokePaint = value; } - } - - public SKPaint StrokePaintWithAlpha - { - get - { - var paint = StrokePaint; - - var r = (byte) (_strokeColor.Red * 255f); - var g = (byte) (_strokeColor.Green * 255f); - var b = (byte) (_strokeColor.Blue * 255f); - var a = (byte) (_strokeColor.Alpha * 255f * Alpha); - - paint.Color = new SKColor(r, g, b, a); - return paint; - } - } - - public SKPaint FillPaintWithAlpha - { - get - { - var paint = FillPaint; - - var r = (byte) (_fillColor.Red * 255f); - var g = (byte) (_fillColor.Green * 255f); - var b = (byte) (_fillColor.Blue * 255f); - var a = (byte) (_fillColor.Alpha * 255f * Alpha); - - paint.Color = new SKColor(r, g, b, a); - return paint; - } - } - - public void SetFillPaintShader(SKShader shader) - { - FillPaint.Shader = shader; - } - - public void SetFillPaintFilterBitmap(bool value) - { - // todo: restore this - //FillPaint.FilterBitmap = value; - } - - public float ScaledStrokeSize => StrokeSize * _scaleX; - - public float ScaledFontSize => _fontSize * _scaleX; - - public float ScaleX => _scaleX; - - public float ScaleY => _scaleY; - - #region IDisposable Members - - public override void Dispose() - { - _fontPaint?.Dispose(); - _fontPaint = null; - - _strokePaint?.Dispose(); - _strokePaint = null; - - _fillPaint?.Dispose(); - _fillPaint = null; - - _shadowFilter?.Dispose(); - _shadowFilter = null; - - _blurFilter?.Dispose(); - _blurFilter = null; - - base.Dispose(); - } - - #endregion - - public void SetShadow(float blur, float sx, float sy, SKColor color) - { -#pragma warning disable CS0618 - _shadowFilter = SKImageFilter.CreateDropShadow(sx, sy, blur, blur, color, SKDropShadowImageFilterShadowMode.DrawShadowAndForeground); -#pragma warning restore CS0618 - FillPaint.ImageFilter = _shadowFilter; - StrokePaint.ImageFilter = _shadowFilter; - FontPaint.ImageFilter = _shadowFilter; - - _shadowed = true; - _shadowBlur = blur; - _shadowX = sx; - _shadowY = sy; - _shadowColor = color; - } - - public SKPaint GetShadowPaint(float sx, float sy) - { - if (_shadowed) - { - var shadowPaint = new SKPaint - { - Color = SKColors.Black, - IsStroke = false, - IsAntialias = true - }; - - // todo: implement me - shadowPaint.ImageFilter = _shadowFilter; - //shadowPaint.SetShadowLayer(shadowBlur, shadowX * sx, shadowY * sy, shadowColor); - //shadowPaint.Alpha = (int) (Alpha*255f); - return shadowPaint; - } - - return null; - } - - public SKPaint GetImagePaint(float sx, float sy) - { - var imagePaint = new SKPaint - { - Color = SKColors.Black, - IsStroke = false, - IsAntialias = true - }; - - if (Alpha < 1) - { - var color = new SKColor(255, 255, 255, (byte) (Alpha * 255f)); - imagePaint.ColorFilter = SKColorFilter.CreateBlendMode(color, SKBlendMode.Modulate); - } - - if (_isBlurred) - imagePaint.MaskFilter = _blurFilter; - - return imagePaint; - } - - public void SetScale(float sx, float sy) - { - _scaleX = _scaleX * sx; - _scaleY = _scaleY * sy; - - StrokePaint.StrokeWidth = StrokeSize * _scaleX; - FontPaint.TextSize = _fontSize * _scaleX; - } - - public void Reset(SKPaint fontPaint, SKPaint fillPaint, SKPaint strokePaint) - { - _fontPaint?.Dispose(); - _fontPaint = fontPaint.CreateCopy(); - - _fillPaint?.Dispose(); - _fillPaint = fillPaint.CreateCopy(); - - _strokePaint?.Dispose(); - _strokePaint = strokePaint.CreateCopy(); - - _shadowFilter?.Dispose(); - _shadowFilter = null; - - _blurFilter?.Dispose(); - _blurFilter = null; - - _fontName = "Arial"; - _fontSize = 10f; - Alpha = 1; - _scaleX = 1; - _scaleY = 1; - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaDelegatingFontService.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaDelegatingFontService.cs deleted file mode 100644 index 8b80b832ef66..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaDelegatingFontService.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Collections.Generic; -using SkiaSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaDelegatingFontService : AbstractFontService - { - public static SkiaDelegatingFontService Instance = new SkiaDelegatingFontService(); - - private readonly Dictionary _typeFaces = new Dictionary(); - - public override IFontFamily[] GetFontFamilies() - { - var nativeFontService = Fonts.GlobalService; - return nativeFontService.GetFontFamilies(); - } - - public SKTypeface GetTypeface(string name) - { - var nativeFontService = Fonts.GlobalService; - - if (string.IsNullOrEmpty(name)) - { - var style = nativeFontService.GetDefaultFontStyle(); - name = style.Name; - } - - if (!_typeFaces.TryGetValue(name, out var typeface)) - { - try - { - var fontStyle = nativeFontService.GetFontStyleById(name); - - var stream = fontStyle?.OpenStream(); - if (stream != null) - { - typeface = SKTypeface.FromStream(new SKManagedStream(stream)); - } - else if (fontStyle != null) - { - var slant = SKFontStyleSlant.Upright; - if (fontStyle.StyleType == FontStyleType.Italic) - slant = SKFontStyleSlant.Italic; - else if (fontStyle.StyleType == FontStyleType.Oblique) - slant = SKFontStyleSlant.Oblique; - - typeface = SKTypeface.FromFamilyName(fontStyle.FontFamily.Name, fontStyle.Weight, (int) SKFontStyleWidth.Normal, slant); - } - - if (typeface != null) - _typeFaces[name] = typeface; - } - catch (Exception exc) - { - Logger.Info("Unable to load typeface [{0}]" + name, exc); - } - } - - return typeface; - } - - public void ClearFontCache() - { - foreach (var entry in _typeFaces) - { - try - { - entry.Value.Dispose(); - } - catch (Exception exc) - { - Logger.Info("Unable to dispose of a typeface", exc); - } - } - - _typeFaces.Clear(); - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontFamily.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontFamily.cs deleted file mode 100644 index 4cf61b4492ea..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontFamily.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaFontFamily : IFontFamily, IComparable, IComparable - { - private readonly string _name; - private IFontStyle[] _fontStyles; - - public SkiaFontFamily(string name) - { - _name = name; - } - - public string Name => _name; - - public IFontStyle[] GetFontStyles() - { - return _fontStyles ?? (_fontStyles = InitializeFontStyles()); - } - - private IFontStyle[] InitializeFontStyles() - { - var styles = new List(); - - styles.Add( - new SkiaFontStyle( - this, - _name, - _name, - _name, - FontUtils.Normal, - FontStyleType.Normal)); - - styles.Sort(); - return styles.ToArray(); - } - - public override bool Equals(object obj) - { - if (obj == null) - return false; - if (ReferenceEquals(this, obj)) - return true; - if (obj.GetType() != typeof(SkiaFontFamily)) - return false; - SkiaFontFamily other = (SkiaFontFamily) obj; - return _name == other._name; - } - - public override int GetHashCode() - { - return (_name != null ? _name.GetHashCode() : 0); - } - - public override string ToString() - { - return Name; - } - - public int CompareTo(IFontFamily other) - { - return string.Compare(_name, other.Name, StringComparison.Ordinal); - } - - public int CompareTo(object obj) - { - if (obj is IFontFamily other) - return CompareTo(other); - - return -1; - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontService.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontService.cs deleted file mode 100644 index dd322fa41437..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontService.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using SkiaSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaFontService : AbstractFontService - { - private readonly Dictionary _typeFaces = new Dictionary(); - private readonly IFontFamily[] _fontFamilies; - private readonly string _systemFontName; - private readonly string _boldSystemFontName; - - public SkiaFontService(string systemFontName, string boldSystemFontName) - { - _systemFontName = systemFontName; - _boldSystemFontName = boldSystemFontName; - - _fontFamilies = InitializeFontFamilies(); - } - - public override IFontFamily[] GetFontFamilies() - { - return _fontFamilies; - } - - public SKTypeface GetTypeface(string name) - { - if (string.IsNullOrEmpty(name)) - name = _systemFontName; - - if (!_typeFaces.TryGetValue(name, out var typeface)) - { - try - { - typeface = SKTypeface.FromFamilyName(name); - - if (typeface != null) - _typeFaces[name] = typeface; - } - catch (Exception exc) - { - typeface = SKTypeface.FromFamilyName(_systemFontName); - Logger.Info("Unable to load typeface [{0}]" + name, exc); - } - } - - return typeface; - } - - public void ClearFontCache() - { - foreach (var entry in _typeFaces) - { - try - { - entry.Value.Dispose(); - } - catch (Exception exc) - { - Logger.Info("Unable to dispose of a typeface", exc); - } - } - - _typeFaces.Clear(); - } - - public IFontFamily[] InitializeFontFamilies() - { - var familyNames = SKFontManager.Default.GetFontFamilies(); - - var families = new List(); - - foreach (var familyName in familyNames) - { - var family = new SkiaFontFamily(familyName); - if (family.GetFontStyles().Length > 0) - families.Add(family); - } - - families.Sort(); - return families.ToArray(); - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontStyle.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontStyle.cs deleted file mode 100644 index 5a6ea9666f41..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaFontStyle.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaFontStyle : IFontStyle - { - private readonly SkiaFontFamily _family; - - public SkiaFontStyle(SkiaFontFamily family, string id, string name, string fullName, int weight, FontStyleType styleType) - { - _family = family; - Id = id; - Name = name; - FullName = fullName; - Weight = weight; - StyleType = styleType; - } - - public IFontFamily FontFamily => _family; - - public string Id { get; } - - public string Name { get; } - - public string FullName { get; } - - public int Weight { get; } - - public FontStyleType StyleType { get; } - - public override bool Equals(object obj) - { - if (obj == null) - return false; - if (ReferenceEquals(this, obj)) - return true; - if (obj.GetType() != typeof(SkiaFontStyle)) - return false; - SkiaFontStyle other = (SkiaFontStyle) obj; - return Id == other.Id; - } - - public override int GetHashCode() - { - return (Id != null ? Id.GetHashCode() : 0); - } - - public override string ToString() - { - return Name; - } - - public int CompareTo(IFontStyle other) - { - if (Name.Equals("Regular") || Name.Equals("Plain") || Name.Equals("Normal")) - { - return -1; - } - else if (other.Name.Equals("Regular") || other.Name.Equals("Plain") || other.Name.Equals("Normal")) - { - return 1; - } - - return String.Compare(Name, other.Name, StringComparison.Ordinal); - } - - public System.IO.Stream OpenStream() - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs deleted file mode 100644 index a1f7b6644cb8..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaGraphicsService.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System.IO; -using SkiaSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaGraphicsService : IGraphicsService - { - public static readonly SkiaGraphicsService Instance = new SkiaGraphicsService(); - - private static SKPaint _strokePaint; - private static SKPaint _fillPaint; - private static SKBitmap _b; - - private SkiaGraphicsService() - { - if (_strokePaint == null) - { - _strokePaint = new SKPaint - { - Color = SKColors.White, - IsStroke = true - }; - - _fillPaint = new SKPaint - { - Color = SKColors.White, - IsStroke = false - }; - - _b = new SKBitmap(1, 1, SKColorType.Rgba8888, SKAlphaType.Premul); - } - } - - public string SystemFontName => "Arial"; - public string BoldSystemFontName => "Arial-Bold"; - - public IImage LoadImageFromStream(Stream stream, ImageFormat formatHint = ImageFormat.Png) - { - using (var s = new SKManagedStream(stream)) - { - using (var codec = SKCodec.Create(s)) - { - var info = codec.Info; - var bitmap = new SKBitmap(info.Width, info.Height, info.ColorType, info.IsOpaque ? SKAlphaType.Opaque : SKAlphaType.Premul); - - var result = codec.GetPixels(bitmap.Info, bitmap.GetPixels(out _)); - if (result == SKCodecResult.Success || result == SKCodecResult.IncompleteInput) - { - return new SkiaImage(bitmap); - } - } - } - - return null; - } - - public SizeF GetStringSize(string value, string fontName, float fontSize) - { - if (string.IsNullOrEmpty(value)) - return new SizeF(); - - var paint = new SKPaint - { - Typeface = SkiaDelegatingFontService.Instance.GetTypeface(fontName), - TextSize = fontSize - }; - var width = paint.MeasureText(value); - paint.Dispose(); - return new SizeF(width, fontSize); - } - - public SizeF GetStringSize(string value, string fontName, float fontSize, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) - { - if (string.IsNullOrEmpty(value)) - return new SizeF(); - - var paint = new SKPaint - { - TextSize = fontSize, - Typeface = SkiaDelegatingFontService.Instance.GetTypeface(fontName) - }; - var width = paint.MeasureText(value); - paint.Dispose(); - return new SizeF(width, fontSize); - } - - public BitmapExportContext CreateBitmapExportContext(int width, int height, float displayScale = 1) - { - return new SkiaBitmapExportContext(width, height, displayScale, 72, false); - } - - public RectangleF GetPathBounds(PathF path) - { - return path.GetBoundsByFlattening(); - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaImage.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaImage.cs deleted file mode 100644 index 4bdd84e82b66..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaImage.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using SkiaSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaImage : IImage - { - private SKBitmap _image; - - public SkiaImage(SKBitmap image) - { - _image = image; - } - - public float Width => _image.Width; - - public float Height => _image.Height; - - public IImage Downsize(float maxWidthOrHeight, bool disposeOriginal = false) - { - // todo: implement - /* - var downsizedImage = image.Downsize ((int)maxWidthOrHeight, disposeOriginal); - return new MDImage (downsizedImage); - */ - return null; - } - - public IImage Downsize(float maxWidth, float maxHeight, bool disposeOriginal = false) - { - /* - var downsizedImage = image.Downsize ((int)maxWidth, (int)maxHeight, disposeOriginal); - return new MDImage (downsizedImage); - */ - return null; - } - - public IImage Resize(float width, float height, ResizeMode resizeMode = ResizeMode.Fit, bool disposeOriginal = false) - { - using (var context = new SkiaBitmapExportContext((int) width, (int) height, 1)) - { - var fx = width / Width; - var fy = height / Height; - - var w = Width; - var h = Height; - - var x = 0f; - var y = 0f; - - if (resizeMode == ResizeMode.Fit) - { - if (fx < fy) - { - w *= fx; - h *= fx; - } - else - { - w *= fy; - h *= fy; - } - - x = (width - w) / 2; - y = (height - h) / 2; - } - else if (resizeMode == ResizeMode.Bleed) - { - if (fx > fy) - { - w *= fx; - h *= fx; - } - else - { - w *= fy; - h *= fy; - } - - x = (width - w) / 2; - y = (height - h) / 2; - } - else - { - w = width; - h = height; - } - - context.Canvas.DrawImage(this, x, y, w, h); - return context.Image; - } - } - - public SKBitmap NativeImage => _image; - - public void Save(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1) - { - throw new NotImplementedException(); - // todo: implement me - - /* - switch (format) - { - case ImageFormat.Jpeg: - image.Compress (Bitmap.CompressFormat.Jpeg, (int)(quality * 100), stream); - break; - default: - image.Compress (Bitmap.CompressFormat.Png, 100, stream); - break; - } - */ - } - - public Task SaveAsync(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1) - { - throw new NotImplementedException(); - // todo: implement me - - /* - switch (format) - { - case ImageFormat.Jpeg: - await image.CompressAsync (Bitmap.CompressFormat.Jpeg, (int)(quality * 100), stream); - break; - default: - await image.CompressAsync (Bitmap.CompressFormat.Png, 100, stream); - break; - } - */ - } - - public void Dispose() - { - var previousValue = Interlocked.Exchange(ref _image, null); - previousValue?.Dispose(); - } - - public void Draw(ICanvas canvas, RectangleF dirtyRect) - { - canvas.DrawImage(this, dirtyRect.Left, dirtyRect.Top, (float)Math.Round(dirtyRect.Width), (float)Math.Round(dirtyRect.Height)); - } - } - - public static class SkiaImageExtensions - { - public static SKBitmap AsBitmap(this IImage image) - { - if (image is SkiaImage skiaImage) - return skiaImage.NativeImage; - - if (image != null) - Logger.Warn("SkiaImageExtensions.AsBitmap: Unable to get SKBitmap from Image. Expected an image of type SkiaImage however an image of type {0} was received.", image.GetType()); - - return null; - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaTextLayout.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaTextLayout.cs deleted file mode 100644 index 8178f6ee5db4..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/SkiaTextLayout.cs +++ /dev/null @@ -1,266 +0,0 @@ -using System; -using System.Collections.Generic; -using SkiaSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia -{ - public class SkiaTextLayout : IDisposable - { - private readonly LayoutLine _callback; - private readonly RectangleF _rect; - private readonly ITextAttributes _textAttributes; - private readonly string _value; - private readonly TextFlow _textFlow; - private readonly SKPaint _paint; - private readonly bool _disposePaint; - private readonly float _lineHeight; - private readonly float _descent; - - public bool WordWrap { get; set; } = true; - - public SkiaTextLayout( - string value, - RectangleF rect, - ITextAttributes textAttributes, - LayoutLine callback, - TextFlow textFlow = TextFlow.ClipBounds, - SKPaint paint = null) - { - _value = value; - _textAttributes = textAttributes; - _rect = rect; - _callback = callback; - _textFlow = textFlow; - _paint = paint; - - if (paint == null) - { - _paint = new SKPaint() - { - Typeface = SkiaDelegatingFontService.Instance.GetTypeface(_textAttributes.FontName), - TextSize = _textAttributes.FontSize - }; - - _disposePaint = true; - } - - var metrics = _paint.FontMetrics; - _descent = metrics.Descent; - _lineHeight = _paint.FontSpacing; - } - - public void LayoutText() - { - if (string.IsNullOrEmpty(_value)) - return; - - var x = _rect.X; - var y = _rect.Y; - var width = _rect.Width; - var height = _rect.Height; - - x += _textAttributes.Margin; - y += _textAttributes.Margin; - width -= (_textAttributes.Margin * 2); - height -= (_textAttributes.Margin * 2); - - var top = y; - var bottom = y + height; - - if (_textAttributes.HorizontalAlignment == HorizontalAlignment.Right) - _paint.TextAlign = SKTextAlign.Right; - else if (_textAttributes.HorizontalAlignment == HorizontalAlignment.Center) - _paint.TextAlign = SKTextAlign.Center; - - var lines = CreateLines(y, bottom, width); - switch (_textAttributes.VerticalAlignment) - { - case VerticalAlignment.Center: - LayoutCenterAligned(lines, x, width, top, height); - break; - case VerticalAlignment.Bottom: - LayoutBottomAligned(lines, x, width, bottom, top); - break; - default: - LayoutTopAligned(lines, x, y, width); - break; - } - - _paint.TextAlign = SKTextAlign.Left; - } - - private void LayoutCenterAligned( - List lines, - float x, - float width, - float top, - float height) - { - var linesToDraw = lines.Count; - - if (_textFlow == TextFlow.ClipBounds) - { - var maxLines = Math.Floor(height / _lineHeight); - linesToDraw = (int) Math.Min(maxLines, lines.Count); - } - - // Figure out the vertical center of the rect - var y = top + height / 2; - - // Figure out the center index of the list, and the center point to start drawing from. - var startIndex = (lines.Count / 2); - if (linesToDraw % 2 == 0) - y -= _lineHeight / 2; - - // Figure out which index to draw first (of the range) and the point of the first line. - for (var i = 0; i < linesToDraw / 2; i++) - { - y -= _lineHeight; - startIndex--; - } - - y -= _descent; - - // Draw each line. - for (var i = 0; i < linesToDraw; i++) - { - y += _lineHeight; - var line = lines[i + startIndex]; - - var point = new PointF(x, y); - switch (_textAttributes.HorizontalAlignment) - { - case HorizontalAlignment.Center: - point.X = x + width / 2; - break; - case HorizontalAlignment.Right: - point.X = x + width; - break; - } - - _callback(point, _textAttributes, line.Value, 0, 0, 0); - } - } - - private void LayoutBottomAligned( - List lines, - float x, - float width, - float bottom, - float top) - { - var y = bottom - _descent; - - for (int i = lines.Count - 1; i >= 0; i--) - { - var line = lines[i]; - - if (_textFlow == TextFlow.ClipBounds && y - _lineHeight < top) - return; - - var point = new PointF(x, y); - switch (_textAttributes.HorizontalAlignment) - { - case HorizontalAlignment.Center: - point.X = x + width / 2; - break; - case HorizontalAlignment.Right: - point.X = x + width; - break; - } - - _callback(point, _textAttributes, line.Value, 0, 0, 0); - - y -= _lineHeight; - } - } - - private void LayoutTopAligned( - List lines, - float x, - float y, - float width) - { - y -= _descent; - - foreach (var line in lines) - { - y += _lineHeight; - - var point = new PointF(x, y); - switch (_textAttributes.HorizontalAlignment) - { - case HorizontalAlignment.Center: - point.X = x + width / 2; - break; - case HorizontalAlignment.Right: - point.X = x + width; - break; - } - - _callback(point, _textAttributes, line.Value, 0, 0, 0); - } - } - - private List CreateLines(float y, float bottom, float width) - { - var lines = new List(); - - var index = 0; - var length = _value.Length; - while (index < length) - { - y += _lineHeight; - - if (_textFlow == TextFlow.ClipBounds && _textAttributes.VerticalAlignment == VerticalAlignment.Top && y > bottom) - return lines; - - var count = (int) _paint.BreakText(_value.Substring(index), width, out var textWidth); - - var found = false; - if (WordWrap && index + count < length) - { - for (var i = index + count - 1; i >= index && !found; i--) - { - if (char.IsWhiteSpace(_value[i])) - { - count = i - index + 1; - found = true; - } - } - } - - var line = _value.Substring(index, count); - if (found) - textWidth = _paint.MeasureText(line); - lines.Add(new TextLine(line, textWidth)); - - index += count; - } - - return lines; - } - - public void Dispose() - { - if (_disposePaint) - _paint?.Dispose(); - } - } - - public class TextLine - { - public string Value { get; } - public float Width { get; } - - public TextLine( - string value, - float width) - { - Value = value; - Width = width; - } - } -} diff --git a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/Views/SkiaGraphicsView.Tizen.cs b/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/Views/SkiaGraphicsView.Tizen.cs deleted file mode 100644 index 43e5c97a88d4..000000000000 --- a/src/Core/src/Platform/Tizen/Microsoft.Maui.Graphics.Skia/Views/SkiaGraphicsView.Tizen.cs +++ /dev/null @@ -1,45 +0,0 @@ -using ElmSharp; -using SkiaSharp.Views.Tizen; -using Tizen.UIExtensions.ElmSharp; - -#nullable disable - -namespace Microsoft.Maui.Graphics.Skia.Views -{ - public class SkiaGraphicsView : SKCanvasView - { - private IDrawable _drawable; - private SkiaCanvas _canvas; - private ScalingCanvas _scalingCanvas; - - public SkiaGraphicsView(EvasObject parent, IDrawable drawable = null) : base(parent) - { - _canvas = new SkiaCanvas(); - _scalingCanvas = new ScalingCanvas(_canvas); - _scalingCanvas.Scale((float)DeviceInfo.ScalingFactor, (float)DeviceInfo.ScalingFactor); - Drawable = drawable; - PaintSurface += OnPaintSurface; - } - - public IDrawable Drawable - { - get => _drawable; - set - { - _drawable = value; - Invalidate(); - } - } - - protected virtual void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) - { - if (_drawable == null) return; - - var skiaCanvas = e.Surface.Canvas; - skiaCanvas.Clear(); - - _canvas.Canvas = skiaCanvas; - _drawable.Draw(_scalingCanvas, new RectangleF(0, 0, (float)GetSurfaceSize().Width.ToScaledDP(), (float)GetSurfaceSize().Height.ToScaledDP())); - } - } -} From 0185ef8e9478eedaaaacdd79bfc9d317e1d0efdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 20 Jul 2021 15:51:51 +0900 Subject: [PATCH 025/266] Add Essentials.Samples.Tizen (#24) * Add Essentials.Samples.Tizen * Add guard for null exception * Fix Essentials.Samples for Tizen * Fix csproj for net6 * Remove Forms.Init --- Microsoft.Maui.Tizen.sln | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Microsoft.Maui.Tizen.sln b/Microsoft.Maui.Tizen.sln index 4e8bf48e8000..53f703a58728 100644 --- a/Microsoft.Maui.Tizen.sln +++ b/Microsoft.Maui.Tizen.sln @@ -118,6 +118,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.SourceGen", "src\C EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Sample.Tizen", "src\Controls\samples\Controls.Sample.Tizen\Controls.Sample.Tizen.csproj", "{4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.Samples.Tizen", "src\Essentials\samples\Samples.Tizen\Essentials.Samples.Tizen.csproj", "{64483F36-30C0-412D-8230-F69669486F8A}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Compatibility\ControlGallery\src\Issues.Shared\Compatibility.ControlGallery.Issues.Shared.projitems*{ae2513cb-4e5e-4e5c-8237-88954d4c9433}*SharedItemsImports = 13 @@ -862,6 +864,34 @@ Global {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x64.Build.0 = Release|Any CPU {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x86.ActiveCfg = Release|Any CPU {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x86.Build.0 = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|ARM.Build.0 = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|ARM64.Build.0 = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|iPhone.Build.0 = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|x64.ActiveCfg = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|x64.Build.0 = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|x86.ActiveCfg = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Debug|x86.Build.0 = Debug|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|Any CPU.Build.0 = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|ARM.ActiveCfg = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|ARM.Build.0 = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|ARM64.ActiveCfg = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|ARM64.Build.0 = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|iPhone.ActiveCfg = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|iPhone.Build.0 = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|x64.ActiveCfg = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|x64.Build.0 = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|x86.ActiveCfg = Release|Any CPU + {64483F36-30C0-412D-8230-F69669486F8A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -907,6 +937,7 @@ Global {9FAA9654-80E6-4664-9702-47998A04E8FE} = {29AC50BF-B4FB-450B-9386-0C5AD4B84226} {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6} = {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} + {64483F36-30C0-412D-8230-F69669486F8A} = {5817A848-0B04-4035-9F7E-B8621B61CBDD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {650AE971-2F29-46A8-822C-FB4FCDC6A9A0} From f3622e36ca8f05cf8fdcbe0d7adbd56d42920f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 20 Jul 2021 20:08:15 +0900 Subject: [PATCH 026/266] Fix build error (#60) --- src/Core/src/Animations/NativeTicker.Tizen.cs | 4 ++-- src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs | 2 +- src/Core/src/Platform/Tizen/CoreUIAppContext.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Core/src/Animations/NativeTicker.Tizen.cs b/src/Core/src/Animations/NativeTicker.Tizen.cs index 6d7fc0495fae..2cba99d1f71c 100644 --- a/src/Core/src/Animations/NativeTicker.Tizen.cs +++ b/src/Core/src/Animations/NativeTicker.Tizen.cs @@ -19,7 +19,7 @@ public NativeTicker() } _context = SynchronizationContext.Current; - _timer = new Timer((object o) => HandleElapsed(o), this, Timeout.Infinite, Timeout.Infinite); + _timer = new Timer((object? o) => HandleElapsed(o), this, Timeout.Infinite, Timeout.Infinite); } public override void Start() @@ -34,7 +34,7 @@ public override void Stop() _isRunning = false; } - void HandleElapsed(object state) + void HandleElapsed(object? state) { _context?.Post((o) => Fire?.Invoke(), null); } diff --git a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs index cca13b0441e3..7d0ab354af43 100644 --- a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs +++ b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs @@ -243,7 +243,7 @@ void OnCursorChanged(object? sender, EventArgs e) VirtualView.CursorPosition = position; } - void OnSelectionCleared(object sender, EventArgs e) + void OnSelectionCleared(object? sender, EventArgs e) { if (VirtualView == null || NativeView == null) return; diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index f6eca62286bf..323c302b34dd 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -177,7 +177,7 @@ void InitializeMainWindow() MainWindow.BackButtonPressed += OnBackButtonPressed; } - void OnBackButtonPressed(object sender, EventArgs e) + void OnBackButtonPressed(object? sender, EventArgs e) { if (!(_handleBackButtonPressed?.Invoke() ?? false)) { From d299c22e8e1062897924b02ebd10e06ce9ef4b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 21 Jul 2021 09:42:06 +0900 Subject: [PATCH 027/266] Update referenced Tizen.UIExtensions version (#61) --- src/Core/src/Handlers/Image/ImageHandler.Tizen.cs | 1 + src/Core/src/Platform/Tizen/CoreUIAppContext.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs b/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs index 3fed30215bc7..f0604f542f4b 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs @@ -1,4 +1,5 @@ #nullable enable +using System; using System.Threading.Tasks; using Tizen.UIExtensions.Common; using Tizen.UIExtensions.ElmSharp; diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index 323c302b34dd..d6641f4f168e 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -5,6 +5,7 @@ using ElmSharp; using ElmSharp.Wearable; using Tizen.UIExtensions.ElmSharp; +using Tizen.UIExtensions.Common; using ELayout = ElmSharp.Layout; namespace Microsoft.Maui From 97a59da43237fd349828c483abf7089c055671c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 21 Jul 2021 17:29:33 +0900 Subject: [PATCH 028/266] Add BlazorWebView skeleton code (#62) --- .../src/Maui/Tizen/WebViewExtension.cs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs diff --git a/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs b/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs new file mode 100644 index 000000000000..672b21282ed4 --- /dev/null +++ b/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs @@ -0,0 +1,69 @@ +using System; +using System.Runtime.InteropServices; +using TWebView = Tizen.WebView.WebView; + +namespace Microsoft.AspNetCore.Components.WebView.Maui +{ + public static class WebViewExtension + { + public const string ChromiumEwk = "libchromium-ewk.so"; + + public static void SetInterceptRequestCallback(this TWebView webView, InterceptRequestCallback callback) + { + var context = webView.GetContext(); + var handleField = context.GetType().GetField("_handle", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var contextHandle = (IntPtr?)handleField?.GetValue(context); + if (contextHandle != null) + ewk_context_intercept_request_callback_set(contextHandle.Value, callback, IntPtr.Zero); + } + +#pragma warning disable IDE0060 // Remove unused parameter + public static bool SetInterceptRequestResponse(this TWebView webView, IntPtr request, string header, string body, uint length) +#pragma warning restore IDE0060 // Remove unused parameter + { + return ewk_intercept_request_response_set(request, header, body, length); + } + +#pragma warning disable IDE0060 // Remove unused parameter + public static bool IgnoreInterceptRequest(this TWebView webView, IntPtr request) +#pragma warning restore IDE0060 // Remove unused parameter + { + return ewk_intercept_request_ignore(request); + } + +#pragma warning disable IDE0060 // Remove unused parameter + public static string GetInterceptRequestUrl(this TWebView webView, IntPtr request) +#pragma warning restore IDE0060 // Remove unused parameter + { + return Marshal.PtrToStringAnsi(_ewk_intercept_request_url_get(request)) ?? string.Empty; + } + + [DllImport(ChromiumEwk)] + internal static extern IntPtr ewk_view_context_get(IntPtr obj); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void InterceptRequestCallback(IntPtr context, IntPtr request, IntPtr userData); + + [DllImport(ChromiumEwk)] + internal static extern void ewk_context_intercept_request_callback_set(IntPtr context, InterceptRequestCallback callback, IntPtr userData); + + [DllImport(ChromiumEwk, EntryPoint = "ewk_intercept_request_url_get")] + internal static extern IntPtr _ewk_intercept_request_url_get(IntPtr request); + + [DllImport(ChromiumEwk, EntryPoint = "ewk_intercept_request_http_method_get")] + internal static extern IntPtr _ewk_intercept_request_http_method_get(IntPtr request); + + internal static string ewk_intercept_request_http_method_get(IntPtr request) + { + return Marshal.PtrToStringAnsi(_ewk_intercept_request_http_method_get(request)) ?? string.Empty; + } + + [DllImport(ChromiumEwk)] + internal static extern bool ewk_intercept_request_ignore(IntPtr request); + +#pragma warning disable CA2101 // Specify marshaling for P/Invoke string arguments + [DllImport(ChromiumEwk)] +#pragma warning restore CA2101 // Specify marshaling for P/Invoke string arguments + internal static extern bool ewk_intercept_request_response_set(IntPtr request, string header, string body, uint length); + } +} From 0e7725a8d31c20e29d4b583dc53d0661bbafb376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 4 Aug 2021 09:31:29 +0900 Subject: [PATCH 029/266] Bump to latest (#71) - Window lifecycle (#1754) - Move New Navigation Handler to Core and make it internal (#1800) - Scrollview handler (#1669) - ScrollView Resize + Window Handler Resize (#1676) - Font AutoScalingEnabled (#1774) - Rename Font Properties (#1755) - Update layout system to ensure native measure/arrange are called for all controls, even from Page subclasses (#1819) - IContainer as IList (#1724) - Implement Layout padding for new StackLayouts and GridLayout (#1749) - Delete all the TabIndex, TabStop, Focusable things! (#1777) - Introduce SetSemanticFocus API via SemanticExtensions (#1829) - Improve Window and AnimationManager (#1653) - And so on --- .../BordelessEntry/BordelessEntryHandler.cs | 5 - .../NavigationPageHandler.Tizen.cs | 256 -------------- .../NavigationPageHandler.Tizen.cs | 327 ++++++++++++++++++ .../src/Platform/Tizen/CoreUIAppContext.cs | 2 +- .../src/Platform/Tizen/CoreUIAppExtensions.cs | 25 ++ .../src/Platform/Tizen/HandlerExtensions.cs | 4 +- .../src/Platform/Tizen/MauiApplication.cs | 1 + .../src/Platform/Tizen/SemanticExtensions.cs | 19 + 8 files changed, 375 insertions(+), 264 deletions(-) delete mode 100644 src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs create mode 100644 src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs create mode 100644 src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs create mode 100644 src/Core/src/Platform/Tizen/SemanticExtensions.cs diff --git a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs index 2c2b66abf197..6cf29c51de81 100644 --- a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs +++ b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs @@ -41,11 +41,6 @@ public static void MapBorder(BordelessEntryHandler handler, BordelessEntry borde #else public static void MapBorder(BordelessEntryHandler handler, BordelessEntry borderlessEntry) { - } -#elif TIZEN - public static void MapBorder(BordelessEntryHandler handler, BordelessEntry borderlessEntry) - { - } #endif } diff --git a/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs deleted file mode 100644 index 03583d02cfcf..000000000000 --- a/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs +++ /dev/null @@ -1,256 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using ElmSharp; -using Microsoft.Maui.Controls.Internals; -using Microsoft.Maui.Handlers; -using Tizen.UIExtensions.ElmSharp; -using TButton = Tizen.UIExtensions.ElmSharp.Button; -using TSpan = Tizen.UIExtensions.Common.Span; -using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; - -namespace Microsoft.Maui.Controls.Handlers -{ - public partial class NavigationPageHandler : - ViewHandler - { - readonly List _naviItemContentPartList = new List(); - TaskCompletionSource _currentTaskSource = null; - IDictionary _naviItemMap; - - Page PreviousPage => VirtualView.Navigation.NavigationStack.Count > 1 ? VirtualView.Navigation.NavigationStack[VirtualView.Navigation.NavigationStack.Count - 2] : null; - NaviItem CurrentNaviItem => NativeView.NavigationStack.Count > 0 ? NativeView.NavigationStack.Last() : null; - NaviItem PreviousNaviItem => NativeView.NavigationStack.Count > 1 ? NativeView.NavigationStack[NativeView.NavigationStack.Count - 2] : null; - - protected override Naviframe CreateNativeView() - { - return new Naviframe(NativeParent) - { - PreserveContentOnPop = true, - DefaultBackButtonEnabled = false, - }; - } - - protected override void ConnectHandler(Naviframe nativeView) - { - base.ConnectHandler(nativeView); - nativeView.AnimationFinished += OnAnimationFinished; - _naviItemMap = new Dictionary(); - - if (VirtualView == null) - return; - - VirtualView.PushRequested += OnPushRequested; - VirtualView.PopRequested += OnPopRequested; - VirtualView.InternalChildren.CollectionChanged += OnPageCollectionChanged; - - foreach (Page page in VirtualView.InternalChildren) - { - _naviItemMap[page] = NativeView.Push(CreateNavItem(page), SpanTitle(page.Title)); - page.PropertyChanged += NavigationBarPropertyChangedHandler; - - UpdateHasNavigationBar(page); - } - } - - protected override void DisconnectHandler(Naviframe nativeView) - { - base.DisconnectHandler(nativeView); - nativeView.AnimationFinished -= OnAnimationFinished; - - VirtualView.PushRequested -= OnPushRequested; - VirtualView.PopRequested -= OnPopRequested; - VirtualView.InternalChildren.CollectionChanged -= OnPageCollectionChanged; - } - - public static void MapPadding(NavigationPageHandler handler, NavigationPage view) { } - - public static void MapBarTextColor(NavigationPageHandler handler, NavigationPage view) - { - handler.UpdateTitle(view.CurrentPage); - } - - public static void MapBarBackground(NavigationPageHandler handler, NavigationPage view) { } - - public static void MapTitleIcon(NavigationPageHandler handler, NavigationPage view) { } - - public static void MapTitleView(NavigationPageHandler handler, NavigationPage view) { } - - void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) - { - // this handler is invoked only for child pages (contained on a navigation stack) - if (e.PropertyName == NavigationPage.HasNavigationBarProperty.PropertyName) - UpdateHasNavigationBar(sender as Page); - else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName || - e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) - UpdateHasBackButton(sender as Page); - else if (e.PropertyName == Page.TitleProperty.PropertyName) - UpdateTitle(sender as Page); - } - - void OnPageCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - if (e.OldItems != null) - foreach (Page page in e.OldItems) - page.PropertyChanged -= NavigationBarPropertyChangedHandler; - if (e.NewItems != null) - foreach (Page page in e.NewItems) - page.PropertyChanged += NavigationBarPropertyChangedHandler; - } - - void OnPushRequested(object sender, NavigationRequestedEventArgs nre) - { - if (nre.Animated || NativeView.NavigationStack.Count == 0) - { - _naviItemMap[nre.Page] = NativeView.Push(CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); - _currentTaskSource = new TaskCompletionSource(); - nre.Task = _currentTaskSource.Task; - - // There is no TransitionFinished (AnimationFinished) event after the first Push - if (NativeView.NavigationStack.Count == 1) - CompleteCurrentNavigationTask(); - } - else - { - _naviItemMap[nre.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); - } - UpdateHasNavigationBar(nre.Page); - } - - void OnPopRequested(object sender, NavigationRequestedEventArgs nre) - { - if (VirtualView.InternalChildren.Count == NativeView.NavigationStack.Count) - { - nre.Page?.SendDisappearing(); - UpdateNavigationBar(PreviousPage, PreviousNaviItem); - - if (nre.Animated) - { - NativeView.Pop(); - - _currentTaskSource = new TaskCompletionSource(); - nre.Task = _currentTaskSource.Task; - - // There is no TransitionFinished (AnimationFinished) event after Pop the last page - if (NativeView.NavigationStack.Count == 0) - CompleteCurrentNavigationTask(); - } - else - { - CurrentNaviItem?.Delete(); - } - - if (_naviItemMap.ContainsKey(nre.Page)) - _naviItemMap.Remove(nre.Page); - } - } - - void OnAnimationFinished(object sender, EventArgs e) - { - CompleteCurrentNavigationTask(); - } - - void CompleteCurrentNavigationTask() - { - if (_currentTaskSource != null) - { - var tmp = _currentTaskSource; - _currentTaskSource = null; - tmp.SetResult(true); - } - } - - void UpdateHasNavigationBar(Page page) - { - NaviItem item = GetNaviItemForPage(page); - item.SetTabBarStyle(); - item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty); - UpdateBarBackgroundColor(item); - } - - void UpdateNavigationBar(Page page, NaviItem item = null) - { - if (item == null) - item = GetNaviItemForPage(page); - - UpdateTitle(page, item); - UpdateBarBackgroundColor(item); - } - - void UpdateHasBackButton(Page page, NaviItem item = null) - { - if (item == null) - item = GetNaviItemForPage(page); - - TButton button = null; - - if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty) && NativeView.NavigationStack.Count > 1) - { - button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty)); - } - item.SetBackButton(button); - } - - void UpdateTitle(Page page, NaviItem item = null) - { - if (item == null) - item = GetNaviItemForPage(page); - - item.SetTitle(SpanTitle(page.Title)); - } - - string SpanTitle(string Title) - { - TSpan span = new TSpan - { - Text = Title, - HorizontalTextAlignment = TTextAlignment.Center, - ForegroundColor = VirtualView.BarTextColor.ToNative() - }; - return span.GetMarkupText(); - } - - void UpdateBarBackgroundColor(NaviItem item) - { - item.TitleBarBackgroundColor = VirtualView.BarBackgroundColor.ToNativeEFL(); - } - - TButton CreateNavigationButton(string text) - { - var button = new TButton(NativeParent) - { - Text = text - }; - button.SetNavigationBackStyle(); - button.Clicked += (sender, e) => - { - if (!VirtualView.SendBackButtonPressed()) - Tizen.Applications.Application.Current.Exit(); - }; - _naviItemContentPartList.Add(button); - button.Deleted += NaviItemPartContentDeletedHandler; - return button; - } - - void NaviItemPartContentDeletedHandler(object sender, EventArgs e) - { - _naviItemContentPartList.Remove(sender as Widget); - } - - NaviItem GetNaviItemForPage(Page page) - { - NaviItem item; - if (_naviItemMap.TryGetValue(page, out item)) - { - return item; - } - return null; - } - - EvasObject CreateNavItem(Page page) - { - return page.ToNative(MauiContext); - } - } -} diff --git a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs new file mode 100644 index 000000000000..454a1084293c --- /dev/null +++ b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs @@ -0,0 +1,327 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using ElmSharp; +using Microsoft.Maui.Handlers; +using Tizen.UIExtensions.ElmSharp; +using TButton = Tizen.UIExtensions.ElmSharp.Button; +using TSpan = Tizen.UIExtensions.Common.Span; +using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; + +namespace Microsoft.Maui.Handlers +{ + internal partial class NavigationPageHandler : + ViewHandler, INativeViewHandler + { + readonly List _naviItemContentPartList = new List(); + TaskCompletionSource? _currentTaskSource = null; + IDictionary? _naviItemMap; + + IView? PreviousPage => VirtualView.NavigationStack.Count > 1 ? VirtualView.NavigationStack[VirtualView.NavigationStack.Count - 2] : null; + NaviItem? CurrentNaviItem => NativeView.NavigationStack.Count > 0 ? NativeView.NavigationStack.Last() : null; + NaviItem? PreviousNaviItem => NativeView.NavigationStack.Count > 1 ? NativeView.NavigationStack[NativeView.NavigationStack.Count - 2] : null; + + protected override Naviframe CreateNativeView() + { + return new Naviframe(NativeParent) + { + PreserveContentOnPop = true, + DefaultBackButtonEnabled = false, + }; + } + + private static void PushAsyncTo(NavigationPageHandler arg1, INavigationView arg2, object? arg3) + { + if (arg3 is MauiNavigationRequestedEventArgs args) + arg1.OnPushRequested(args); + } + + private static void PopAsyncTo(NavigationPageHandler arg1, INavigationView arg2, object? arg3) + { + if (arg3 is MauiNavigationRequestedEventArgs args) + arg1.OnPopRequested(args); + } + + void OnPushRequested(MauiNavigationRequestedEventArgs e) + { + _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); + + if (e.Animated || NativeView.NavigationStack.Count == 0) + { + _naviItemMap[e.Page] = NativeView.Push(CreateNavItem(e.Page), SpanTitle(e.Page)); + _currentTaskSource = new TaskCompletionSource(); + e.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after the first Push + if (NativeView.NavigationStack.Count == 1) + CompleteCurrentNavigationTask(); + } + else + { + _naviItemMap[e.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(e.Page), SpanTitle(e.Page)); + } + //UpdateHasNavigationBar(nre.Page); + } + + void OnPopRequested(MauiNavigationRequestedEventArgs e) + { + _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); + + if (VirtualView.NavigationStack.Count == NativeView.NavigationStack.Count) + { + //e.Page?.SendDisappearing(); + //UpdateNavigationBar(PreviousPage, PreviousNaviItem); + + if (e.Animated) + { + NativeView.Pop(); + + _currentTaskSource = new TaskCompletionSource(); + e.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after Pop the last page + if (NativeView.NavigationStack.Count == 0) + CompleteCurrentNavigationTask(); + } + else + { + CurrentNaviItem?.Delete(); + } + + if (_naviItemMap.ContainsKey(e.Page)) + _naviItemMap.Remove(e.Page); + } + } + + protected override void ConnectHandler(Naviframe nativeView) + { + base.ConnectHandler(nativeView); + nativeView.AnimationFinished += OnAnimationFinished; + _naviItemMap = new Dictionary(); + + if (VirtualView == null) + return; + + //VirtualView.PushRequested += OnPushRequested; + //VirtualView.PopRequested += OnPopRequested; + //VirtualView.InternalChildren.CollectionChanged += OnPageCollectionChanged; + + foreach (var page in VirtualView.NavigationStack) + { + _naviItemMap[page] = NativeView.Push(CreateNavItem(page), SpanTitle(page)); + //page.PropertyChanged += NavigationBarPropertyChangedHandler; + + //UpdateHasNavigationBar(page); + } + } + + protected override void DisconnectHandler(Naviframe nativeView) + { + base.DisconnectHandler(nativeView); + nativeView.AnimationFinished -= OnAnimationFinished; + + //VirtualView.PushRequested -= OnPushRequested; + //VirtualView.PopRequested -= OnPopRequested; + //VirtualView.InternalChildren.CollectionChanged -= OnPageCollectionChanged; + } + + //public static void MapPadding(NavigationPageHandler handler, INavigationView view) { } + + //public static void MapBarTextColor(NavigationPageHandler handler, INavigationView view) + //{ + // //handler.UpdateTitle(view.CurrentPage); + //} + + public static void MapBarBackground(NavigationPageHandler handler, INavigationView view) { } + + public static void MapTitleIcon(NavigationPageHandler handler, INavigationView view) { } + + public static void MapTitleView(NavigationPageHandler handler, INavigationView view) { } + + //void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) + //{ + // // this handler is invoked only for child pages (contained on a navigation stack) + // if (e.PropertyName == INavigationView.HasNavigationBarProperty.PropertyName) + // UpdateHasNavigationBar(sender as Page); + // else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName || + // e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) + // UpdateHasBackButton(sender as Page); + // else if (e.PropertyName == Page.TitleProperty.PropertyName) + // UpdateTitle(sender as Page); + //} + + //void OnPageCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + //{ + // if (e.OldItems != null) + // foreach (Page page in e.OldItems) + // page.PropertyChanged -= NavigationBarPropertyChangedHandler; + // if (e.NewItems != null) + // foreach (Page page in e.NewItems) + // page.PropertyChanged += NavigationBarPropertyChangedHandler; + //} + + //void OnPushRequested(object sender, NavigationRequestedEventArgs nre) + //{ + // if (nre.Animated || NativeView.NavigationStack.Count == 0) + // { + // _naviItemMap[nre.Page] = NativeView.Push(CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); + // _currentTaskSource = new TaskCompletionSource(); + // nre.Task = _currentTaskSource.Task; + + // // There is no TransitionFinished (AnimationFinished) event after the first Push + // if (NativeView.NavigationStack.Count == 1) + // CompleteCurrentNavigationTask(); + // } + // else + // { + // _naviItemMap[nre.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); + // } + // UpdateHasNavigationBar(nre.Page); + //} + + //void OnPopRequested(object sender, NavigationRequestedEventArgs nre) + //{ + // if (VirtualView.InternalChildren.Count == NativeView.NavigationStack.Count) + // { + // nre.Page?.SendDisappearing(); + // UpdateNavigationBar(PreviousPage, PreviousNaviItem); + + // if (nre.Animated) + // { + // NativeView.Pop(); + + // _currentTaskSource = new TaskCompletionSource(); + // nre.Task = _currentTaskSource.Task; + + // // There is no TransitionFinished (AnimationFinished) event after Pop the last page + // if (NativeView.NavigationStack.Count == 0) + // CompleteCurrentNavigationTask(); + // } + // else + // { + // CurrentNaviItem?.Delete(); + // } + + // if (_naviItemMap.ContainsKey(nre.Page)) + // _naviItemMap.Remove(nre.Page); + // } + //} + + void OnAnimationFinished(object sender, EventArgs e) + { + CompleteCurrentNavigationTask(); + } + + void CompleteCurrentNavigationTask() + { + if (_currentTaskSource != null) + { + var tmp = _currentTaskSource; + _currentTaskSource = null; + tmp.SetResult(true); + } + } + + //void UpdateHasNavigationBar(IView page) + //{ + // NaviItem item = GetNaviItemForPage(page); + // item.SetTabBarStyle(); + // item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty); + // UpdateBarBackgroundColor(item); + //} + + //void UpdateNavigationBar(Page page, NaviItem item = null) + //{ + // if (item == null) + // item = GetNaviItemForPage(page); + + // UpdateTitle(page, item); + // UpdateBarBackgroundColor(item); + //} + + //void UpdateHasBackButton(Page page, NaviItem item = null) + //{ + // if (item == null) + // item = GetNaviItemForPage(page); + + // TButton button = null; + + // if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty) && NativeView.NavigationStack.Count > 1) + // { + // button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty)); + // } + // item.SetBackButton(button); + //} + + void UpdateTitle(IView page, NaviItem? item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + item?.SetTitle(SpanTitle(page)); + } + + string SpanTitle(IView view) + { + if (view is not IPage page) + return string.Empty; + else + { + var span = new TSpan + { + Text = page.Title, + HorizontalTextAlignment = TTextAlignment.Center, + //ForegroundColor = VirtualView.BarTextColor.ToNative() + }; + return span.GetMarkupText(); + } + } + + //void UpdateBarBackgroundColor(NaviItem item) + //{ + // item.TitleBarBackgroundColor = VirtualView.BarBackgroundColor.ToNativeEFL(); + //} + + //TButton CreateNavigationButton(string text) + //{ + // var button = new TButton(NativeParent) + // { + // Text = text + // }; + // button.SetNavigationBackStyle(); + // button.Clicked += (sender, e) => + // { + // if (!VirtualView.SendBackButtonPressed()) + // Tizen.Applications.Application.Current.Exit(); + // }; + // _naviItemContentPartList.Add(button); + // button.Deleted += NaviItemPartContentDeletedHandler; + // return button; + //} + + //void NaviItemPartContentDeletedHandler(object sender, EventArgs e) + //{ + // _naviItemContentPartList.Remove(sender as Widget); + //} + + NaviItem? GetNaviItemForPage(IView page) + { + _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); + + NaviItem item; + if (_naviItemMap.TryGetValue(page, out item)) + { + return item; + } + return null; + } + + EvasObject CreateNavItem(IView page) + { + return page.ToNative(MauiContext!); + } + } +} diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index d6641f4f168e..9fcc6dfb728e 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -121,7 +121,7 @@ public void SetBackButtonPressedHandler(Func handler) static Window CreateDefaultWindow() { - return GetPreloadedWindow() ?? new Window("XamarinWindow"); + return GetPreloadedWindow() ?? new Window("MauiDefaultWindow"); } static Window? GetPreloadedWindow() diff --git a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs new file mode 100644 index 000000000000..c730e41e1cbb --- /dev/null +++ b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs @@ -0,0 +1,25 @@ +using System; +using Tizen.Applications; +using EWindow = ElmSharp.Window; + +namespace Microsoft.Maui +{ + internal static class CoreUIAppExtensions + { + public static IWindow GetWindow(this CoreUIApplication application) + { + if (MauiApplication.Current.VirtualWindow != null) + return MauiApplication.Current.VirtualWindow; + + var nativeWindow = MauiApplication.Current.MainWindow; + + foreach (var window in MauiApplication.Current.Application.Windows) + { + if (window?.Handler?.NativeView is EWindow win && win == nativeWindow) + return window; + } + + throw new InvalidOperationException("Window Not Found"); + } + } +} diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 43df1d04043b..2be109138318 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -20,10 +20,10 @@ public static EvasObject ToNative(this IElement view, IMauiContext context) handler = null; if (handler == null) - handler = context.Handlers.GetHandler(view.GetType()) as IViewHandler; + handler = context.Handlers.GetHandler(view.GetType()); if (handler == null) - throw new Exception($"Handler not found for view {view} or was not {nameof(IViewHandler)}."); + throw new Exception($"Handler not found for view {view}."); handler.SetMauiContext(context); diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index b8a0f94391d5..f5b52c59508e 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -62,6 +62,7 @@ protected override void OnCreate() var activationState = new ActivationState(mauiContext); var window = Application.CreateWindow(activationState); + _virtualWindow = new WeakReference(window); tizenWindow.SetWindow(window, mauiContext); return tizenWindow; diff --git a/src/Core/src/Platform/Tizen/SemanticExtensions.cs b/src/Core/src/Platform/Tizen/SemanticExtensions.cs new file mode 100644 index 000000000000..f641969d5648 --- /dev/null +++ b/src/Core/src/Platform/Tizen/SemanticExtensions.cs @@ -0,0 +1,19 @@ +using System; +using ElmSharp.Accessible; + +namespace Microsoft.Maui +{ + public static partial class SemanticExtensions + { + public static void SetSemanticFocus(this IFrameworkElement element) + { + if (element?.Handler?.NativeView == null) + throw new NullReferenceException("Can't access view from a null handler"); + + if (element.Handler.NativeView is not AccessibleObject) + return; + + //TODO : Need to implement + } + } +} From 17d01160b1a26656cf553df9aeca86c362c03124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 4 Aug 2021 10:33:17 +0900 Subject: [PATCH 030/266] Remove IPage on Tizen (#72) - Merge IFrameworkElement and IView and Remove IPage (#1875) --- .../NavigationPage/NavigationPageHandler.Tizen.cs | 4 ++-- src/Core/src/Handlers/Page/PageHandler.Tizen.cs | 12 ++++++++---- src/Core/src/Platform/Tizen/SemanticExtensions.cs | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs index 454a1084293c..976499e8305e 100644 --- a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs +++ b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs @@ -266,13 +266,13 @@ void UpdateTitle(IView page, NaviItem? item = null) string SpanTitle(IView view) { - if (view is not IPage page) + if (view is not ITitledElement page) return string.Empty; else { var span = new TSpan { - Text = page.Title, + Text = page.Title??string.Empty, HorizontalTextAlignment = TTextAlignment.Center, //ForegroundColor = VirtualView.BarTextColor.ToNative() }; diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index 52097e13bc5a..4ee2aa05db20 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -41,11 +41,15 @@ void UpdateContent() _contentHandler?.Dispose(); _contentHandler = null; - NativeView.Children.Add(VirtualView.Content.ToNative(MauiContext)); - if (VirtualView.Content.Handler is INativeViewHandler thandler) + if (VirtualView is IContentView cv && cv.Content is IView view) { - thandler?.SetParent(this); - _contentHandler = thandler; + NativeView.Children.Add(view.ToNative(MauiContext)); + + if (view.Handler is INativeViewHandler thandler) + { + thandler?.SetParent(this); + _contentHandler = thandler; + } } } } diff --git a/src/Core/src/Platform/Tizen/SemanticExtensions.cs b/src/Core/src/Platform/Tizen/SemanticExtensions.cs index f641969d5648..6a4c0bbc720e 100644 --- a/src/Core/src/Platform/Tizen/SemanticExtensions.cs +++ b/src/Core/src/Platform/Tizen/SemanticExtensions.cs @@ -5,7 +5,7 @@ namespace Microsoft.Maui { public static partial class SemanticExtensions { - public static void SetSemanticFocus(this IFrameworkElement element) + public static void SetSemanticFocus(this IView element) { if (element?.Handler?.NativeView == null) throw new NullReferenceException("Can't access view from a null handler"); From f2f8e164b15341d073b027d4d908a185309a8b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 4 Aug 2021 14:02:00 +0900 Subject: [PATCH 031/266] Add Blazor webview (#67) * Add Blazor webview * Replace space to tab * remove space --- .../Maui/Tizen/BlazorWebViewHandler.Tizen.cs | 13 +++++++++++ .../src/Maui/Tizen/WebViewExtension.cs | 22 ++++++++++++------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs index 7b45a654c4f0..9e6ff4d8af6d 100644 --- a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs +++ b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs @@ -91,6 +91,19 @@ private void PostMessageFromJS(JavaScriptMessage message) } } + public void PostMessageFromJS(JavaScriptMessage message) + { + if (message is null) + { + throw new ArgumentNullException(nameof(message)); + } + + if (message.Name.Equals("BlazorHandler", StringComparison.Ordinal)) + { + _webviewManager!.MessageReceivedInternal(new Uri(NativeWebView.Url), message.GetBodyAsString()); + } + } + private void StartWebViewCoreIfPossible() { if (!RequiredStartupPropertiesSet || diff --git a/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs b/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs index 672b21282ed4..5df674fa296c 100644 --- a/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs +++ b/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs @@ -17,23 +17,28 @@ public static void SetInterceptRequestCallback(this TWebView webView, InterceptR ewk_context_intercept_request_callback_set(contextHandle.Value, callback, IntPtr.Zero); } -#pragma warning disable IDE0060 // Remove unused parameter - public static bool SetInterceptRequestResponse(this TWebView webView, IntPtr request, string header, string body, uint length) + public static void SetInspectorStart(this TWebView webView, uint port) + { + var context = webView.GetContext(); + var handleField = context.GetType().GetField("_handle", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var contextHandle = (IntPtr?)handleField?.GetValue(context); + if (contextHandle != null) + ewk_context_inspector_server_start(contextHandle.Value, port); + } + + public static bool SetInterceptRequestResponse(this TWebView webView, IntPtr request, string header, string body, uint length) #pragma warning restore IDE0060 // Remove unused parameter { return ewk_intercept_request_response_set(request, header, body, length); } -#pragma warning disable IDE0060 // Remove unused parameter public static bool IgnoreInterceptRequest(this TWebView webView, IntPtr request) #pragma warning restore IDE0060 // Remove unused parameter { return ewk_intercept_request_ignore(request); } -#pragma warning disable IDE0060 // Remove unused parameter public static string GetInterceptRequestUrl(this TWebView webView, IntPtr request) -#pragma warning restore IDE0060 // Remove unused parameter { return Marshal.PtrToStringAnsi(_ewk_intercept_request_url_get(request)) ?? string.Empty; } @@ -58,12 +63,13 @@ internal static string ewk_intercept_request_http_method_get(IntPtr request) return Marshal.PtrToStringAnsi(_ewk_intercept_request_http_method_get(request)) ?? string.Empty; } - [DllImport(ChromiumEwk)] + [DllImport(ChromiumEwk)] + public static extern uint ewk_context_inspector_server_start(IntPtr context, uint port); + + [DllImport(ChromiumEwk)] internal static extern bool ewk_intercept_request_ignore(IntPtr request); -#pragma warning disable CA2101 // Specify marshaling for P/Invoke string arguments [DllImport(ChromiumEwk)] -#pragma warning restore CA2101 // Specify marshaling for P/Invoke string arguments internal static extern bool ewk_intercept_request_response_set(IntPtr request, string header, string body, uint length); } } From 78d28035719ddc38a8529738cbad42d2357eb5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9D=B8=EC=84=9C/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Associate/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 4 Aug 2021 15:41:44 +0900 Subject: [PATCH 032/266] Fix entry cursor error (#68) * Fix entry cursor error * Update code referring to android extension * Remove duplicate code & Add exception cases * Code fixes for consistency --- .../src/Platform/Tizen/EntryExtensions.cs | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Core/src/Platform/Tizen/EntryExtensions.cs b/src/Core/src/Platform/Tizen/EntryExtensions.cs index dc8a2f1ed8ac..7fae01f40761 100644 --- a/src/Core/src/Platform/Tizen/EntryExtensions.cs +++ b/src/Core/src/Platform/Tizen/EntryExtensions.cs @@ -145,14 +145,10 @@ static int GetSelectionEnd(Entry platformEntry, ITextInput entry, int start) [PortHandler] public static void UpdateSelectionLength(this Entry nativeEntry, IEntry entry) { - var start = GetSelectionStart(nativeEntry, entry); - var end = GetSelectionEnd(nativeEntry, entry, start); - var selectionLength = end - start; + int start = GetSelectionStart(nativeEntry, entry); + int end = GetSelectionEnd(nativeEntry, entry, start); - if (selectionLength != entry.SelectionLength) - entry.SelectionLength = selectionLength; - - if (selectionLength > 0) + if (start < end) { nativeEntry.SetSelectionRegion(start, end); } @@ -164,10 +160,10 @@ public static void UpdateSelectionLength(this Entry nativeEntry, IEntry entry) static int GetSelectionStart(Entry nativeEntry, IEntry entry) { - var start = entry.Text?.Length ?? 0; - var cursorPosition = entry.CursorPosition; + int start = nativeEntry.Text?.Length ?? 0; + int cursorPosition = entry.CursorPosition; - if (entry.CursorPosition > 0) + if (!string.IsNullOrEmpty(nativeEntry.Text)) start = Math.Min(start, cursorPosition); if (start != cursorPosition) @@ -178,11 +174,10 @@ static int GetSelectionStart(Entry nativeEntry, IEntry entry) static int GetSelectionEnd(Entry nativeEntry, IEntry entry, int start) { - var end = start; - - if (entry.SelectionLength > 0) - end = Math.Min((start + entry.SelectionLength), entry.Text?.Length ?? 0); - + int end = Math.Max(start, Math.Min(nativeEntry.Text?.Length ?? 0, start + entry.SelectionLength)); + int selectionLength = end - start; + if (selectionLength != entry.SelectionLength) + entry.SelectionLength = selectionLength; return end; } From 975fbdfcf9fd08a90f06f142a7d0563fe0ac624d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 4 Aug 2021 16:45:09 +0900 Subject: [PATCH 033/266] Fix nullable issue (#77) --- .../Handlers/NavigationPage/NavigationPageHandler.Tizen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs index 976499e8305e..c5a52f1259bc 100644 --- a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs +++ b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs @@ -210,7 +210,7 @@ public static void MapTitleView(NavigationPageHandler handler, INavigationView v // } //} - void OnAnimationFinished(object sender, EventArgs e) + void OnAnimationFinished(object? sender, EventArgs e) { CompleteCurrentNavigationTask(); } @@ -311,7 +311,7 @@ string SpanTitle(IView view) { _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); - NaviItem item; + NaviItem? item; if (_naviItemMap.TryGetValue(page, out item)) { return item; From d3c1bdd81a950d34d77481d47a59f3e5f54caf09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 6 Aug 2021 11:14:56 +0900 Subject: [PATCH 034/266] Fix Image loading (#78) --- .../src/Handlers/Image/ImageHandler.Tizen.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs b/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs index f0604f542f4b..7f4d4113c5fe 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs @@ -44,4 +44,34 @@ void OnSetImageSource(Image? obj) // Empty on purpose } } + + // TODO : Will be removed. Use ImageEx temporaily before Tizen.UIExtension.Image fixing. + class ImageEx : Image, IMeasurable + { + public ImageEx(ElmSharp.EvasObject parent) : base(parent) { } + + Size IMeasurable.Measure(double availableWidth, double availableHeight) + { + var imageSize = ObjectSize; + var size = new Size() + { + Width = imageSize.Width, + Height = imageSize.Height, + }; + + if (0 != availableWidth && 0 != availableHeight + && (imageSize.Width > availableWidth || imageSize.Height > availableHeight)) + { + // when available size is limited and insufficient for the image ... + double imageRatio = imageSize.Width / imageSize.Height; + double availableRatio = availableWidth / availableHeight; + // depending on the relation between availableRatio and imageRatio, copy the availableWidth or availableHeight + // and calculate the size which preserves the image ratio, but does not exceed the available size + size.Width = availableRatio > imageRatio ? imageSize.Width * availableHeight / imageSize.Height : availableWidth; + size.Height = availableRatio > imageRatio ? availableHeight : imageSize.Height * availableWidth / imageSize.Width; + } + + return size; + } + } } \ No newline at end of file From 51cfa939aca14df8f9d109756d2a764f117727f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 6 Aug 2021 11:21:33 +0900 Subject: [PATCH 035/266] Fix nested layout issue (#79) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 허강호/Common Platform Lab(SR)/Principal Engineer/삼성전자 --- src/Core/src/Platform/Tizen/LayoutCanvas.cs | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/Core/src/Platform/Tizen/LayoutCanvas.cs diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs new file mode 100644 index 000000000000..6219e7fb083f --- /dev/null +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -0,0 +1,23 @@ +using System; +using ElmSharp; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using TSize = Tizen.UIExtensions.Common.Size; +using Size = Microsoft.Maui.Graphics.Size; +using Rectangle = Microsoft.Maui.Graphics.Rectangle; + +namespace Microsoft.Maui +{ + public class LayoutCanvas : Canvas, IMeasurable + { + public LayoutCanvas(EvasObject parent) : base(parent) { } + + public TSize Measure(double availableWidth, double availableHeight) + { + return CrossPlatformMeasure?.Invoke(availableWidth.ToScaledDP(), availableHeight.ToScaledDP()).ToPixel() ?? new TSize(0, 0); + } + + internal Func? CrossPlatformMeasure { get; set; } + internal Func? CrossPlatformArrange { get; set; } + } +} From 283eece89b02ece4f04e9e3c294d915816fbd5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 6 Aug 2021 16:01:07 +0900 Subject: [PATCH 036/266] Fix issues caused by bump up (#75) * Fix issues caused by bump up * Update Tizen file provider * Update file provider with proper path --- .../src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs index 9e6ff4d8af6d..e3e58bd8554f 100644 --- a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs +++ b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs @@ -1,11 +1,11 @@ using System; using System.IO; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Maui; using Microsoft.Maui.Dispatching; using Microsoft.Maui.Handlers; using Tizen.WebView; +using TApplication = Tizen.Applications.Application; using TChromium = Tizen.WebView.Chromium; using TWebView = Tizen.WebView.WebView; @@ -120,6 +120,8 @@ private void StartWebViewCoreIfPossible() // unclear there's any other use case. We can add more options later if so. var contentRootDir = Path.GetDirectoryName(HostPage!) ?? string.Empty; var hostPageRelativePath = Path.GetRelativePath(contentRootDir, HostPage!); + var resContentRootDir = Path.Combine(TApplication.Current.DirectoryInfo.Resource, contentRootDir); + var mauiAssetFileProvider = new PhysicalFileProvider(resContentRootDir); var fileProvider = VirtualView.CreateFileProvider(contentRootDir); From 46c052d25b7c65e11f73c73d1f17a64e3d0868cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 6 Aug 2021 16:02:04 +0900 Subject: [PATCH 037/266] Fix unmatched partial method (#84) --- src/Core/src/Handlers/View/ViewHandler.Tizen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/src/Handlers/View/ViewHandler.Tizen.cs b/src/Core/src/Handlers/View/ViewHandler.Tizen.cs index 7b185ff373c5..3c49493d2c64 100644 --- a/src/Core/src/Handlers/View/ViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/View/ViewHandler.Tizen.cs @@ -166,7 +166,7 @@ partial void ConnectingHandler(NativeView? nativeView) } } - partial void DisconnectingHandler(NativeView? nativeView) + partial void DisconnectingHandler(NativeView nativeView) { if (nativeView == null) return; From 50c65eb365061af2366e9d3f3f5f17c15f911c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 10 Aug 2021 08:42:26 +0900 Subject: [PATCH 038/266] Fixes incorrect parameter type for ILayoutManager.ArrangeChildren (Rectangle -> Size). (#91) --- src/Core/src/Platform/Tizen/LayoutCanvas.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs index 6219e7fb083f..27fdc9bc6d93 100644 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -18,6 +18,6 @@ public TSize Measure(double availableWidth, double availableHeight) } internal Func? CrossPlatformMeasure { get; set; } - internal Func? CrossPlatformArrange { get; set; } + internal Func? CrossPlatformArrange { get; set; } } } From 9eb22f4240997003a042f1d30b3ee8c5b648e2e1 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 11 Aug 2021 13:47:15 +0900 Subject: [PATCH 039/266] Make the HandlerToRendererShim simple --- .../Core/src/Tizen/HandlerToRendererShim.cs | 1 - src/Compatibility/Core/src/Tizen/Platform.cs | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs index d90ff96b622e..c183ec309af1 100644 --- a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs +++ b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs @@ -76,7 +76,6 @@ public void SetElement(VisualElement element) NativeView.Deleted += OnNativeDeleted; ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(oldElement, Element)); - (ViewHandler as INativeViewHandler)?.SetParent(new MockParentHandler(element.RealParent as VisualElement)); } void OnBatchCommitted(object sender, EventArg e) diff --git a/src/Compatibility/Core/src/Tizen/Platform.cs b/src/Compatibility/Core/src/Tizen/Platform.cs index c9aca6bcb231..0ef8670bf924 100644 --- a/src/Compatibility/Core/src/Tizen/Platform.cs +++ b/src/Compatibility/Core/src/Tizen/Platform.cs @@ -92,16 +92,7 @@ internal static IVisualElementRenderer CreateRenderer(VisualElement element) { vh.SetParent(nvh); } - - if (handler is LayoutHandler layoutHandler) - { - renderer = new LayoutHandlerToRendererShim(layoutHandler); - } - else - { - renderer = new HandlerToRendererShim(vh); - } - + renderer = new HandlerToRendererShim(vh); element.Handler = handler; } } From 13f127abc1bcd231ee73a9aa2d7fedf8afd0e473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 12 Aug 2021 09:57:36 +0900 Subject: [PATCH 040/266] Revert "Fixes incorrect parameter type for ILayoutManager.ArrangeChildren (Rectangle -> Size). (#91)" (#97) This reverts commit c54ac836ef961d647989a34fa83208b9883142ef. --- src/Core/src/Platform/Tizen/LayoutCanvas.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs index 27fdc9bc6d93..6219e7fb083f 100644 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -18,6 +18,6 @@ public TSize Measure(double availableWidth, double availableHeight) } internal Func? CrossPlatformMeasure { get; set; } - internal Func? CrossPlatformArrange { get; set; } + internal Func? CrossPlatformArrange { get; set; } } } From a90d32cb5e16ce8672a7b0a49b5d8a0724d577bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 13 Aug 2021 08:22:24 +0900 Subject: [PATCH 041/266] Refactor the LayoutHandler (#99) --- .../Handlers/Layout/LayoutHandler.Tizen.cs | 13 ++++++++-- src/Core/src/Platform/Tizen/LayoutCanvas.cs | 26 ++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs index a597010a388c..167d09886bb3 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs @@ -168,9 +168,18 @@ void EnsureZIndexOrder(IView child) } } - public void RegisterOnLayoutUpdated() + public void Update(int index, IView child) { - _layoutUpdatedRegistered = true; + _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); + _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + NativeView.Children.RemoveAt(index); + NativeView.Children.Insert(index, child.ToNative(MauiContext)); + if (child.Handler is INativeViewHandler childHandler) + { + childHandler?.SetParent(this); + } } } } diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs index 6219e7fb083f..7b7d25cf76a7 100644 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -10,7 +10,15 @@ namespace Microsoft.Maui { public class LayoutCanvas : Canvas, IMeasurable { - public LayoutCanvas(EvasObject parent) : base(parent) { } + Rectangle _arrangeCache; + IView _virtualView; + + public LayoutCanvas(EvasObject parent, IView view) : base(parent) + { + _arrangeCache = default(Rectangle); + _virtualView = view; + LayoutUpdated += OnLayoutUpdated; + } public TSize Measure(double availableWidth, double availableHeight) { @@ -19,5 +27,21 @@ public TSize Measure(double availableWidth, double availableHeight) internal Func? CrossPlatformMeasure { get; set; } internal Func? CrossPlatformArrange { get; set; } + + protected void OnLayoutUpdated(object? sender, LayoutEventArgs e) + { + var nativeGeometry = Geometry.ToDP(); + + if (_arrangeCache == nativeGeometry) + return; + + if (nativeGeometry.Width > 0 && nativeGeometry.Height > 0) + { + nativeGeometry.X = _virtualView.Frame.X; + nativeGeometry.Y = _virtualView.Frame.Y; + CrossPlatformMeasure!(nativeGeometry.Width, nativeGeometry.Height); + CrossPlatformArrange!(nativeGeometry); + } + } } } From a000c961bd9efa33875e3f692371ccb46f186f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 13 Aug 2021 13:16:27 +0900 Subject: [PATCH 042/266] Fix layout measure issue (#100) --- src/Core/src/Platform/Tizen/LayoutCanvas.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs index 7b7d25cf76a7..edb4aeea3f04 100644 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -2,9 +2,9 @@ using ElmSharp; using Tizen.UIExtensions.Common; using Tizen.UIExtensions.ElmSharp; -using TSize = Tizen.UIExtensions.Common.Size; -using Size = Microsoft.Maui.Graphics.Size; using Rectangle = Microsoft.Maui.Graphics.Rectangle; +using Size = Microsoft.Maui.Graphics.Size; +using TSize = Tizen.UIExtensions.Common.Size; namespace Microsoft.Maui { @@ -37,8 +37,8 @@ protected void OnLayoutUpdated(object? sender, LayoutEventArgs e) if (nativeGeometry.Width > 0 && nativeGeometry.Height > 0) { - nativeGeometry.X = _virtualView.Frame.X; - nativeGeometry.Y = _virtualView.Frame.Y; + nativeGeometry.X = 0; + nativeGeometry.Y = 0; CrossPlatformMeasure!(nativeGeometry.Width, nativeGeometry.Height); CrossPlatformArrange!(nativeGeometry); } From ddf4e8d61646a174a32719d272e8daeaf4a0ba39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 20 Aug 2021 10:26:36 +0900 Subject: [PATCH 043/266] Fix LayoutHandler Update issue (#103) * Fix LayoutHandler Update issue * Implement InvalidateMeasure propagation * Update MapBackground --- src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs | 3 +++ src/Core/src/Platform/Tizen/LayoutCanvas.cs | 12 +++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs index 167d09886bb3..0f44ad28dc2e 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs @@ -174,7 +174,10 @@ public void Update(int index, IView child) _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + var toBeRemoved = NativeView.Children[index]; NativeView.Children.RemoveAt(index); + toBeRemoved.Unrealize(); + NativeView.Children.Insert(index, child.ToNative(MauiContext)); if (child.Handler is INativeViewHandler childHandler) { diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs index edb4aeea3f04..ce070524867e 100644 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -10,12 +10,11 @@ namespace Microsoft.Maui { public class LayoutCanvas : Canvas, IMeasurable { - Rectangle _arrangeCache; IView _virtualView; + Size _measureCache; public LayoutCanvas(EvasObject parent, IView view) : base(parent) { - _arrangeCache = default(Rectangle); _virtualView = view; LayoutUpdated += OnLayoutUpdated; } @@ -32,14 +31,17 @@ protected void OnLayoutUpdated(object? sender, LayoutEventArgs e) { var nativeGeometry = Geometry.ToDP(); - if (_arrangeCache == nativeGeometry) - return; + var measured = CrossPlatformMeasure!(nativeGeometry.Width, nativeGeometry.Height); + if (measured != _measureCache) + { + _virtualView?.Parent?.InvalidateMeasure(); + } + _measureCache = measured; if (nativeGeometry.Width > 0 && nativeGeometry.Height > 0) { nativeGeometry.X = 0; nativeGeometry.Y = 0; - CrossPlatformMeasure!(nativeGeometry.Width, nativeGeometry.Height); CrossPlatformArrange!(nativeGeometry); } } From 9afce5d9dc7855945f632e8a3407efe37c9ef8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 23 Aug 2021 13:47:25 +0900 Subject: [PATCH 044/266] Add InitializationOptions (#107) * Add InitializationOptions * Set UseSkiaSharp true as default * Apply DP as default --- src/Compatibility/Core/src/AppHostBuilderExtensions.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs index b0aeb898259e..db525316c74f 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs @@ -43,6 +43,14 @@ using StreamImagesourceHandler = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.StreamImageSourceHandler; using ImageLoaderSourceHandler = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.UriImageSourceHandler; using DefaultRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.DefaultRenderer; +using FrameRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.FrameRenderer; +using ImageRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.ImageRenderer; +using EllipseRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.EllipseRenderer; +using LineRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.LineRenderer; +using PathRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.PathRenderer; +using PolygonRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.PolygonRenderer; +using PolylineRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.PolylineRenderer; +using RectangleRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp.RectangleRenderer; #endif namespace Microsoft.Maui.Controls.Compatibility.Hosting From 44f1701c5aea0c26a4998b506413d80f58e71301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 23 Aug 2021 16:15:29 +0900 Subject: [PATCH 045/266] Fix SKClipperView to have proper size (#115) --- src/Core/src/Platform/Tizen/WrapperView.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index efb0664f346c..4b5f93dc64d4 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -321,7 +321,9 @@ public static void SetClipperCanvas(this EvasObject target, SKClipperView clippe public class SKClipperView : SKCanvasView { - public SKClipperView(EvasObject parent) : base(parent) { } + public SKClipperView(EvasObject parent) : base(parent) { + IgnorePixelScaling = true; + } public bool ClippingRequired { get; set; } From 381069fa4264c1eb4da9729bb93c14cf8bafcec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 23 Aug 2021 16:51:01 +0900 Subject: [PATCH 046/266] Fix Essentials sample (#108) * Fix Essentials sample for Tizen * Remove UseSkiaSharp flag * Remove MaterialComponents * Fix Tizen flag * Remove CustomRenderer --- .../samples/Samples/Essentials.Sample.csproj | 7 ++++++- .../samples/Samples/Platforms/Tizen/Program.cs | 2 +- src/Essentials/samples/Samples/Startup.cs | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Essentials/samples/Samples/Essentials.Sample.csproj b/src/Essentials/samples/Samples/Essentials.Sample.csproj index 68d4e6d739e1..59ae2ce826ee 100644 --- a/src/Essentials/samples/Samples/Essentials.Sample.csproj +++ b/src/Essentials/samples/Samples/Essentials.Sample.csproj @@ -30,6 +30,11 @@ + + + + + @@ -47,4 +52,4 @@ - \ No newline at end of file + diff --git a/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs b/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs index 4602bc64c8f2..ba600d072e83 100644 --- a/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs +++ b/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs @@ -13,4 +13,4 @@ static void Main(string[] args) app.Run(args); } } -} +} \ No newline at end of file diff --git a/src/Essentials/samples/Samples/Startup.cs b/src/Essentials/samples/Samples/Startup.cs index b85505ad73d9..539c469ddc68 100644 --- a/src/Essentials/samples/Samples/Startup.cs +++ b/src/Essentials/samples/Samples/Startup.cs @@ -30,6 +30,21 @@ public static MauiApp CreateMauiApp() essentials.OnAppAction(App.HandleAppActions); }); +#if TIZEN + builder + .ConfigureServices(services => + { + services.AddTransient((_) => + { + var option = new InitializationOptions + { + DisplayResolutionUnit = DisplayResolutionUnit.DP(true), + }; + return option; + }); +#endif + }); + return builder.Build(); } } From d033d84a379cf70899bf0e78dfcf0895d6e43034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=B1=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 23 Aug 2021 19:15:02 +0900 Subject: [PATCH 047/266] Add ShellHandler (#64) * Add ShellHandler * Move ShellView into Platform/Tizen * Update ShellView * Move the code for embedded tizen resources to csproj * Add UIExtenstions for shell --- .../Tizen/Extensions/ShellExtensions.cs | 2 +- .../Platform/Tizen/Resources/arrow_left.png | Bin 0 -> 490 bytes .../Tizen/Resources/dots_horizontal.png | Bin 0 -> 419 bytes .../Core/Platform/Tizen/Resources/menu.png | Bin 0 -> 417 bytes .../Platform/Tizen/Shell/ShellSectionView.cs | 376 ++++++++++++++++++ .../Tizen.UIExtensions/INavigationView.cs | 24 ++ .../Tizen/Shell/Tizen.UIExtensions/ITabs.cs | 30 ++ .../Tizen.UIExtensions/NavigationView.cs | 205 ++++++++++ .../Tizen/Shell/Tizen.UIExtensions/Tabs.cs | 35 ++ .../Tizen.UIExtensions/ThemeConstants.cs | 25 ++ 10 files changed, 696 insertions(+), 1 deletion(-) create mode 100644 src/Controls/src/Core/Platform/Tizen/Resources/arrow_left.png create mode 100644 src/Controls/src/Core/Platform/Tizen/Resources/dots_horizontal.png create mode 100644 src/Controls/src/Core/Platform/Tizen/Resources/menu.png create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs diff --git a/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs index fc30d0f8f202..53b70de2c3d3 100644 --- a/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs @@ -14,4 +14,4 @@ public static DrawerBehavior ToPlatform(this FlyoutBehavior behavior) return DrawerBehavior.Drawer; } } -} \ No newline at end of file +} diff --git a/src/Controls/src/Core/Platform/Tizen/Resources/arrow_left.png b/src/Controls/src/Core/Platform/Tizen/Resources/arrow_left.png new file mode 100644 index 0000000000000000000000000000000000000000..923dfeb34fef7636cd416788a5e63a0e782c54b9 GIT binary patch literal 490 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+K*nlM7srr@!*8$K^D#O~w0$ghaeB$4mmL1u zN=VndfR%Ua@l1g#AZBg%d{)IqvO18)$c9z>fY|)pqQz=^8N{xpsHQv z%kvz39g0e`{Wh?wRqfd{wXPslUi_7!$tjJ+ObZ^>9NIVI%9>E0)F8vU<~hYP&*>kV z_bY3$OEu8hswJ)wB`Jv|saDBFsX&Us$iUE2*T7iU$Rfnh$ja2f%Gg}nz`)ADK-@hP z6dVW*x%nxXX_dG&q)EMP0BX|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+Kt_tEi(^Q{;kTCzxf%=vTrMU|+8nJAKfQsj&e~cXmcv2Erg#_GFs<>6xUFz`3Ul>!lrT4@f-?e^I zZ`)~H4$XMEWAD_R;m2m25{PcDoikCz^VbE&TR(+f`^(mWoTFOe8c~vxSdwa$T$Bo= z7>o=IEp-iyb&V`S42`TzO{@$Iv<(b^WN6D7Z4?c;`6-!cmAEyi+$@<6)Sv;fp|~vF zDk-rzRkyS#lOZiLC)G+{U%w=`KtDGzJu^95*V54?(BCLOE4y2A9Z(O0r>mdKI;Vst E0GM@v1^@s6 literal 0 HcmV?d00001 diff --git a/src/Controls/src/Core/Platform/Tizen/Resources/menu.png b/src/Controls/src/Core/Platform/Tizen/Resources/menu.png new file mode 100644 index 0000000000000000000000000000000000000000..6dcfc0575a1d6c10f34cf6df4933ce31b21ccf02 GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+eS5K)hhiu0R{01Y44~ zy9wy$!fk$L9koEv$x0Bg+Kt__Mi(^Q{;kVZUxf&D%S{~kfk#J9^|Jm7P z*M&HpZnXS+UnrO^DKLeB;e1Z`^Od##zLheb)@M1>RhO{aL(B80uF|d24g7qfp6*GS z+gqnqe_Pyk>$bOAO4`HqKkC-(6JS_S%+#a$)V%xH<2;~kswJ)wB`Jv|saDBFsX&Us z$iUE2*T7iU$Rfnh$ja2%%Gglbz`)ADVE%&JAnzkI _contentCache = new Dictionary(); + Dictionary _contentToTabsItem = new Dictionary(); + Dictionary _itemToContent = new Dictionary(); + List _tabsItems = new List(); + + EColor _backgroundColor = ShellView.DefaultBackgroundColor; + EColor _foregroundColor = ShellView.DefaultForegroundColor; + + bool _disposed = false; + + public ShellSectionView(ShellSection section, IMauiContext context) + { + ShellSection = section; + MauiContext = context; + ShellSection.PropertyChanged += OnSectionPropertyChanged; + (ShellSection.Items as INotifyCollectionChanged).CollectionChanged += OnShellSectionCollectionChanged; + + _mainLayout = new EBox(NativeParent); + _mainLayout.SetLayoutCallback(OnLayout); + + _contentArea = new EBox(NativeParent); + _contentArea.Show(); + _mainLayout.PackEnd(_contentArea); + + UpdateTabsItem(); + UpdateCurrentItem(ShellSection.CurrentItem); + + ((IShellController)Shell.Current).AddAppearanceObserver(this, ShellSection); + (ShellSection as IShellSectionController).AddDisplayedPageObserver(this, UpdateDisplayedPage); + } + + bool HasTabs => _tabs != null; + + bool _tabBarIsVisible = true; + + protected IMauiContext MauiContext { get; private set; } + + protected EvasObject NativeParent + { + get => MauiContext?.Context?.BaseLayout; + } + + protected virtual bool TabBarIsVisible + { + get => _tabBarIsVisible; + set + { + if (_tabBarIsVisible != value) + { + _tabBarIsVisible = value; + _mainLayout.MarkChanged(); + + if (value) + { + _tabs?.Show(); + } + else + { + _tabs?.Hide(); + } + } + } + } + + public ShellSection ShellSection { get; } + + public EvasObject NativeView + { + get + { + return _mainLayout; + } + } + + public EColor ToolbarBackgroundColor + { + get + { + return _backgroundColor; + } + set + { + _backgroundColor = value; + UpdateToolbarBackgroudColor(_backgroundColor); + } + } + + public EColor ToolbarForegroundColor + { + get + { + return _foregroundColor; + } + set + { + _foregroundColor = value; + UpdateToolbarForegroundColor(_foregroundColor); + } + } + + ~ShellSectionView() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance) + { + var backgroundColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarBackgroundColor; + var foregroundColor = appearance?.ForegroundColor; + ToolbarBackgroundColor = backgroundColor.IsDefault() ? ShellView.DefaultBackgroundColor : backgroundColor.ToNativeEFL(); + ToolbarForegroundColor = foregroundColor.IsDefault() ? ShellView.DefaultForegroundColor : foregroundColor.ToNativeEFL(); + } + + void UpdateDisplayedPage(Page page) + { + if (_displayedPage != null) + { + _displayedPage.PropertyChanged -= OnDisplayedPagePropertyChanged; + } + + if (page == null) + { + TabBarIsVisible = true; + return; + } + _displayedPage = page; + _displayedPage.PropertyChanged += OnDisplayedPagePropertyChanged; + TabBarIsVisible = Shell.GetTabBarIsVisible(page); + } + + void OnDisplayedPagePropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == Shell.TabBarIsVisibleProperty.PropertyName) + { + TabBarIsVisible = Shell.GetTabBarIsVisible(_displayedPage); + } + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + ((IShellController)Shell.Current).RemoveAppearanceObserver(this); + if (ShellSection != null) + { + (ShellSection as IShellSectionController).RemoveDisplayedPageObserver(this); + ShellSection.PropertyChanged -= OnSectionPropertyChanged; + DeinitializeTabs(); + + foreach (var native in _contentCache.Values) + { + native.Unrealize(); + } + _contentCache.Clear(); + _contentToTabsItem.Clear(); + _itemToContent.Clear(); + } + NativeView.Unrealize(); + } + _disposed = true; + } + + void InitializeTabs() + { + if (_tabs != null) + { + return; + } + _tabs = new Tabs(NativeParent); + _tabs.Show(); + _tabs.BackgroundColor = _backgroundColor; + _tabs.Scrollable = TabsType.Fixed; + _tabs.Selected += OnTabsSelected; + _mainLayout.PackEnd(_tabs); + } + + void ClearTabsItem() + { + if (!HasTabs) + return; + + foreach (var item in _tabsItems) + { + item.Delete(); + } + _tabsItems.Clear(); + _contentToTabsItem.Clear(); + _itemToContent.Clear(); + } + + void DeinitializeTabs() + { + if (_tabs == null) + { + return; + } + ClearTabsItem(); + _tabs.Unrealize(); + _tabs = null; + } + + void OnSectionPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "CurrentItem") + { + UpdateCurrentItem(ShellSection.CurrentItem); + } + } + + void UpdateCurrentItem(ShellContent content) + { + UpdateCurrentShellContent(content); + if (_contentToTabsItem.ContainsKey(content)) + { + _contentToTabsItem[content].IsSelected = true; + } + } + + void UpdateToolbarBackgroudColor(EColor color) + { + foreach (EToolbarItem item in _tabsItems) + { + item.SetBackgroundColor(color); + } + } + + void UpdateToolbarForegroundColor(EColor color) + { + foreach (EToolbarItem item in _tabsItems) + { + item.SetUnderlineColor(color); + } + } + + void UpdateTabsItem() + { + if (ShellSection.Items.Count <= 1) + { + DeinitializeTabs(); + return; + } + + InitializeTabs(); + ClearTabsItem(); + foreach (ShellContent content in ShellSection.Items) + { + InsertTabsItem(content); + } + _tabs.Scrollable = ShellSection.Items.Count > 3 ? TabsType.Scrollable : TabsType.Fixed; + } + + EToolbarItem InsertTabsItem(ShellContent content) + { + EToolbarItem item = _tabs.Append(content.Title, null); + item.SetBackgroundColor(_backgroundColor); + item.SetUnderlineColor(_foregroundColor); + + _tabsItems.Add(item); + _itemToContent[item] = content; + _contentToTabsItem[content] = item; + return item; + } + + void OnShellSectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + UpdateTabsItem(); + } + + void OnTabsSelected(object sender, EToolbarItemEventArgs e) + { + if (_tabs.SelectedItem == null) + { + return; + } + + ShellContent content = _itemToContent[_tabs.SelectedItem]; + if (ShellSection.CurrentItem != content) + { + ShellSection.SetValueFromRenderer(ShellSection.CurrentItemProperty, content); + } + } + + void UpdateCurrentShellContent(ShellContent content) + { + if (_currentContent != null) + { + _currentContent.Hide(); + _contentArea.UnPack(_currentContent); + _currentContent = null; + } + + if (content == null) + { + return; + } + + if (!_contentCache.ContainsKey(content)) + { + var native = CreateShellContent(content); + native.SetAlignment(-1, -1); + native.SetWeight(1, 1); + _contentCache[content] = native; + } + _currentContent = _contentCache[content]; + _currentContent.Show(); + _contentArea.PackEnd(_currentContent); + } + + EvasObject CreateShellContent(ShellContent content) + { + Page xpage = ((IShellContentController)content).GetOrCreateContent(); + return xpage.ToNative(MauiContext); + } + + void OnLayout() + { + if (NativeView.Geometry.Width == 0 || NativeView.Geometry.Height == 0) + return; + var bound = NativeView.Geometry; + + int tabsHeight; + if (HasTabs && TabBarIsVisible) + { + var tabsBound = bound; + tabsHeight = _tabs.MinimumHeight; + tabsBound.Height = tabsHeight; + _tabs.Geometry = tabsBound; + } + else + { + tabsHeight = 0; + } + + var contentBound = bound; + contentBound.Y += tabsHeight; + contentBound.Height -= tabsHeight; + _contentArea.Geometry = contentBound; + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs new file mode 100644 index 000000000000..8a89f957ee94 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs @@ -0,0 +1,24 @@ +using System; +using ElmSharp; +using Tizen.UIExtensions.Common; +using EColor = ElmSharp.Color; + +namespace Tizen.UIExtensions.Shell +{ + public interface INavigationView + { + EvasObject TargetView { get; } + + EvasObject Header { get; set; } + + EvasObject Footer { get; set; } + + EvasObject Content { get; set; } + + EColor BackgroundColor { get; set; } + + EvasObject BackgroundImage { get; set; } + + event EventHandler LayoutUpdated; + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs new file mode 100644 index 000000000000..2f7c7c1c6223 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs @@ -0,0 +1,30 @@ +using System; +using ElmSharp; +using EColor = ElmSharp.Color; +using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; + +namespace Tizen.UIExtensions.Shell +{ + public interface ITabs + { + TabsType Scrollable { get; set; } + + EColor BackgroundColor { get; set; } + + ToolbarItem SelectedItem { get; } + + event EventHandler Selected; + + ToolbarItem Append(string label, string icon); + + ToolbarItem Append(string label); + + ToolbarItem InsertBefore(ToolbarItem before, string label, string icon); + } + + public enum TabsType + { + Fixed, + Scrollable + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs new file mode 100644 index 000000000000..72fcb594a9ca --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs @@ -0,0 +1,205 @@ +using ElmSharp; +using System; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using EColor = ElmSharp.Color; +using EBox = ElmSharp.Box; + +namespace Tizen.UIExtensions.Shell +{ + ///

- + \ No newline at end of file diff --git a/src/Workload/Microsoft.NET.Sdk.Maui/WorkloadManifest.in.json b/src/Workload/Microsoft.NET.Sdk.Maui/WorkloadManifest.in.json index 2c0e318fee86..341426f01a2a 100644 --- a/src/Workload/Microsoft.NET.Sdk.Maui/WorkloadManifest.in.json +++ b/src/Workload/Microsoft.NET.Sdk.Maui/WorkloadManifest.in.json @@ -119,6 +119,21 @@ "Microsoft.Maui.Essentials.Ref.tizen", "Microsoft.Maui.Essentials.Runtime.tizen" ] + }, + "maui-tizen": { + "description": ".NET MAUI SDK for Tizen", + "extends": [ + "maui-core", + "tizen" + ], + "packs": [ + "Microsoft.Maui.Core.Ref.tizen", + "Microsoft.Maui.Core.Runtime.tizen", + "Microsoft.Maui.Controls.Ref.tizen", + "Microsoft.Maui.Controls.Runtime.tizen", + "Microsoft.Maui.Essentials.Ref.tizen", + "Microsoft.Maui.Essentials.Runtime.tizen" + ] } }, "packs": { From 20c15baaefae40be3f49faef8b6cf3e9318e3ae7 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 26 Aug 2021 14:30:07 +0900 Subject: [PATCH 049/266] Fix build and runtime error after bumping to latest code --- src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs index 5e4587b1ce82..d63099842bb0 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs @@ -46,6 +46,10 @@ public static Task MapImageSourceAsync(IButtonHandler handler, IImage image) return handler.ImageSourceLoader.UpdateImageSourceAsync(); } + //TODO : Need to impl + [MissingMapper] + public static void MapImageSource(ButtonHandler handler, IButton image) { } + [MissingMapper] public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button) { } From 945303902bc0146569affa0936b3c54f422c18dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 26 Aug 2021 17:02:02 +0900 Subject: [PATCH 050/266] Fix HandlerToRendererShim dispose (#127) --- src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs index c183ec309af1..fe07cba3ba82 100644 --- a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs +++ b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs @@ -75,7 +75,6 @@ public void SetElement(VisualElement element) NativeView.Deleted += OnNativeDeleted; ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(oldElement, Element)); - } void OnBatchCommitted(object sender, EventArg e) From a816554ea077a0cfda9e18cc75b500b24b0ad2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=B1=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 26 Aug 2021 17:02:40 +0900 Subject: [PATCH 051/266] Add ShellSearchView (#121) * Add ShellSearchView * Fix the layout issue in ShellSearchResultList * Enable nullable * Fix maximum height of ShellSearchResultList --- .../Tizen.UIExtensions/SearchBarExtensions.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/SearchBarExtensions.cs diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/SearchBarExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/SearchBarExtensions.cs new file mode 100644 index 000000000000..c49eb6095309 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/SearchBarExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.Maui.Controls; +using TFontAttributes = Tizen.UIExtensions.Common.FontAttributes; + +namespace Tizen.UIExtensions.Shell +{ + public static class SearchBarExtensions + { + + public static TFontAttributes ToNative(this FontAttributes fontAttribute) + { + TFontAttributes attributes = TFontAttributes.None; + if (fontAttribute == FontAttributes.Italic) + attributes = attributes | TFontAttributes.Italic; + + if (fontAttribute == FontAttributes.Bold) + attributes = attributes | TFontAttributes.Bold; + + return attributes; + } + } +} From 78db18f62868250c9dbdf804f0da09b39deb4f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 26 Aug 2021 19:24:39 +0900 Subject: [PATCH 052/266] Fix scaling issue on Clip (#130) --- src/Core/src/Platform/Tizen/WrapperView.cs | 49 +++++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index 4b5f93dc64d4..b77907f0c83a 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -319,13 +319,34 @@ public static void SetClipperCanvas(this EvasObject target, SKClipperView clippe internal static extern IntPtr elm_object_part_content_get(IntPtr obj, string part); } + public class DrawClipEventArgs : EventArgs + { + public DrawClipEventArgs(ICanvas canvas, RectangleF dirtyRect) + { + Canvas = canvas; + DirtyRect = dirtyRect; + } + + public ICanvas Canvas { get; set; } + + public RectangleF DirtyRect { get; set; } + } + public class SKClipperView : SKCanvasView { - public SKClipperView(EvasObject parent) : base(parent) { - IgnorePixelScaling = true; + private SkiaCanvas _canvas; + private ScalingCanvas _scalingCanvas; + + public SKClipperView(EvasObject parent) : base(parent) + { + _canvas = new SkiaCanvas(); + _scalingCanvas = new ScalingCanvas(_canvas); + PaintSurface += OnPaintSurface; } + public float DeviceScalingFactor { get; set; } public bool ClippingRequired { get; set; } + public event EventHandler? DrawClip; public new void Invalidate() { @@ -333,6 +354,30 @@ public SKClipperView(EvasObject parent) : base(parent) { OnDrawFrame(); ClippingRequired = false; } + + protected virtual void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) + { + var skiaCanvas = e.Surface.Canvas; + skiaCanvas.Clear(); + + _canvas.Canvas = skiaCanvas; + _scalingCanvas.ResetState(); + + float width = e.Info.Width; + float height = e.Info.Height; + if (DeviceScalingFactor > 0) + { + width = width / DeviceScalingFactor; + height = height / DeviceScalingFactor; + } + + _scalingCanvas.SaveState(); + + if (DeviceScalingFactor > 0) + _scalingCanvas.Scale(DeviceScalingFactor, DeviceScalingFactor); + DrawClip?.Invoke(this, new DrawClipEventArgs(_scalingCanvas, new RectangleF(0, 0, width, height))); + _scalingCanvas.RestoreState(); + } } public static class ClipperExtension From b9239ac284ae65a85240c61ccbf415869cd3ff41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 27 Aug 2021 08:07:46 +0900 Subject: [PATCH 053/266] Fix DisplayResolutionUnit sync issue (#134) --- .../src/Platform/Tizen/CoreUIAppContext.cs | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index 9fcc6dfb728e..135a534276b5 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -12,9 +12,6 @@ namespace Microsoft.Maui { public class CoreUIAppContext { - DisplayResolutionUnit _displayResolutionUnit = DisplayResolutionUnit.DP; - double _viewPortWidth = -1; - static CoreUIAppContext? _instance = null; Func? _handleBackButtonPressed; @@ -46,27 +43,6 @@ public static CoreUIAppContext GetInstance(CoreApplication application, Window? public DeviceType DeviceType => DeviceInfo.GetDeviceType(); - public DisplayResolutionUnit DisplayResolutionUnit - { - get => _displayResolutionUnit; - set - { - _displayResolutionUnit = value; - DeviceInfo.DisplayResolutionUnit = _displayResolutionUnit; - } - } - - public double ViewportWidth - { - get => _viewPortWidth; - set - { - _viewPortWidth = value; - // TODO. DeviceInfo.ViewportWidth is readonly, fix it - //ViewportWidth = _viewPortWidth; - } - } - protected CoreUIAppContext(CoreApplication application) : this(application, CreateDefaultWindow()) { } @@ -76,9 +52,6 @@ protected CoreUIAppContext(CoreApplication application, Window window) _ = application ?? throw new ArgumentNullException(nameof(application)); _ = window ?? throw new ArgumentNullException(nameof(window)); - if (DisplayResolutionUnit == DisplayResolutionUnit.VP && ViewportWidth < 0) - throw new InvalidOperationException($"ViewportWidth should be set in case of DisplayResolutionUnit == VP"); - Elementary.Initialize(); Elementary.ThemeOverlay(); CurrentApplication = application; From 6b4b9e79b7745d0e08abb18668a3b2509e7c9b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 30 Aug 2021 13:14:15 +0900 Subject: [PATCH 054/266] Fix build error (#137) --- src/Core/src/Platform/Tizen/WrapperView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index b77907f0c83a..dc00458b1c0f 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -355,7 +355,7 @@ public SKClipperView(EvasObject parent) : base(parent) ClippingRequired = false; } - protected virtual void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) + protected virtual void OnPaintSurface(object? sender, SKPaintSurfaceEventArgs e) { var skiaCanvas = e.Surface.Canvas; skiaCanvas.Clear(); From 7717240baa51b9ef1c8be001d31be4962d01240b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 30 Aug 2021 13:57:17 +0900 Subject: [PATCH 055/266] Replace SkiaGraphicsView with local patch (#135) This commit will be revert when upstream code is updated --- .../Platform/Tizen/GraphicsViewExtensions.cs | 1 + src/Core/src/Platform/Tizen/MauiShapeView.cs | 1 + .../Platform/Tizen/SkiaGraphicsView.Tizen.cs | 62 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 src/Core/src/Platform/Tizen/SkiaGraphicsView.Tizen.cs diff --git a/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs b/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs index b6ee57a02f82..b6168716a04b 100644 --- a/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs @@ -1,4 +1,5 @@ using Microsoft.Maui.Graphics.Skia.Views; +using SkiaGraphicsView = Microsoft.Maui.Platform.Tizen.SkiaGraphicsView; namespace Microsoft.Maui.Platform { diff --git a/src/Core/src/Platform/Tizen/MauiShapeView.cs b/src/Core/src/Platform/Tizen/MauiShapeView.cs index 6baeb99bccdc..027f1422c136 100644 --- a/src/Core/src/Platform/Tizen/MauiShapeView.cs +++ b/src/Core/src/Platform/Tizen/MauiShapeView.cs @@ -1,5 +1,6 @@ using ElmSharp; using Microsoft.Maui.Graphics.Skia.Views; +using SkiaGraphicsView = Microsoft.Maui.Platform.Tizen.SkiaGraphicsView; namespace Microsoft.Maui.Platform { diff --git a/src/Core/src/Platform/Tizen/SkiaGraphicsView.Tizen.cs b/src/Core/src/Platform/Tizen/SkiaGraphicsView.Tizen.cs new file mode 100644 index 000000000000..84cdea6fd9a7 --- /dev/null +++ b/src/Core/src/Platform/Tizen/SkiaGraphicsView.Tizen.cs @@ -0,0 +1,62 @@ +#nullable disable +using ElmSharp; +using SkiaSharp.Views.Tizen; +using Microsoft.Maui.Graphics; +using Microsoft.Maui.Graphics.Skia; + +namespace Microsoft.Maui.Platform.Tizen +{ + // TODO. Remove it + // This class a temporary used, until Microsoft.Maui.Graphics.Skia.Views.SkiaGraphicsView is updated on upstream. + public class SkiaGraphicsView : SKCanvasView + { + private IDrawable _drawable; + private SkiaCanvas _canvas; + private ScalingCanvas _scalingCanvas; + + public SkiaGraphicsView(EvasObject parent, IDrawable drawable = null) : base(parent) + { + _canvas = new SkiaCanvas(); + _scalingCanvas = new ScalingCanvas(_canvas); + Drawable = drawable; + PaintSurface += OnPaintSurface; + } + + public float DeviceScalingFactor { get; set; } + + public IDrawable Drawable + { + get => _drawable; + set + { + _drawable = value; + Invalidate(); + } + } + + protected virtual void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) + { + if (_drawable == null) return; + + var skiaCanvas = e.Surface.Canvas; + skiaCanvas.Clear(); + + _canvas.Canvas = skiaCanvas; + _scalingCanvas.ResetState(); + + float width = e.Info.Width; + float height = e.Info.Height; + if (DeviceScalingFactor > 0) + { + width = width / DeviceScalingFactor; + height = height / DeviceScalingFactor; + } + + _scalingCanvas.SaveState(); + if (DeviceScalingFactor > 0) + _scalingCanvas.Scale(DeviceScalingFactor, DeviceScalingFactor); + _drawable.Draw(_scalingCanvas, new RectangleF(0, 0, width, height)); + _scalingCanvas.RestoreState(); + } + } +} From 7c662c4331f4734888a13fa1b73ccee91a7ac90c Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 31 Aug 2021 10:54:28 +0900 Subject: [PATCH 056/266] Support Min/Max Height/Width on IView and applying MauiApp/MauiAppBuilder pattern - Support Min/Max Height/Width on IView (#2265) - Updating .NET MAUI to use MauiApp/MauiAppBuilder pattern and use MS.Extensions.DependencyInjection (#2137) --- src/Core/src/Platform/Tizen/MauiApplication.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index f5b52c59508e..cc75ecd8e481 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -21,7 +21,13 @@ protected MauiApplication() protected override void OnPreCreate() { - base.OnPreCreate(); + get + { + IWindow? window = null; + _virtualWindow?.TryGetTarget(out window); + return window; + } + } Elementary.Initialize(); Elementary.ThemeOverlay(); @@ -38,10 +44,11 @@ protected override void OnPreCreate() Services = _applicationContext.Services; - if (Services == null) - throw new InvalidOperationException($"The {nameof(IServiceProvider)} instance was not found."); + var mauiApp = CreateMauiApp(); + + Services = mauiApp.Services; - Current.Services.InvokeLifecycleEvents(del => del(this)); + Current.Services?.InvokeLifecycleEvents(del => del(this)); } protected override void OnCreate() From a907a423c1136b4514ff086a9d29ce131b8b0519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 1 Sep 2021 09:00:06 +0900 Subject: [PATCH 057/266] Fix Tizen Templates (#144) --- .../MauiApp1/Platforms/Tizen/Main.cs | 21 ------------------- .../Platforms/Tizen/tizen-manifest.xml | 15 ------------- .../MauiApp1/Platforms/Tizen/Main.cs | 21 ------------------- .../Platforms/Tizen/tizen-manifest.xml | 15 ------------- 4 files changed, 72 deletions(-) delete mode 100644 src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs delete mode 100644 src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml delete mode 100644 src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs delete mode 100644 src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs deleted file mode 100644 index 731ac52155eb..000000000000 --- a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Microsoft.Maui; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Controls.Compatibility; - -namespace MauiApp1 -{ - class Program : MauiApplication - { - protected override void OnCreate() - { - base.OnCreate(); - } - - static void Main(string[] args) - { - var app = new Program(); - app.Run(args); - } - } -} diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml deleted file mode 100644 index 5847c71b195d..000000000000 --- a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - appicon.xhigh.png - - - - - http://tizen.org/privilege/internet - - - - \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs deleted file mode 100644 index 731ac52155eb..000000000000 --- a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Microsoft.Maui; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Controls.Compatibility; - -namespace MauiApp1 -{ - class Program : MauiApplication - { - protected override void OnCreate() - { - base.OnCreate(); - } - - static void Main(string[] args) - { - var app = new Program(); - app.Run(args); - } - } -} diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml deleted file mode 100644 index 5847c71b195d..000000000000 --- a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - appicon.xhigh.png - - - - - http://tizen.org/privilege/internet - - - - \ No newline at end of file From f5f09a0a1525d290d8c92e53b6a734b301a833b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 1 Sep 2021 13:08:51 +0900 Subject: [PATCH 058/266] Fix webview break caused by updated dependency (#143) --- src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs index e3e58bd8554f..d4cdf0de679f 100644 --- a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs +++ b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Microsoft.AspNetCore.Components.Web; using Microsoft.Extensions.FileProviders; using Microsoft.Maui; using Microsoft.Maui.Dispatching; From 812d623683c77767c3ab48eff4c11d03e6cab419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 1 Sep 2021 16:15:59 +0900 Subject: [PATCH 059/266] Update the Tizen.UIExtension.ElmSharp version (#145) --- .../Microsoft.Maui.Dependencies.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj b/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj index 4b29e672015f..b37ce29104e2 100644 --- a/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj +++ b/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj @@ -38,4 +38,4 @@ - \ No newline at end of file + From 306ed66c239d79f63f10886758f4405f05ef504d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=B1=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 1 Sep 2021 20:06:50 +0900 Subject: [PATCH 060/266] Reomve internal UIExtensions compoments for Shell (#147) --- .../Platform/Tizen/Shell/ShellSectionView.cs | 1 - .../Tizen.UIExtensions/INavigationView.cs | 24 -- .../Tizen/Shell/Tizen.UIExtensions/ITabs.cs | 30 --- .../Tizen.UIExtensions/NavigationView.cs | 205 ------------------ .../Tizen.UIExtensions/SearchBarExtensions.cs | 21 -- .../Tizen/Shell/Tizen.UIExtensions/Tabs.cs | 35 --- .../Tizen.UIExtensions/ThemeConstants.cs | 25 --- 7 files changed, 341 deletions(-) delete mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs delete mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs delete mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs delete mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/SearchBarExtensions.cs delete mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs delete mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs index 8ecd27799ed1..306b0809134a 100644 --- a/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs @@ -4,7 +4,6 @@ using System.ComponentModel; using ElmSharp; using Tizen.UIExtensions.ElmSharp; -using Tizen.UIExtensions.Shell; using EBox = ElmSharp.Box; using EColor = ElmSharp.Color; using EToolbarItem = ElmSharp.ToolbarItem; diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs deleted file mode 100644 index 8a89f957ee94..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using ElmSharp; -using Tizen.UIExtensions.Common; -using EColor = ElmSharp.Color; - -namespace Tizen.UIExtensions.Shell -{ - public interface INavigationView - { - EvasObject TargetView { get; } - - EvasObject Header { get; set; } - - EvasObject Footer { get; set; } - - EvasObject Content { get; set; } - - EColor BackgroundColor { get; set; } - - EvasObject BackgroundImage { get; set; } - - event EventHandler LayoutUpdated; - } -} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs deleted file mode 100644 index 2f7c7c1c6223..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using ElmSharp; -using EColor = ElmSharp.Color; -using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; - -namespace Tizen.UIExtensions.Shell -{ - public interface ITabs - { - TabsType Scrollable { get; set; } - - EColor BackgroundColor { get; set; } - - ToolbarItem SelectedItem { get; } - - event EventHandler Selected; - - ToolbarItem Append(string label, string icon); - - ToolbarItem Append(string label); - - ToolbarItem InsertBefore(ToolbarItem before, string label, string icon); - } - - public enum TabsType - { - Fixed, - Scrollable - } -} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs deleted file mode 100644 index 72fcb594a9ca..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs +++ /dev/null @@ -1,205 +0,0 @@ -using ElmSharp; -using System; -using Tizen.UIExtensions.Common; -using Tizen.UIExtensions.ElmSharp; -using EColor = ElmSharp.Color; -using EBox = ElmSharp.Box; - -namespace Tizen.UIExtensions.Shell -{ - /// - /// The native widget that is configured with an header and an list of items to be used in NavigationDrawer. - /// - public class NavigationView : Background, INavigationView - { - static readonly EColor s_defaultBackgroundColor = ElmSharp.ThemeConstants.Shell.ColorClass.DefaultNavigationViewBackgroundColor; - - EBox _mainLayout; - - EvasObject _header; - EvasObject _footer; - EvasObject _content; - - EvasObject _backgroundImage; - EColor _backgroundColor; - - /// - /// Initializes a new instance of the class. - /// - /// Parent evas object. - public NavigationView(EvasObject parent) : base(parent) - { - InitializeComponent(parent); - } - - /// - /// Gets or sets the background color of the NavigtiaonView. - /// - public override EColor BackgroundColor - { - get => _backgroundColor; - set - { - _backgroundColor = value; - EColor effectiveColor = _backgroundColor.IsDefault ? s_defaultBackgroundColor : _backgroundColor; - base.BackgroundColor = effectiveColor; - } - } - - /// - /// Gets or sets the background image of the NavigtiaonView. - /// - public EvasObject BackgroundImage - { - get => _backgroundImage; - set - { - _backgroundImage = value; - this.SetBackgroundPart(_backgroundImage); - } - } - - /// - /// Gets or sets the header view of the NavigtiaonView. - /// - public EvasObject Header - { - get => _header; - set => UpdateHeader(value); - } - - /// - /// Gets or sets the footer view of the NavigtiaonView. - /// - public EvasObject Footer - { - get => _footer; - set => UpdateFooter(value); - } - - public EvasObject Content - { - get => _content; - set => UpdateContent(value); - } - - /// - /// Gets or sets the target view of the NavigtiaonView. - /// - public EvasObject TargetView => this; - - /// - /// Notifies that the layout has been updated. - /// - public event EventHandler LayoutUpdated; - - void InitializeComponent(EvasObject parent) - { - base.BackgroundColor = s_defaultBackgroundColor; - - _mainLayout = new EBox(parent) - { - AlignmentX = -1, - AlignmentY = -1, - WeightX = 1, - WeightY = 1 - }; - _mainLayout.SetLayoutCallback(OnLayout); - _mainLayout.Show(); - - SetContent(_mainLayout); - } - - void OnLayout() - { - if (Geometry.Width == 0 || Geometry.Height == 0) - return; - - var bound = Geometry; - int headerHeight = 0; - int footerHeight = 0; - - if (_header != null) - { - var headerBound = bound; - headerHeight = _header.MinimumHeight; - headerBound.Height = headerHeight; - _header.Geometry = headerBound; - } - - if (_footer != null) - { - var footerbound = bound; - footerHeight = _footer.MinimumHeight; - footerbound.Y = bound.Y + bound.Height - footerHeight; - footerbound.Height = footerHeight; - _footer.Geometry = footerbound; - } - - if (_content != null) - { - bound.Y += headerHeight; - bound.Height = bound.Height - headerHeight - footerHeight; - _content.Geometry = bound; - } - - NotifyOnLayout(); - } - - void NotifyOnLayout() - { - LayoutUpdated?.Invoke(this, new LayoutEventArgs() { Geometry = Geometry.ToCommon() }); - } - - void UpdateHeader(EvasObject header) - { - if (_header != null) - { - _mainLayout.UnPack(_header); - _header.Unrealize(); - _header = null; - } - - if (header != null) - { - _mainLayout.PackStart(header); - } - _header = header; - _header?.Show(); - } - - void UpdateFooter(EvasObject footer) - { - if (_footer != null) - { - _mainLayout.UnPack(_footer); - _footer.Unrealize(); - _footer = null; - } - - if (footer != null) - { - _mainLayout.PackEnd(footer); - } - _footer = footer; - _footer?.Show(); - } - - void UpdateContent(EvasObject content) - { - if (_content != null) - { - _mainLayout.UnPack(_content); - _content.Unrealize(); - _content = null; - } - - if (content != null) - { - _mainLayout.PackEnd(content); - } - _content = content; - _content?.Show(); - } - } -} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/SearchBarExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/SearchBarExtensions.cs deleted file mode 100644 index c49eb6095309..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/SearchBarExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Microsoft.Maui.Controls; -using TFontAttributes = Tizen.UIExtensions.Common.FontAttributes; - -namespace Tizen.UIExtensions.Shell -{ - public static class SearchBarExtensions - { - - public static TFontAttributes ToNative(this FontAttributes fontAttribute) - { - TFontAttributes attributes = TFontAttributes.None; - if (fontAttribute == FontAttributes.Italic) - attributes = attributes | TFontAttributes.Italic; - - if (fontAttribute == FontAttributes.Bold) - attributes = attributes | TFontAttributes.Bold; - - return attributes; - } - } -} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs deleted file mode 100644 index 0046969b13cb..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs +++ /dev/null @@ -1,35 +0,0 @@ -using ElmSharp; -using Tizen.UIExtensions.ElmSharp; -using EToolbar = ElmSharp.Toolbar; - -namespace Tizen.UIExtensions.Shell -{ - public class Tabs : EToolbar, ITabs - { - TabsType _type; - - public Tabs(EvasObject parent) : base(parent) - { - Style = ElmSharp.ThemeConstants.Toolbar.Styles.Material; - SelectionMode = ToolbarSelectionMode.Always; - } - - public TabsType Scrollable - { - get => _type; - set - { - switch (value) - { - case TabsType.Fixed: - this.ShrinkMode = ToolbarShrinkMode.Expand; - break; - case TabsType.Scrollable: - this.ShrinkMode = ToolbarShrinkMode.Scroll; - break; - } - _type = value; - } - } - } -} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs deleted file mode 100644 index b91c87d53211..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs +++ /dev/null @@ -1,25 +0,0 @@ -using EColor = ElmSharp.Color; - -namespace Tizen.UIExtensions.Shell -{ - public class ThemeConstants - { - public class Shell - { - public class ColorClass - { - public static readonly EColor DefaultBackgroundColor = EColor.FromRgb(33, 150, 243); - public static readonly EColor DefaultForegroundColor = EColor.White; - public static readonly EColor DefaultTitleColor = EColor.White; - } - - public class Resources - { - // The source of icon resources is https://materialdesignicons.com/ - public const string MenuIcon = "Platform.Tizen.Resources.menu.png"; - public const string BackIcon = "Platform.Tizen.Resources.arrow_left.png"; - public const string DotsIcon = "Platform.Tizen.Resources.dots_horizontal.png"; - } - } - } -} From 5b030ff83865114c6db051538027dc1f0e4ceec2 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 2 Sep 2021 13:59:06 +0900 Subject: [PATCH 061/266] Adds missing implementation after bumping to latest main --- .../NavigationPageHandler.Tizen.cs | 327 ------------------ 1 file changed, 327 deletions(-) delete mode 100644 src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs diff --git a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs deleted file mode 100644 index c5a52f1259bc..000000000000 --- a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs +++ /dev/null @@ -1,327 +0,0 @@ -#nullable enable - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using ElmSharp; -using Microsoft.Maui.Handlers; -using Tizen.UIExtensions.ElmSharp; -using TButton = Tizen.UIExtensions.ElmSharp.Button; -using TSpan = Tizen.UIExtensions.Common.Span; -using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; - -namespace Microsoft.Maui.Handlers -{ - internal partial class NavigationPageHandler : - ViewHandler, INativeViewHandler - { - readonly List _naviItemContentPartList = new List(); - TaskCompletionSource? _currentTaskSource = null; - IDictionary? _naviItemMap; - - IView? PreviousPage => VirtualView.NavigationStack.Count > 1 ? VirtualView.NavigationStack[VirtualView.NavigationStack.Count - 2] : null; - NaviItem? CurrentNaviItem => NativeView.NavigationStack.Count > 0 ? NativeView.NavigationStack.Last() : null; - NaviItem? PreviousNaviItem => NativeView.NavigationStack.Count > 1 ? NativeView.NavigationStack[NativeView.NavigationStack.Count - 2] : null; - - protected override Naviframe CreateNativeView() - { - return new Naviframe(NativeParent) - { - PreserveContentOnPop = true, - DefaultBackButtonEnabled = false, - }; - } - - private static void PushAsyncTo(NavigationPageHandler arg1, INavigationView arg2, object? arg3) - { - if (arg3 is MauiNavigationRequestedEventArgs args) - arg1.OnPushRequested(args); - } - - private static void PopAsyncTo(NavigationPageHandler arg1, INavigationView arg2, object? arg3) - { - if (arg3 is MauiNavigationRequestedEventArgs args) - arg1.OnPopRequested(args); - } - - void OnPushRequested(MauiNavigationRequestedEventArgs e) - { - _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); - - if (e.Animated || NativeView.NavigationStack.Count == 0) - { - _naviItemMap[e.Page] = NativeView.Push(CreateNavItem(e.Page), SpanTitle(e.Page)); - _currentTaskSource = new TaskCompletionSource(); - e.Task = _currentTaskSource.Task; - - // There is no TransitionFinished (AnimationFinished) event after the first Push - if (NativeView.NavigationStack.Count == 1) - CompleteCurrentNavigationTask(); - } - else - { - _naviItemMap[e.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(e.Page), SpanTitle(e.Page)); - } - //UpdateHasNavigationBar(nre.Page); - } - - void OnPopRequested(MauiNavigationRequestedEventArgs e) - { - _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); - - if (VirtualView.NavigationStack.Count == NativeView.NavigationStack.Count) - { - //e.Page?.SendDisappearing(); - //UpdateNavigationBar(PreviousPage, PreviousNaviItem); - - if (e.Animated) - { - NativeView.Pop(); - - _currentTaskSource = new TaskCompletionSource(); - e.Task = _currentTaskSource.Task; - - // There is no TransitionFinished (AnimationFinished) event after Pop the last page - if (NativeView.NavigationStack.Count == 0) - CompleteCurrentNavigationTask(); - } - else - { - CurrentNaviItem?.Delete(); - } - - if (_naviItemMap.ContainsKey(e.Page)) - _naviItemMap.Remove(e.Page); - } - } - - protected override void ConnectHandler(Naviframe nativeView) - { - base.ConnectHandler(nativeView); - nativeView.AnimationFinished += OnAnimationFinished; - _naviItemMap = new Dictionary(); - - if (VirtualView == null) - return; - - //VirtualView.PushRequested += OnPushRequested; - //VirtualView.PopRequested += OnPopRequested; - //VirtualView.InternalChildren.CollectionChanged += OnPageCollectionChanged; - - foreach (var page in VirtualView.NavigationStack) - { - _naviItemMap[page] = NativeView.Push(CreateNavItem(page), SpanTitle(page)); - //page.PropertyChanged += NavigationBarPropertyChangedHandler; - - //UpdateHasNavigationBar(page); - } - } - - protected override void DisconnectHandler(Naviframe nativeView) - { - base.DisconnectHandler(nativeView); - nativeView.AnimationFinished -= OnAnimationFinished; - - //VirtualView.PushRequested -= OnPushRequested; - //VirtualView.PopRequested -= OnPopRequested; - //VirtualView.InternalChildren.CollectionChanged -= OnPageCollectionChanged; - } - - //public static void MapPadding(NavigationPageHandler handler, INavigationView view) { } - - //public static void MapBarTextColor(NavigationPageHandler handler, INavigationView view) - //{ - // //handler.UpdateTitle(view.CurrentPage); - //} - - public static void MapBarBackground(NavigationPageHandler handler, INavigationView view) { } - - public static void MapTitleIcon(NavigationPageHandler handler, INavigationView view) { } - - public static void MapTitleView(NavigationPageHandler handler, INavigationView view) { } - - //void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) - //{ - // // this handler is invoked only for child pages (contained on a navigation stack) - // if (e.PropertyName == INavigationView.HasNavigationBarProperty.PropertyName) - // UpdateHasNavigationBar(sender as Page); - // else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName || - // e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) - // UpdateHasBackButton(sender as Page); - // else if (e.PropertyName == Page.TitleProperty.PropertyName) - // UpdateTitle(sender as Page); - //} - - //void OnPageCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - //{ - // if (e.OldItems != null) - // foreach (Page page in e.OldItems) - // page.PropertyChanged -= NavigationBarPropertyChangedHandler; - // if (e.NewItems != null) - // foreach (Page page in e.NewItems) - // page.PropertyChanged += NavigationBarPropertyChangedHandler; - //} - - //void OnPushRequested(object sender, NavigationRequestedEventArgs nre) - //{ - // if (nre.Animated || NativeView.NavigationStack.Count == 0) - // { - // _naviItemMap[nre.Page] = NativeView.Push(CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); - // _currentTaskSource = new TaskCompletionSource(); - // nre.Task = _currentTaskSource.Task; - - // // There is no TransitionFinished (AnimationFinished) event after the first Push - // if (NativeView.NavigationStack.Count == 1) - // CompleteCurrentNavigationTask(); - // } - // else - // { - // _naviItemMap[nre.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); - // } - // UpdateHasNavigationBar(nre.Page); - //} - - //void OnPopRequested(object sender, NavigationRequestedEventArgs nre) - //{ - // if (VirtualView.InternalChildren.Count == NativeView.NavigationStack.Count) - // { - // nre.Page?.SendDisappearing(); - // UpdateNavigationBar(PreviousPage, PreviousNaviItem); - - // if (nre.Animated) - // { - // NativeView.Pop(); - - // _currentTaskSource = new TaskCompletionSource(); - // nre.Task = _currentTaskSource.Task; - - // // There is no TransitionFinished (AnimationFinished) event after Pop the last page - // if (NativeView.NavigationStack.Count == 0) - // CompleteCurrentNavigationTask(); - // } - // else - // { - // CurrentNaviItem?.Delete(); - // } - - // if (_naviItemMap.ContainsKey(nre.Page)) - // _naviItemMap.Remove(nre.Page); - // } - //} - - void OnAnimationFinished(object? sender, EventArgs e) - { - CompleteCurrentNavigationTask(); - } - - void CompleteCurrentNavigationTask() - { - if (_currentTaskSource != null) - { - var tmp = _currentTaskSource; - _currentTaskSource = null; - tmp.SetResult(true); - } - } - - //void UpdateHasNavigationBar(IView page) - //{ - // NaviItem item = GetNaviItemForPage(page); - // item.SetTabBarStyle(); - // item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty); - // UpdateBarBackgroundColor(item); - //} - - //void UpdateNavigationBar(Page page, NaviItem item = null) - //{ - // if (item == null) - // item = GetNaviItemForPage(page); - - // UpdateTitle(page, item); - // UpdateBarBackgroundColor(item); - //} - - //void UpdateHasBackButton(Page page, NaviItem item = null) - //{ - // if (item == null) - // item = GetNaviItemForPage(page); - - // TButton button = null; - - // if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty) && NativeView.NavigationStack.Count > 1) - // { - // button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty)); - // } - // item.SetBackButton(button); - //} - - void UpdateTitle(IView page, NaviItem? item = null) - { - if (item == null) - item = GetNaviItemForPage(page); - - item?.SetTitle(SpanTitle(page)); - } - - string SpanTitle(IView view) - { - if (view is not ITitledElement page) - return string.Empty; - else - { - var span = new TSpan - { - Text = page.Title??string.Empty, - HorizontalTextAlignment = TTextAlignment.Center, - //ForegroundColor = VirtualView.BarTextColor.ToNative() - }; - return span.GetMarkupText(); - } - } - - //void UpdateBarBackgroundColor(NaviItem item) - //{ - // item.TitleBarBackgroundColor = VirtualView.BarBackgroundColor.ToNativeEFL(); - //} - - //TButton CreateNavigationButton(string text) - //{ - // var button = new TButton(NativeParent) - // { - // Text = text - // }; - // button.SetNavigationBackStyle(); - // button.Clicked += (sender, e) => - // { - // if (!VirtualView.SendBackButtonPressed()) - // Tizen.Applications.Application.Current.Exit(); - // }; - // _naviItemContentPartList.Add(button); - // button.Deleted += NaviItemPartContentDeletedHandler; - // return button; - //} - - //void NaviItemPartContentDeletedHandler(object sender, EventArgs e) - //{ - // _naviItemContentPartList.Remove(sender as Widget); - //} - - NaviItem? GetNaviItemForPage(IView page) - { - _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); - - NaviItem? item; - if (_naviItemMap.TryGetValue(page, out item)) - { - return item; - } - return null; - } - - EvasObject CreateNavItem(IView page) - { - return page.ToNative(MauiContext!); - } - } -} From 9c7286535d581295307eef3e21a5db725207094b Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 3 Sep 2021 15:50:10 +0900 Subject: [PATCH 062/266] [Tizen] Adds BoxView Handler --- .../Handlers/BoxView/BoxViewHandler.Tizen.cs | 25 +++++++++++++++++++ .../src/Platform/Tizen/BoxViewExtensions.cs | 12 +++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/Core/src/Handlers/BoxView/BoxViewHandler.Tizen.cs create mode 100644 src/Core/src/Platform/Tizen/BoxViewExtensions.cs diff --git a/src/Core/src/Handlers/BoxView/BoxViewHandler.Tizen.cs b/src/Core/src/Handlers/BoxView/BoxViewHandler.Tizen.cs new file mode 100644 index 000000000000..630fd3fdc49c --- /dev/null +++ b/src/Core/src/Handlers/BoxView/BoxViewHandler.Tizen.cs @@ -0,0 +1,25 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Handlers +{ + public partial class BoxViewHandler : ViewHandler + { + protected override MauiBoxView CreateNativeView() + { + return new MauiBoxView(NativeParent!) + { + Drawable = new BoxViewDrawable(VirtualView) + }; + } + + public static void MapColor(BoxViewHandler handler, IBoxView boxView) + { + handler.NativeView?.InvalidateBoxView(boxView); + } + + public static void MapCornerRadius(BoxViewHandler handler, IBoxView boxView) + { + handler.NativeView?.InvalidateBoxView(boxView); + } + } +} diff --git a/src/Core/src/Platform/Tizen/BoxViewExtensions.cs b/src/Core/src/Platform/Tizen/BoxViewExtensions.cs new file mode 100644 index 000000000000..1c450ddd290b --- /dev/null +++ b/src/Core/src/Platform/Tizen/BoxViewExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui +{ + public static class BoxViewExtensions + { + public static void InvalidateBoxView(this MauiBoxView nativeView, IBoxView boxView) + { + nativeView.Invalidate(); + } + } +} \ No newline at end of file From 330fab4579c1ac9e25beea04881bbae13b1ae9a9 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 7 Sep 2021 18:42:23 +0900 Subject: [PATCH 063/266] [Tizen] Implement ProgressColor property in ProgressBarHandlers - Implement ProgressColor property in ProgressBarHandlers (#600) --- .../src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs | 5 +++++ src/Core/src/Platform/Tizen/ProgressBarExtensions.cs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs b/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs index 1f65c2b3a496..79e4a795cef1 100644 --- a/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs +++ b/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs @@ -29,5 +29,10 @@ public static void MapProgressColor(ProgressBarHandler handler, IProgress progre { handler.PlatformView?.UpdateProgressColor(progress); } + + public static void MapProgressColor(ProgressBarHandler handler, IProgress progress) + { + handler.NativeView?.UpdateProgressColor(progress); + } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs b/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs index 89ce8489bb20..d7e69723a472 100644 --- a/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs +++ b/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs @@ -13,5 +13,10 @@ public static void UpdateProgressColor(this ProgressBar platformProgressBar, IPr { platformProgressBar.Color = progress.ProgressColor.ToPlatformEFL(); } + + public static void UpdateProgressColor(this ProgressBar nativeProgressBar, IProgress progress) + { + nativeProgressBar.Color = progress.ProgressColor.ToNativeEFL(); + } } } \ No newline at end of file From 34af028853c926a081be3fff622c681a2ffc7a56 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 8 Sep 2021 18:34:15 +0900 Subject: [PATCH 064/266] [Tizen] Handle ContentViews and templated content in new layout system --- .../src/Handlers/Page/PageHandler.Tizen.cs | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index 4ee2aa05db20..a6fabfd3aa1b 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -1,4 +1,4 @@ -using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.Common; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Handlers @@ -28,29 +28,6 @@ protected override ContentCanvas CreatePlatformView() public override void NativeArrange(Graphics.Rectangle frame) { - // empty on purpose - } - - void UpdateContent() - { - _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); - _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); - _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); - - NativeView.Children.Clear(); - _contentHandler?.Dispose(); - _contentHandler = null; - - if (VirtualView is IContentView cv && cv.Content is IView view) - { - NativeView.Children.Add(view.ToNative(MauiContext)); - - if (view.Handler is INativeViewHandler thandler) - { - thandler?.SetParent(this); - _contentHandler = thandler; - } - } } } } \ No newline at end of file From 8824f3a911a309f762e7a0ec7a11c58f83928cbb Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 23 Sep 2021 21:07:36 +0900 Subject: [PATCH 065/266] Bump to latest (rc1) - ImageButtonHandler and Handler Re-usability (#2352) - Remove IBoxView (#2619) - Add SupportedOSPlatformVersion (#2565) - Merge all the .NET 6 projects/solutions (#2505) - Shadow Support (#570) - Add IndicatorView handler(#2038) --- ...ui.Tizen.sln => ._Microsoft.Maui.Tizen.sln | 0 ...osoft.Maui.Controls.MultiTargeting.targets | 4 +- .../Handlers/BoxView/BoxViewHandler.Tizen.cs | 25 --------- .../Handlers/Button/ButtonHandler.Tizen.cs | 15 ++++-- .../Tizen/ImageSourceServiceResult.cs | 39 -------------- .../src/Platform/Tizen/BoxViewExtensions.cs | 12 ----- .../src/Platform/Tizen/ImageExtensions.cs | 53 +++++++++++++++++++ 7 files changed, 67 insertions(+), 81 deletions(-) rename Microsoft.Maui.Tizen.sln => ._Microsoft.Maui.Tizen.sln (100%) delete mode 100644 src/Core/src/Handlers/BoxView/BoxViewHandler.Tizen.cs delete mode 100644 src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs delete mode 100644 src/Core/src/Platform/Tizen/BoxViewExtensions.cs diff --git a/Microsoft.Maui.Tizen.sln b/._Microsoft.Maui.Tizen.sln similarity index 100% rename from Microsoft.Maui.Tizen.sln rename to ._Microsoft.Maui.Tizen.sln diff --git a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets index d93d10790ec0..cecf6d5cd201 100644 --- a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets +++ b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets @@ -31,9 +31,9 @@ - + - + diff --git a/src/Core/src/Handlers/BoxView/BoxViewHandler.Tizen.cs b/src/Core/src/Handlers/BoxView/BoxViewHandler.Tizen.cs deleted file mode 100644 index 630fd3fdc49c..000000000000 --- a/src/Core/src/Handlers/BoxView/BoxViewHandler.Tizen.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.Maui.Graphics; - -namespace Microsoft.Maui.Handlers -{ - public partial class BoxViewHandler : ViewHandler - { - protected override MauiBoxView CreateNativeView() - { - return new MauiBoxView(NativeParent!) - { - Drawable = new BoxViewDrawable(VirtualView) - }; - } - - public static void MapColor(BoxViewHandler handler, IBoxView boxView) - { - handler.NativeView?.InvalidateBoxView(boxView); - } - - public static void MapCornerRadius(BoxViewHandler handler, IBoxView boxView) - { - handler.NativeView?.InvalidateBoxView(boxView); - } - } -} diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs index d63099842bb0..192e9acd74b8 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs @@ -46,9 +46,18 @@ public static Task MapImageSourceAsync(IButtonHandler handler, IImage image) return handler.ImageSourceLoader.UpdateImageSourceAsync(); } - //TODO : Need to impl - [MissingMapper] - public static void MapImageSource(ButtonHandler handler, IButton image) { } + public static void MapImageSource(IButtonHandler handler, IButton image) => + MapImageSourceAsync(handler, image).FireAndForget(handler); + + public static Task MapImageSourceAsync(IButtonHandler handler, IButton image) + { + if (image.ImageSource == null) + { + return Task.CompletedTask; + } + + return handler.ImageSourceLoader.UpdateImageSourceAsync(); + } [MissingMapper] public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button) { } diff --git a/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs b/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs deleted file mode 100644 index 6e48ceaec7c1..000000000000 --- a/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs +++ /dev/null @@ -1,39 +0,0 @@ -#nullable enable -using System; - -namespace Microsoft.Maui -{ - public class ImageSourceServiceResult : IImageSourceServiceResult - { - Action? _dispose; - - public ImageSourceServiceResult(bool result, Action? dispose = null) - : this(result, false, dispose) - { - } - - public ImageSourceServiceResult(bool result, bool resolutionDependent, Action? dispose = null) - { - Value = result; - IsResolutionDependent = resolutionDependent; - _dispose = dispose; - } - - public bool Value { get; } - - public bool IsResolutionDependent { get; } - - public bool IsDisposed { get; private set; } - - public void Dispose() - { - if (IsDisposed) - return; - - IsDisposed = true; - - _dispose?.Invoke(); - _dispose = null; - } - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/BoxViewExtensions.cs b/src/Core/src/Platform/Tizen/BoxViewExtensions.cs deleted file mode 100644 index 1c450ddd290b..000000000000 --- a/src/Core/src/Platform/Tizen/BoxViewExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.Maui.Graphics; - -namespace Microsoft.Maui -{ - public static class BoxViewExtensions - { - public static void InvalidateBoxView(this MauiBoxView nativeView, IBoxView boxView) - { - nativeView.Invalidate(); - } - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ImageExtensions.cs b/src/Core/src/Platform/Tizen/ImageExtensions.cs index 607b99cdc0c0..a11d1aa7a793 100644 --- a/src/Core/src/Platform/Tizen/ImageExtensions.cs +++ b/src/Core/src/Platform/Tizen/ImageExtensions.cs @@ -18,5 +18,58 @@ public static void UpdateIsAnimationPlaying(this Image platformImage, IImageSour platformImage.IsAnimated = image.IsAnimationPlaying; platformImage.IsAnimationPlaying = image.IsAnimationPlaying; } + + public static async Task?> UpdateSourceAsync(this IImageSourcePart image, Image destinationContext, IImageSourceServiceProvider services, Action setImage, CancellationToken cancellationToken = default) + { + image.UpdateIsLoading(false); + + var imageSource = image.Source; + if (imageSource == null) + return null; + + var events = image as IImageSourcePartEvents; + + events?.LoadingStarted(); + image.UpdateIsLoading(true); + + try + { + var service = services.GetRequiredImageSourceService(imageSource); + var result = await service.GetImageAsync(imageSource, destinationContext, cancellationToken); + var tImage = result?.Value; + + var applied = !cancellationToken.IsCancellationRequested && tImage != null && imageSource == image.Source; + + // only set the image if we are still on the same one + if (applied) + { + setImage.Invoke(tImage); + destinationContext.UpdateIsAnimationPlaying(image); + } + + events?.LoadingCompleted(applied); + + return result; + } + catch (OperationCanceledException) + { + // no-op + events?.LoadingCompleted(false); + } + catch (Exception ex) + { + events?.LoadingFailed(ex); + } + finally + { + // only mark as finished if we are still working on the same image + if (imageSource == image.Source) + { + image.UpdateIsLoading(false); + } + } + + return null; + } } } From 332930a02741cf4c1312d92efc17b5b91d0a5889 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 24 Sep 2021 16:33:45 +0900 Subject: [PATCH 066/266] [Tizen] Apply graphics related code review feedback --- .../GraphicsView/GraphicsViewHandler.Tizen.cs | 2 +- .../Platform/Tizen/GraphicsViewExtensions.cs | 1 - src/Core/src/Platform/Tizen/MauiShapeView.cs | 1 - .../Platform/Tizen/SkiaGraphicsView.Tizen.cs | 62 ------------------- 4 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/SkiaGraphicsView.Tizen.cs diff --git a/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs index 792912100de3..f37d204da2af 100644 --- a/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs @@ -1,4 +1,4 @@ -using Microsoft.Maui.Platform; +using Microsoft.Maui.Platform; namespace Microsoft.Maui.Handlers { diff --git a/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs b/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs index b6168716a04b..b6ee57a02f82 100644 --- a/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs @@ -1,5 +1,4 @@ using Microsoft.Maui.Graphics.Skia.Views; -using SkiaGraphicsView = Microsoft.Maui.Platform.Tizen.SkiaGraphicsView; namespace Microsoft.Maui.Platform { diff --git a/src/Core/src/Platform/Tizen/MauiShapeView.cs b/src/Core/src/Platform/Tizen/MauiShapeView.cs index 027f1422c136..6baeb99bccdc 100644 --- a/src/Core/src/Platform/Tizen/MauiShapeView.cs +++ b/src/Core/src/Platform/Tizen/MauiShapeView.cs @@ -1,6 +1,5 @@ using ElmSharp; using Microsoft.Maui.Graphics.Skia.Views; -using SkiaGraphicsView = Microsoft.Maui.Platform.Tizen.SkiaGraphicsView; namespace Microsoft.Maui.Platform { diff --git a/src/Core/src/Platform/Tizen/SkiaGraphicsView.Tizen.cs b/src/Core/src/Platform/Tizen/SkiaGraphicsView.Tizen.cs deleted file mode 100644 index 84cdea6fd9a7..000000000000 --- a/src/Core/src/Platform/Tizen/SkiaGraphicsView.Tizen.cs +++ /dev/null @@ -1,62 +0,0 @@ -#nullable disable -using ElmSharp; -using SkiaSharp.Views.Tizen; -using Microsoft.Maui.Graphics; -using Microsoft.Maui.Graphics.Skia; - -namespace Microsoft.Maui.Platform.Tizen -{ - // TODO. Remove it - // This class a temporary used, until Microsoft.Maui.Graphics.Skia.Views.SkiaGraphicsView is updated on upstream. - public class SkiaGraphicsView : SKCanvasView - { - private IDrawable _drawable; - private SkiaCanvas _canvas; - private ScalingCanvas _scalingCanvas; - - public SkiaGraphicsView(EvasObject parent, IDrawable drawable = null) : base(parent) - { - _canvas = new SkiaCanvas(); - _scalingCanvas = new ScalingCanvas(_canvas); - Drawable = drawable; - PaintSurface += OnPaintSurface; - } - - public float DeviceScalingFactor { get; set; } - - public IDrawable Drawable - { - get => _drawable; - set - { - _drawable = value; - Invalidate(); - } - } - - protected virtual void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e) - { - if (_drawable == null) return; - - var skiaCanvas = e.Surface.Canvas; - skiaCanvas.Clear(); - - _canvas.Canvas = skiaCanvas; - _scalingCanvas.ResetState(); - - float width = e.Info.Width; - float height = e.Info.Height; - if (DeviceScalingFactor > 0) - { - width = width / DeviceScalingFactor; - height = height / DeviceScalingFactor; - } - - _scalingCanvas.SaveState(); - if (DeviceScalingFactor > 0) - _scalingCanvas.Scale(DeviceScalingFactor, DeviceScalingFactor); - _drawable.Draw(_scalingCanvas, new RectangleF(0, 0, width, height)); - _scalingCanvas.RestoreState(); - } - } -} From bae03e2e9faa56b9dd3e01078fdc3db9f659ce9c Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 30 Sep 2021 13:00:47 +0900 Subject: [PATCH 067/266] [Tizen] Port H/V TextAlignment to Editor/Picker Handler --- src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs index 6728f484bb47..beddec9055ca 100644 --- a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs +++ b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs @@ -118,6 +118,11 @@ public static void MapKeyboard(EditorHandler handler, IEditor editor) handler.NativeView?.UpdateKeyboard(editor); } + public static void MapHorizontalTextAlignment(EditorHandler handler, IEditor editor) + { + handler.NativeView?.UpdateHorizontalTextAlignment(editor); + } + [MissingMapper] public static void MapCharacterSpacing(IEditorHandler handler, IEditor editor) { } From ba74c059f0b2f3b75f9e70faa0828a2afd77f255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=B1=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 1 Oct 2021 13:31:04 +0900 Subject: [PATCH 068/266] [Tizen] Add TVShellView (#183) * [Tizen] Add TVShellView * [Tizen] Update TVShellView * [Tizen] Update NativeView for Shell * [Tizen] Update ShellView * [Tizen] Change default FlyoutBackgroundColor for TV * [Tizen] Enable nullable --- .../Tizen/Extensions/ShellExtensions.cs | 17 - .../Platform/Tizen/Shell/ShellSectionView.cs | 375 ------------------ .../Tizen/Shell/TVNavigationDrawer.cs | 256 ++++++++++++ .../Platform/Tizen/Shell/TVNavigationView.cs | 27 ++ 4 files changed, 283 insertions(+), 392 deletions(-) delete mode 100644 src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs delete mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationDrawer.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationView.cs diff --git a/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs deleted file mode 100644 index 53b70de2c3d3..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Tizen.UIExtensions.Common; - -namespace Microsoft.Maui.Controls.Platform -{ - public static class ShellExtensions - { - public static DrawerBehavior ToPlatform(this FlyoutBehavior behavior) - { - if (behavior == FlyoutBehavior.Disabled) - return DrawerBehavior.Disabled; - else if (behavior == FlyoutBehavior.Locked) - return DrawerBehavior.Locked; - else - return DrawerBehavior.Drawer; - } - } -} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs deleted file mode 100644 index 306b0809134a..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs +++ /dev/null @@ -1,375 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using ElmSharp; -using Tizen.UIExtensions.ElmSharp; -using EBox = ElmSharp.Box; -using EColor = ElmSharp.Color; -using EToolbarItem = ElmSharp.ToolbarItem; -using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; - -namespace Microsoft.Maui.Controls.Platform -{ - public interface IShellSectionRenderer : IDisposable - { - EvasObject NativeView { get; } - } - - public class ShellSectionView : IAppearanceObserver, IShellSectionRenderer - { - EBox _mainLayout = null; - EBox _contentArea = null; - Tabs _tabs = null; - EvasObject _currentContent = null; - Page _displayedPage; - - Dictionary _contentCache = new Dictionary(); - Dictionary _contentToTabsItem = new Dictionary(); - Dictionary _itemToContent = new Dictionary(); - List _tabsItems = new List(); - - EColor _backgroundColor = ShellView.DefaultBackgroundColor; - EColor _foregroundColor = ShellView.DefaultForegroundColor; - - bool _disposed = false; - - public ShellSectionView(ShellSection section, IMauiContext context) - { - ShellSection = section; - MauiContext = context; - ShellSection.PropertyChanged += OnSectionPropertyChanged; - (ShellSection.Items as INotifyCollectionChanged).CollectionChanged += OnShellSectionCollectionChanged; - - _mainLayout = new EBox(NativeParent); - _mainLayout.SetLayoutCallback(OnLayout); - - _contentArea = new EBox(NativeParent); - _contentArea.Show(); - _mainLayout.PackEnd(_contentArea); - - UpdateTabsItem(); - UpdateCurrentItem(ShellSection.CurrentItem); - - ((IShellController)Shell.Current).AddAppearanceObserver(this, ShellSection); - (ShellSection as IShellSectionController).AddDisplayedPageObserver(this, UpdateDisplayedPage); - } - - bool HasTabs => _tabs != null; - - bool _tabBarIsVisible = true; - - protected IMauiContext MauiContext { get; private set; } - - protected EvasObject NativeParent - { - get => MauiContext?.Context?.BaseLayout; - } - - protected virtual bool TabBarIsVisible - { - get => _tabBarIsVisible; - set - { - if (_tabBarIsVisible != value) - { - _tabBarIsVisible = value; - _mainLayout.MarkChanged(); - - if (value) - { - _tabs?.Show(); - } - else - { - _tabs?.Hide(); - } - } - } - } - - public ShellSection ShellSection { get; } - - public EvasObject NativeView - { - get - { - return _mainLayout; - } - } - - public EColor ToolbarBackgroundColor - { - get - { - return _backgroundColor; - } - set - { - _backgroundColor = value; - UpdateToolbarBackgroudColor(_backgroundColor); - } - } - - public EColor ToolbarForegroundColor - { - get - { - return _foregroundColor; - } - set - { - _foregroundColor = value; - UpdateToolbarForegroundColor(_foregroundColor); - } - } - - ~ShellSectionView() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance) - { - var backgroundColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarBackgroundColor; - var foregroundColor = appearance?.ForegroundColor; - ToolbarBackgroundColor = backgroundColor.IsDefault() ? ShellView.DefaultBackgroundColor : backgroundColor.ToNativeEFL(); - ToolbarForegroundColor = foregroundColor.IsDefault() ? ShellView.DefaultForegroundColor : foregroundColor.ToNativeEFL(); - } - - void UpdateDisplayedPage(Page page) - { - if (_displayedPage != null) - { - _displayedPage.PropertyChanged -= OnDisplayedPagePropertyChanged; - } - - if (page == null) - { - TabBarIsVisible = true; - return; - } - _displayedPage = page; - _displayedPage.PropertyChanged += OnDisplayedPagePropertyChanged; - TabBarIsVisible = Shell.GetTabBarIsVisible(page); - } - - void OnDisplayedPagePropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == Shell.TabBarIsVisibleProperty.PropertyName) - { - TabBarIsVisible = Shell.GetTabBarIsVisible(_displayedPage); - } - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed) - return; - - if (disposing) - { - ((IShellController)Shell.Current).RemoveAppearanceObserver(this); - if (ShellSection != null) - { - (ShellSection as IShellSectionController).RemoveDisplayedPageObserver(this); - ShellSection.PropertyChanged -= OnSectionPropertyChanged; - DeinitializeTabs(); - - foreach (var native in _contentCache.Values) - { - native.Unrealize(); - } - _contentCache.Clear(); - _contentToTabsItem.Clear(); - _itemToContent.Clear(); - } - NativeView.Unrealize(); - } - _disposed = true; - } - - void InitializeTabs() - { - if (_tabs != null) - { - return; - } - _tabs = new Tabs(NativeParent); - _tabs.Show(); - _tabs.BackgroundColor = _backgroundColor; - _tabs.Scrollable = TabsType.Fixed; - _tabs.Selected += OnTabsSelected; - _mainLayout.PackEnd(_tabs); - } - - void ClearTabsItem() - { - if (!HasTabs) - return; - - foreach (var item in _tabsItems) - { - item.Delete(); - } - _tabsItems.Clear(); - _contentToTabsItem.Clear(); - _itemToContent.Clear(); - } - - void DeinitializeTabs() - { - if (_tabs == null) - { - return; - } - ClearTabsItem(); - _tabs.Unrealize(); - _tabs = null; - } - - void OnSectionPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == "CurrentItem") - { - UpdateCurrentItem(ShellSection.CurrentItem); - } - } - - void UpdateCurrentItem(ShellContent content) - { - UpdateCurrentShellContent(content); - if (_contentToTabsItem.ContainsKey(content)) - { - _contentToTabsItem[content].IsSelected = true; - } - } - - void UpdateToolbarBackgroudColor(EColor color) - { - foreach (EToolbarItem item in _tabsItems) - { - item.SetBackgroundColor(color); - } - } - - void UpdateToolbarForegroundColor(EColor color) - { - foreach (EToolbarItem item in _tabsItems) - { - item.SetUnderlineColor(color); - } - } - - void UpdateTabsItem() - { - if (ShellSection.Items.Count <= 1) - { - DeinitializeTabs(); - return; - } - - InitializeTabs(); - ClearTabsItem(); - foreach (ShellContent content in ShellSection.Items) - { - InsertTabsItem(content); - } - _tabs.Scrollable = ShellSection.Items.Count > 3 ? TabsType.Scrollable : TabsType.Fixed; - } - - EToolbarItem InsertTabsItem(ShellContent content) - { - EToolbarItem item = _tabs.Append(content.Title, null); - item.SetBackgroundColor(_backgroundColor); - item.SetUnderlineColor(_foregroundColor); - - _tabsItems.Add(item); - _itemToContent[item] = content; - _contentToTabsItem[content] = item; - return item; - } - - void OnShellSectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - UpdateTabsItem(); - } - - void OnTabsSelected(object sender, EToolbarItemEventArgs e) - { - if (_tabs.SelectedItem == null) - { - return; - } - - ShellContent content = _itemToContent[_tabs.SelectedItem]; - if (ShellSection.CurrentItem != content) - { - ShellSection.SetValueFromRenderer(ShellSection.CurrentItemProperty, content); - } - } - - void UpdateCurrentShellContent(ShellContent content) - { - if (_currentContent != null) - { - _currentContent.Hide(); - _contentArea.UnPack(_currentContent); - _currentContent = null; - } - - if (content == null) - { - return; - } - - if (!_contentCache.ContainsKey(content)) - { - var native = CreateShellContent(content); - native.SetAlignment(-1, -1); - native.SetWeight(1, 1); - _contentCache[content] = native; - } - _currentContent = _contentCache[content]; - _currentContent.Show(); - _contentArea.PackEnd(_currentContent); - } - - EvasObject CreateShellContent(ShellContent content) - { - Page xpage = ((IShellContentController)content).GetOrCreateContent(); - return xpage.ToNative(MauiContext); - } - - void OnLayout() - { - if (NativeView.Geometry.Width == 0 || NativeView.Geometry.Height == 0) - return; - var bound = NativeView.Geometry; - - int tabsHeight; - if (HasTabs && TabBarIsVisible) - { - var tabsBound = bound; - tabsHeight = _tabs.MinimumHeight; - tabsBound.Height = tabsHeight; - _tabs.Geometry = tabsBound; - } - else - { - tabsHeight = 0; - } - - var contentBound = bound; - contentBound.Y += tabsHeight; - contentBound.Height -= tabsHeight; - _contentArea.Geometry = contentBound; - } - } -} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationDrawer.cs b/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationDrawer.cs new file mode 100644 index 000000000000..2c15c235f8d8 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationDrawer.cs @@ -0,0 +1,256 @@ +# nullable enable + +using System; +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; +using EBox = ElmSharp.Box; +using EColor = ElmSharp.Color; +using TButton = Tizen.UIExtensions.ElmSharp.Button; +using ITNavigationView = Tizen.UIExtensions.ElmSharp.INavigationView; + +namespace Microsoft.Maui.Controls.Platform +{ + public class TVNavigationDrawer : EBox, INavigationDrawer, IFlyoutBehaviorObserver + { + EBox _drawerBox; + EBox _mainBox; + EvasObject? _main; + EvasObject? _drawer; + TButton _focusControlArea; + + FlyoutBehavior _behavior; + bool _isOpen; + + double _openRatio; + + public TVNavigationDrawer(EvasObject parent) : base(parent) + { + SetLayoutCallback(OnLayout); + + _drawerBox = new EBox(parent); + _drawerBox.Show(); + PackEnd(_drawerBox); + + _mainBox = new EBox(parent); + _mainBox.SetLayoutCallback(OnMainBoxLayout); + _mainBox.Show(); + PackEnd(_mainBox); + + _focusControlArea = new TButton(parent) + { + Color = EColor.Transparent, + BackgroundColor = EColor.Transparent + }; + _focusControlArea.SetEffectColor(EColor.Transparent); + _focusControlArea.Show(); + _mainBox.PackEnd(_focusControlArea); + + _behavior = FlyoutBehavior.Flyout; + + _drawerBox.KeyUp += (s, e) => + { + if (e.KeyName == "Return" || e.KeyName == "Right") + { + IsOpen = false; + } + }; + + _mainBox.KeyUp += (s, e) => + { + if (e.KeyName == "Left") + { + if (_focusControlArea.IsFocused) + IsOpen = true; + } + else + { + // Workaround to prevent unexpected movement of the focus to drawer during page pushing. + if (_behavior == FlyoutBehavior.Locked) + _drawerBox.AllowTreeFocus = true; + } + }; + + _mainBox.KeyDown += (s, e) => + { + if (e.KeyName != "Left") + { + // Workaround to prevent unexpected movement of the focus to drawer during page pushing. + if (_behavior == FlyoutBehavior.Locked) + _drawerBox.AllowTreeFocus = false; + } + }; + + UpdateFocusPolicy(); + } + + public event EventHandler? Toggled; + + public EvasObject TargetView => this; + + public EvasObject? NavigationView + { + get => _drawer; + set => UpdateNavigationView(value); + } + + public EvasObject? Main + { + get => _main; + set => UpdateMain(value); + } + + public bool IsOpen + { + get => _isOpen; + set => UpdateOpenState(value); + } + + public bool IsSplit { get; set; } + + public void UpdateBehavior(FlyoutBehavior behavior) + { + _behavior = behavior; + _focusControlArea.IsEnabled = _behavior == FlyoutBehavior.Flyout; + + var open = false; + + if (_behavior == FlyoutBehavior.Locked) + open = true; + else if (_behavior == FlyoutBehavior.Disabled) + open = false; + else + open = _drawerBox.IsFocused; + + UpdateOpenState(open); + } + + void UpdateNavigationView(EvasObject? navigationView) + { + if (_drawer != null) + { + _drawerBox.UnPack(_drawer); + _drawer.Hide(); + } + + _drawer = navigationView; + + if (_drawer != null) + { + _drawer.SetAlignment(-1, -1); + _drawer.SetWeight(1, 1); + _drawer.Show(); + _drawerBox.PackEnd(_drawer); + } + } + + void UpdateMain(EvasObject? main) + { + if (_main != null) + { + _mainBox.UnPack(_main); + _main.Hide(); + } + _main = main; + + if (_main != null) + { + _main.SetAlignment(-1, -1); + _main.SetWeight(1, 1); + _main.Show(); + _mainBox.PackStart(_main); + } + } + + void OnMainBoxLayout() + { + if (_main != null) + { + _main.Geometry = _mainBox.Geometry; + } + + var focusedButtonGeometry = _mainBox.Geometry; + focusedButtonGeometry.X = focusedButtonGeometry.X - 100; + focusedButtonGeometry.Width = 0; + focusedButtonGeometry.Height = (int)((_drawer as ITNavigationView)?.GetTvFlyoutItemHeight()).GetValueOrDefault(); + _focusControlArea.Geometry = focusedButtonGeometry; + } + + void OnLayout() + { + if (Geometry.Width == 0 || Geometry.Height == 0) + return; + + var bound = Geometry; + + var ratioMax = this.GetTvFlyoutRatio(Geometry.Width, Geometry.Height); + var ratioMin = (_behavior == FlyoutBehavior.Disabled) ? 0 : this.GetTvFlyoutRatioMin(); + var drawerWidthMax = (int)(bound.Width * ratioMax); + var drawerWidthMin = (int)(bound.Width * ratioMin); + + var drawerWidthOutBound = (int)((drawerWidthMax - drawerWidthMin) * (1 - _openRatio)); + var drawerWidthInBound = drawerWidthMax - drawerWidthOutBound; + + var drawerGeometry = bound; + drawerGeometry.Width = drawerWidthInBound; + _drawerBox.Geometry = drawerGeometry; + + var containerGeometry = bound; + containerGeometry.X = drawerWidthInBound; + containerGeometry.Width = (_behavior == FlyoutBehavior.Locked) ? (bound.Width - drawerWidthInBound) : (bound.Width - drawerWidthMin); + _mainBox.Geometry = containerGeometry; + } + + void UpdateOpenState(bool isOpen) + { + if (_behavior == FlyoutBehavior.Locked && !isOpen) + return; + + double endState = ((_behavior != FlyoutBehavior.Disabled) && isOpen) ? 1 : 0; + new Animation((r) => + { + _openRatio = r; + OnLayout(); + }, _openRatio, endState, Easing.SinOut).Commit(Shell.Current, "DrawerMove", finished: (f, aborted) => + { + if (!aborted) + { + if (_isOpen != isOpen) + { + _isOpen = isOpen; + UpdateFocusPolicy(); + Toggled?.Invoke(this, EventArgs.Empty); + } + } + }); + } + + void UpdateFocusPolicy() + { + if (_isOpen) + { + if (_behavior == FlyoutBehavior.Locked) + { + _drawerBox.AllowTreeFocus = true; + _mainBox.AllowTreeFocus = true; + } + else + { + _mainBox.AllowTreeFocus = false; + _drawerBox.AllowTreeFocus = true; + _drawerBox.SetFocus(true); + } + } + else + { + _mainBox.AllowTreeFocus = true; + _drawerBox.AllowTreeFocus = false; + _mainBox.SetFocus(true); + } + } + + void IFlyoutBehaviorObserver.OnFlyoutBehaviorChanged(FlyoutBehavior behavior) + { + UpdateBehavior(behavior); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationView.cs new file mode 100644 index 000000000000..e6b847ffa0d6 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationView.cs @@ -0,0 +1,27 @@ +using ElmSharp; +using EColor = ElmSharp.Color; +using TNavigationView = Tizen.UIExtensions.ElmSharp.NavigationView; + +namespace Microsoft.Maui.Controls.Platform +{ + public class TVNavigationView : TNavigationView + { + EColor _backgroundColor; + + public TVNavigationView(EvasObject parent) : base(parent) + { + BackgroundColor = this.GetTvDefaultBackgroundColor().ToNativeEFL(); + } + + public override EColor BackgroundColor + { + get => _backgroundColor; + set + { + _backgroundColor = value; + base.BackgroundColor = _backgroundColor.IsDefault ? this.GetTvDefaultBackgroundColor().ToNativeEFL() : _backgroundColor; + } + } + + } +} From 8c0bd1c2d79380e14d46cb860359877c42a118aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 5 Oct 2021 16:09:05 +0900 Subject: [PATCH 069/266] Refactor WrapperView to draw drawable features (#186) * Refactor WrapperView to draw drawable features * Update class names and devide files * Override NeesContainer to remove duplicated code * Update class names --- src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs | 8 ++++++++ src/Core/src/Platform/Tizen/WrapperView.cs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs diff --git a/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs b/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs new file mode 100644 index 000000000000..8c203a2666c4 --- /dev/null +++ b/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs @@ -0,0 +1,8 @@ + +namespace Microsoft.Maui +{ + public interface IWrapperViewCanvas + { + public IWrapperViewDrawables Drawables { get; } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index dc00458b1c0f..571373e41e43 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -11,7 +11,7 @@ namespace Microsoft.Maui.Platform { - public interface IBackgroundCanvas + public partial class WrapperView : Canvas, IWrapperViewCanvas { public SkiaGraphicsView BackgroundCanvas { get; } } From f5dfb02a6cdafda9d4bcbdc6b9b78d385737e6ba Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 6 Oct 2021 15:27:57 +0900 Subject: [PATCH 070/266] [Tizen] Adds ApplicationHandler --- .../src/Core/HandlerImpl/Window.Tizen.cs | 12 ------ src/Core/src/IMauiContext.cs | 1 - src/Core/src/MauiContext.cs | 13 +++++++ src/Core/src/Platform/MauiContext.Tizen.cs | 39 ------------------- .../src/Platform/Tizen/ActivationState.cs | 14 ------- .../src/Platform/Tizen/HandlerExtensions.cs | 31 ++++++++++----- src/Core/src/Platform/Tizen/LayoutCanvas.cs | 4 +- .../src/Platform/Tizen/MauiApplication.cs | 8 +++- 8 files changed, 42 insertions(+), 80 deletions(-) delete mode 100644 src/Controls/src/Core/HandlerImpl/Window.Tizen.cs delete mode 100644 src/Core/src/Platform/MauiContext.Tizen.cs delete mode 100644 src/Core/src/Platform/Tizen/ActivationState.cs diff --git a/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs deleted file mode 100644 index 12dcf19a25ea..000000000000 --- a/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable enable -using System; -using EWindow = ElmSharp.Window; - -namespace Microsoft.Maui.Controls -{ - public partial class Window - { - internal EWindow NativeWindow => - (Handler?.NativeView as EWindow) ?? throw new InvalidOperationException("Window should have a ElmSharp.Window set."); - } -} \ No newline at end of file diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index e1648772dffa..11b1593bb241 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -12,7 +12,6 @@ public interface IMauiContext Android.Content.Context? Context { get; } #elif TIZEN CoreUIAppContext? Context { get; } - ElmSharp.Window? Window { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/MauiContext.cs b/src/Core/src/MauiContext.cs index 341f0a423205..b7ce80111b14 100644 --- a/src/Core/src/MauiContext.cs +++ b/src/Core/src/MauiContext.cs @@ -19,6 +19,19 @@ public MauiContext(IServiceProvider services, Android.Content.Context context) { AddWeakSpecific(context); } +#elif TIZEN + public MauiContext(IServiceProvider services, Tizen.Applications.CoreUIApplication application, CoreUIAppContext context, IMauiContext? parent = null) + : this(services, parent) + { + AddSpecific(application); + AddWeakSpecific(context.MainWindow); + } + + public MauiContext(IServiceProvider services, CoreUIAppContext context, IMauiContext? parent = null) + : this(services, parent) + { + AddWeakSpecific(context); + } #endif public MauiContext(IServiceProvider services) diff --git a/src/Core/src/Platform/MauiContext.Tizen.cs b/src/Core/src/Platform/MauiContext.Tizen.cs deleted file mode 100644 index 231f6a27583f..000000000000 --- a/src/Core/src/Platform/MauiContext.Tizen.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using ElmSharp; - -namespace Microsoft.Maui -{ - public partial class MauiContext - { - readonly WeakReference? _context; - - public MauiContext(CoreUIAppContext context) : this() - { - _context = new WeakReference(context ?? throw new ArgumentNullException(nameof(context))); - } - - public MauiContext(IServiceProvider services, CoreUIAppContext context) : this(services) - { - _context = new WeakReference(context ?? throw new ArgumentNullException(nameof(context))); - } - - public CoreUIAppContext? Context - { - get - { - if (_context == null) - return null; - - CoreUIAppContext? context; - if (_context.TryGetTarget(out context)) - { - return context; - } - - return null; - } - } - - public Window? Window => Context?.MainWindow; - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ActivationState.cs b/src/Core/src/Platform/Tizen/ActivationState.cs deleted file mode 100644 index 6719e581c7ce..000000000000 --- a/src/Core/src/Platform/Tizen/ActivationState.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Microsoft.Maui -{ - public class ActivationState : IActivationState - { - public ActivationState(IMauiContext context) - { - Context = context ?? throw new ArgumentNullException(nameof(context)); - } - - public IMauiContext Context { get; } - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 2be109138318..bb8896c0a96c 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -38,25 +38,36 @@ public static EvasObject ToNative(this IElement view, IMauiContext context) return result; } - public static void SetWindow(this Window nativeWindow, IWindow window, IMauiContext mauiContext) + public static void SetApplicationHandler(this CoreUIApplication nativeApplication, IApplication application, IMauiContext context) + { + _ = nativeApplication ?? throw new ArgumentNullException(nameof(nativeApplication)); + SetHandler(application, context); + } + + public static void SetWindowHandler(this Window nativeWindow, IWindow window, IMauiContext context) { _ = nativeWindow ?? throw new ArgumentNullException(nameof(nativeWindow)); - _ = window ?? throw new ArgumentNullException(nameof(window)); - _ = mauiContext ?? throw new ArgumentNullException(nameof(mauiContext)); + SetHandler(window, context); + } - var handler = window.Handler; + static void SetHandler(IElement element, IMauiContext context) + { + _ = element ?? throw new ArgumentNullException(nameof(element)); + _ = context ?? throw new ArgumentNullException(nameof(context)); + + var handler = element.Handler; if (handler == null) - handler = mauiContext.Handlers.GetHandler(window.GetType()); + handler = context.Handlers.GetHandler(element.GetType()); if (handler == null) - throw new Exception($"Handler not found for view {window}."); + throw new Exception($"Handler not found for view {element}."); - handler.SetMauiContext(mauiContext); + handler.SetMauiContext(context); - window.Handler = handler; + element.Handler = handler; - if (handler.VirtualView != window) - handler.SetVirtualView(window); + if (handler.VirtualView != element) + handler.SetVirtualView(element); } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs index ce070524867e..7d5117ee2174 100644 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -32,9 +32,9 @@ protected void OnLayoutUpdated(object? sender, LayoutEventArgs e) var nativeGeometry = Geometry.ToDP(); var measured = CrossPlatformMeasure!(nativeGeometry.Width, nativeGeometry.Height); - if (measured != _measureCache) + if (measured != _measureCache && _virtualView?.Parent is IView parentView) { - _virtualView?.Parent?.InvalidateMeasure(); + parentView?.InvalidateMeasure(); } _measureCache = measured; diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index cc75ecd8e481..baf9ffd7d275 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -46,6 +46,8 @@ protected override void OnPreCreate() var mauiApp = CreateMauiApp(); + MauiApplicationContext = new MauiContext(mauiApp.Services, this, CoreUIAppContext.GetInstance(this)); + Services = mauiApp.Services; Current.Services?.InvokeLifecycleEvents(del => del(this)); @@ -61,7 +63,7 @@ protected override void OnCreate() this.CreatePlatformWindow(Application); - var tizenWindow = mauiContext.Window; + var tizenWindow = mauiContext.Context?.MainWindow; if (tizenWindow == null) throw new InvalidOperationException($"The {nameof(tizenWindow)} instance was not found."); @@ -70,7 +72,7 @@ protected override void OnCreate() var window = Application.CreateWindow(activationState); _virtualWindow = new WeakReference(window); - tizenWindow.SetWindow(window, mauiContext); + tizenWindow.SetWindowHandler(window, mauiContext); return tizenWindow; } @@ -131,6 +133,8 @@ protected override void OnTerminate() public static new MauiApplication Current { get; private set; } = null!; + internal IMauiContext MauiApplicationContext { get; private set; } = null!; + public Window MainWindow { get; protected set; } = null!; public IServiceProvider Services { get; protected set; } = null!; From 5b211df3ca92c85d6838f4fa564fb5bfa785ab87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=B1=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 8 Oct 2021 14:05:24 +0900 Subject: [PATCH 071/266] Fix Background issue of Frame (#193) --- src/Core/src/Handlers/Page/PageHandler.Tizen.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index a6fabfd3aa1b..fe4a22898d2e 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -1,4 +1,4 @@ -using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.Common; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Handlers @@ -29,5 +29,13 @@ protected override ContentCanvas CreatePlatformView() public override void NativeArrange(Graphics.Rectangle frame) { } + + protected override ContentCanvas CreateNativeView() + { + var view = base.CreateNativeView(); + view.BackgroundColor = (DeviceInfo.GetDeviceType() == DeviceType.TV) ? EColor.Transparent : EColor.White; + + return view; + } } } \ No newline at end of file From e194447d1daf6a36732a5d2088dc18ff2989cc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 12 Oct 2021 15:27:12 +0900 Subject: [PATCH 072/266] Fix UpdateBackground (#194) * Fix UpdateBackground * Add ContentView Background mapper * Fix Editor/Entry/Label/Layout Background * Add IWrapperViewCanvas.Content * Add PageHandler Background mapper * Restore WrapperView * Remove unnecessary namespace --- src/Core/src/Handlers/Page/PageHandler.Tizen.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index fe4a22898d2e..bd23553109ab 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -1,4 +1,4 @@ -using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.Common; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Handlers @@ -28,9 +28,15 @@ protected override ContentCanvas CreatePlatformView() public override void NativeArrange(Graphics.Rectangle frame) { + handler.UpdateValue(nameof(handler.ContainerView)); + if (page.Background != null && handler.NativeView.BackgroundColor != EColor.Transparent) + { + handler.NativeView.BackgroundColor = EColor.Transparent; + } + handler.GetWrappedNativeView()?.UpdateBackground(page); } - protected override ContentCanvas CreateNativeView() + public static void MapTitle(PageHandler handler, IContentView page) { var view = base.CreateNativeView(); view.BackgroundColor = (DeviceInfo.GetDeviceType() == DeviceType.TV) ? EColor.Transparent : EColor.White; From 3ad355cbc881248307f74f7c96e5ad0e6cc2fc4e Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 12 Oct 2021 15:51:52 +0900 Subject: [PATCH 073/266] [Tizen] Fix build error on PageHandler --- src/Core/src/Handlers/Page/PageHandler.Tizen.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index bd23553109ab..47ec3d6b686b 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -1,4 +1,4 @@ -using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.Common; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Handlers @@ -36,7 +36,10 @@ public override void NativeArrange(Graphics.Rectangle frame) handler.GetWrappedNativeView()?.UpdateBackground(page); } - public static void MapTitle(PageHandler handler, IContentView page) + [MissingMapper] + public static void MapTitle(PageHandler handler, IContentView page) { } + + protected override ContentCanvas CreateNativeView() { var view = base.CreateNativeView(); view.BackgroundColor = (DeviceInfo.GetDeviceType() == DeviceType.TV) ? EColor.Transparent : EColor.White; From 721c9218b42f820fcc6112c3f0682939852f8407 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 25 Oct 2021 13:28:46 +0900 Subject: [PATCH 074/266] [Tizen] Apply ITextButton related changes --- src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs index 192e9acd74b8..bbac0ca9b951 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs @@ -51,11 +51,6 @@ public static void MapImageSource(IButtonHandler handler, IButton image) => public static Task MapImageSourceAsync(IButtonHandler handler, IButton image) { - if (image.ImageSource == null) - { - return Task.CompletedTask; - } - return handler.ImageSourceLoader.UpdateImageSourceAsync(); } From 2e9a9569d92b2a839bdf58bc5cdac705a53ef181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 28 Oct 2021 16:22:33 +0900 Subject: [PATCH 075/266] [Tizen] Add Shadows (#233) * [Tizen] Add Shadows * [Tizen] Apply review comments * [Tizen] Move updating shape in proper position * [Tizen] Update BackgroundDrawable * [Tizen] Apply review comments --- .../src/Graphics/BackgroundDrawable.Tizen.cs | 34 +++++++++++++++ src/Core/src/Graphics/ShadowDrawable.Tizen.cs | 38 +++++++++++++++++ src/Core/src/Platform/Tizen/DPExtensions.cs | 5 +++ .../src/Platform/Tizen/GeometryExtensions.cs | 41 +++++++++++++++++++ src/Core/src/Platform/Tizen/WrapperView.cs | 10 +++-- 5 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 src/Core/src/Graphics/BackgroundDrawable.Tizen.cs create mode 100644 src/Core/src/Graphics/ShadowDrawable.Tizen.cs create mode 100644 src/Core/src/Platform/Tizen/GeometryExtensions.cs diff --git a/src/Core/src/Graphics/BackgroundDrawable.Tizen.cs b/src/Core/src/Graphics/BackgroundDrawable.Tizen.cs new file mode 100644 index 000000000000..8c9fa3fc3401 --- /dev/null +++ b/src/Core/src/Graphics/BackgroundDrawable.Tizen.cs @@ -0,0 +1,34 @@ +namespace Microsoft.Maui.Graphics +{ + public class BackgroundDrawable : IDrawable + { + Paint _paint; + PathF _path; + + public BackgroundDrawable(Paint paint, PathF path) + { + _paint = paint; + _path = path; + } + + public void UpdatePaint(Paint paint) + { + _paint = paint; + } + + public void UpdatePath(PathF path) + { + _path = path; + } + + public void Draw(ICanvas canvas, RectangleF dirtyRect) + { + canvas.SaveState(); + + canvas.SetFillPaint(_paint, dirtyRect); + canvas.FillPath(_path); + + canvas.RestoreState(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Graphics/ShadowDrawable.Tizen.cs b/src/Core/src/Graphics/ShadowDrawable.Tizen.cs new file mode 100644 index 000000000000..7dc746fa5031 --- /dev/null +++ b/src/Core/src/Graphics/ShadowDrawable.Tizen.cs @@ -0,0 +1,38 @@ +namespace Microsoft.Maui.Graphics +{ + public class ShadowDrawable : IDrawable + { + IShadow _shadow; + PathF _path; + + public ShadowDrawable(IShadow shadow, PathF path) + { + _shadow = shadow; + _path = path; + } + + public void UpdateShadow(IShadow shadow, PathF path) + { + _shadow = shadow; + _path = path; + } + + public void Draw(ICanvas canvas, RectangleF dirtyRect) + { + canvas.SaveState(); + Color color = _shadow.Paint.ToColor() != null ? _shadow.Paint.ToColor()!.MultiplyAlpha(_shadow.Opacity) : Colors.Black.MultiplyAlpha(_shadow.Opacity); + canvas.SetShadow( + new SizeF((float)_shadow.Offset.X, (float)_shadow.Offset.Y), + (int)_shadow.Radius, + color); + canvas.FillPath(_path); + canvas.RestoreState(); + + canvas.SaveState(); + canvas.StrokeColor = Colors.Transparent; + canvas.DrawPath(_path); + canvas.ClipPath(_path, WindingMode.EvenOdd); + canvas.RestoreState(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/DPExtensions.cs b/src/Core/src/Platform/Tizen/DPExtensions.cs index 5bb53ef49c33..6279754308d0 100644 --- a/src/Core/src/Platform/Tizen/DPExtensions.cs +++ b/src/Core/src/Platform/Tizen/DPExtensions.cs @@ -62,6 +62,11 @@ public static float ToScaledDP(this float pixel) return pixel / (float)DeviceInfo.ScalingFactor; } + public static float ToScaledDP(this float pixel) + { + return pixel / (float)DeviceInfo.ScalingFactor; + } + public static double ToScaledDP(this double pixel) { return pixel / DeviceInfo.ScalingFactor; diff --git a/src/Core/src/Platform/Tizen/GeometryExtensions.cs b/src/Core/src/Platform/Tizen/GeometryExtensions.cs new file mode 100644 index 000000000000..a9a604efefe3 --- /dev/null +++ b/src/Core/src/Platform/Tizen/GeometryExtensions.cs @@ -0,0 +1,41 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui +{ + internal static class GeometryExtensions + { + public static Rect ExpandTo(this Rect geometry, IShadow? shadow) + { + double left = 0; + double top = 0; + double right = 0; + double bottom = 0; + + var scaledOffsetX = shadow == null ? 0 : shadow.Offset.X.ToScaledPixel(); + var scaledOffsetY = shadow == null ? 0 : shadow.Offset.Y.ToScaledPixel(); + var scaledBlurRadius = shadow == null ? 0 : ((double)shadow.Radius).ToScaledPixel(); + var spreadSize = scaledBlurRadius * 3; + var spreadLeft = scaledOffsetX - spreadSize; + var spreadRight = scaledOffsetX + spreadSize; + var spreadTop = scaledOffsetY - spreadSize; + var spreadBottom = scaledOffsetY + spreadSize; + if (left > spreadLeft) + left = spreadLeft; + if (top > spreadTop) + top = spreadTop; + if (right < spreadRight) + right = spreadRight; + if (bottom < spreadBottom) + bottom = spreadBottom; + + var canvasGeometry = new Rect( + geometry.X + (int)left, + geometry.Y + (int)top, + geometry.Width + (int)right - (int)left, + geometry.Height + (int)bottom - (int)top); + + return canvasGeometry; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index 571373e41e43..d7586aae5262 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -21,6 +21,7 @@ public partial class WrapperView : Canvas, IBackgroundCanvas Lazy _drawableCanvas; Lazy _clipperView; EvasObject? _content; + IShape? _shape; public WrapperView(EvasObject parent) : base(parent) { @@ -33,6 +34,7 @@ public WrapperView(EvasObject parent) : base(parent) PassEvents = true }; view.Show(); + view.PassEvents = true; Children.Add(view); view.Lower(); Content?.RaiseTop(); @@ -143,10 +145,6 @@ void OnClipPaint(object? sender, DrawClipEventArgs e) } canvas.FillPath(clipPath); Content?.SetClipperCanvas(_clipperView.Value); - if (_drawableCanvas.IsValueCreated) - { - _drawableCanvas.Value.SetClipperCanvas(_clipperView.Value); - } } void OnLayout(object? sender, LayoutEventArgs e) @@ -310,6 +308,10 @@ public static void SetClipperCanvas(this EvasObject target, SKClipperView clippe target.SetClip(null); // To restore original image evas_object_clip_set(target, realHandle); } + + var path = new PathF(); + path.AppendRectangle(bounds); + return path; } [DllImport("libevas.so.1")] From 5568c52132b69bf4ca9222f22b700cf6add1c7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 29 Oct 2021 12:06:26 +0900 Subject: [PATCH 076/266] [Tizen] Add BorderDrawable (#224) * Move to platform specific * Fix border handler for Tizen * Rename ToDrawable method * Fix border content layout * Fix BorderView * Apply rebase --- .../Tizen/BackgroundDrawable.cs} | 6 ++- src/Core/src/Platform/Tizen/BorderDrawable.cs | 39 +++++++++++++++++++ .../Tizen/ShadowDrawable.cs} | 4 +- 3 files changed, 46 insertions(+), 3 deletions(-) rename src/Core/src/{Graphics/BackgroundDrawable.Tizen.cs => Platform/Tizen/BackgroundDrawable.cs} (88%) create mode 100644 src/Core/src/Platform/Tizen/BorderDrawable.cs rename src/Core/src/{Graphics/ShadowDrawable.Tizen.cs => Platform/Tizen/ShadowDrawable.cs} (93%) diff --git a/src/Core/src/Graphics/BackgroundDrawable.Tizen.cs b/src/Core/src/Platform/Tizen/BackgroundDrawable.cs similarity index 88% rename from src/Core/src/Graphics/BackgroundDrawable.Tizen.cs rename to src/Core/src/Platform/Tizen/BackgroundDrawable.cs index 8c9fa3fc3401..eca0551560bd 100644 --- a/src/Core/src/Graphics/BackgroundDrawable.Tizen.cs +++ b/src/Core/src/Platform/Tizen/BackgroundDrawable.cs @@ -1,4 +1,6 @@ -namespace Microsoft.Maui.Graphics +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui { public class BackgroundDrawable : IDrawable { @@ -31,4 +33,4 @@ public void Draw(ICanvas canvas, RectangleF dirtyRect) canvas.RestoreState(); } } -} \ No newline at end of file +} diff --git a/src/Core/src/Platform/Tizen/BorderDrawable.cs b/src/Core/src/Platform/Tizen/BorderDrawable.cs new file mode 100644 index 000000000000..915fd337e932 --- /dev/null +++ b/src/Core/src/Platform/Tizen/BorderDrawable.cs @@ -0,0 +1,39 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui +{ + public class BorderDrawable : IDrawable + { + Paint _paint; + IBorder _border; + + public BorderDrawable(Paint paint, IBorder border) + { + _paint = paint; + _border = border; + } + + public void Draw(ICanvas canvas, RectangleF dirtyRect) + { + canvas.SaveState(); + + var borderPath = _border.Shape?.PathForBounds(dirtyRect) ?? null; + if (borderPath != null) + { + canvas.MiterLimit = _border.StrokeMiterLimit; + canvas.StrokeColor = _border.Stroke.ToColor(); + canvas.StrokeDashPattern = _border.StrokeDashPattern; + canvas.StrokeLineCap = _border.StrokeLineCap; + canvas.StrokeLineJoin = _border.StrokeLineJoin; + canvas.StrokeSize = (float)_border.StrokeThickness; + + canvas.DrawPath(borderPath); + + canvas.SetFillPaint(_paint, dirtyRect); + canvas.FillPath(borderPath); + } + + canvas.RestoreState(); + } + } +} diff --git a/src/Core/src/Graphics/ShadowDrawable.Tizen.cs b/src/Core/src/Platform/Tizen/ShadowDrawable.cs similarity index 93% rename from src/Core/src/Graphics/ShadowDrawable.Tizen.cs rename to src/Core/src/Platform/Tizen/ShadowDrawable.cs index 7dc746fa5031..62a56575db8b 100644 --- a/src/Core/src/Graphics/ShadowDrawable.Tizen.cs +++ b/src/Core/src/Platform/Tizen/ShadowDrawable.cs @@ -1,4 +1,6 @@ -namespace Microsoft.Maui.Graphics +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui { public class ShadowDrawable : IDrawable { From 8b4df1b20ec2ef5fc8dcd8447f09c69803c899cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=B1=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 3 Nov 2021 16:01:37 +0900 Subject: [PATCH 077/266] [Tizen] Fix entry cursor issue (#222) * Fix entry cursor issue * Fix UpdateSelectionLength method --- src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs | 2 +- src/Core/src/Platform/Tizen/EntryExtensions.cs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs index 7d0ab354af43..172585a09cae 100644 --- a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs +++ b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs @@ -1,6 +1,5 @@ using System; using Tizen.UIExtensions.ElmSharp; -using SmartEvent = ElmSharp.SmartEvent; using EEntry = ElmSharp.Entry; namespace Microsoft.Maui.Handlers @@ -31,6 +30,7 @@ protected override void ConnectHandler(Entry platformView) platformView.PrependMarkUpFilter(MaxLengthFilter); + // TODO: Fix me later // An initial CursorPosition is set after layouting to avoid timing issue when the EditField entry is initialized. //if (VirtualView != null) diff --git a/src/Core/src/Platform/Tizen/EntryExtensions.cs b/src/Core/src/Platform/Tizen/EntryExtensions.cs index 7fae01f40761..d5deaf79e40c 100644 --- a/src/Core/src/Platform/Tizen/EntryExtensions.cs +++ b/src/Core/src/Platform/Tizen/EntryExtensions.cs @@ -145,6 +145,9 @@ static int GetSelectionEnd(Entry platformEntry, ITextInput entry, int start) [PortHandler] public static void UpdateSelectionLength(this Entry nativeEntry, IEntry entry) { + if (nativeEntry.IsUpdatingCursorPosition) + return; + int start = GetSelectionStart(nativeEntry, entry); int end = GetSelectionEnd(nativeEntry, entry, start); From 9ed555aeb9e95ed4bad5feb1eeea1c94f353268b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=B1=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 3 Nov 2021 16:01:52 +0900 Subject: [PATCH 078/266] [Tizen] Remove TVNavigationDrawer TVNavigationView (#223) * [Tizen] Remove TVNavigationDrawer TVNavigationView * [Elmsharp] Update Tizen.UIExtensions version --- .../Tizen/Extensions/ShellExtensions.cs | 17 ++ .../Tizen/Shell/TVNavigationDrawer.cs | 256 ------------------ .../Platform/Tizen/Shell/TVNavigationView.cs | 27 -- 3 files changed, 17 insertions(+), 283 deletions(-) create mode 100644 src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs delete mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationDrawer.cs delete mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationView.cs diff --git a/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs new file mode 100644 index 000000000000..134b7962375d --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs @@ -0,0 +1,17 @@ +using Tizen.UIExtensions.Common; + +namespace Microsoft.Maui.Controls.Platform +{ + public static class ShellExtensions + { + public static DrawerBehavior ToNative(this FlyoutBehavior behavior) + { + if (behavior == FlyoutBehavior.Disabled) + return DrawerBehavior.Disabled; + else if (behavior == FlyoutBehavior.Locked) + return DrawerBehavior.Locked; + else + return DrawerBehavior.Drawer; + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationDrawer.cs b/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationDrawer.cs deleted file mode 100644 index 2c15c235f8d8..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationDrawer.cs +++ /dev/null @@ -1,256 +0,0 @@ -# nullable enable - -using System; -using ElmSharp; -using Tizen.UIExtensions.ElmSharp; -using EBox = ElmSharp.Box; -using EColor = ElmSharp.Color; -using TButton = Tizen.UIExtensions.ElmSharp.Button; -using ITNavigationView = Tizen.UIExtensions.ElmSharp.INavigationView; - -namespace Microsoft.Maui.Controls.Platform -{ - public class TVNavigationDrawer : EBox, INavigationDrawer, IFlyoutBehaviorObserver - { - EBox _drawerBox; - EBox _mainBox; - EvasObject? _main; - EvasObject? _drawer; - TButton _focusControlArea; - - FlyoutBehavior _behavior; - bool _isOpen; - - double _openRatio; - - public TVNavigationDrawer(EvasObject parent) : base(parent) - { - SetLayoutCallback(OnLayout); - - _drawerBox = new EBox(parent); - _drawerBox.Show(); - PackEnd(_drawerBox); - - _mainBox = new EBox(parent); - _mainBox.SetLayoutCallback(OnMainBoxLayout); - _mainBox.Show(); - PackEnd(_mainBox); - - _focusControlArea = new TButton(parent) - { - Color = EColor.Transparent, - BackgroundColor = EColor.Transparent - }; - _focusControlArea.SetEffectColor(EColor.Transparent); - _focusControlArea.Show(); - _mainBox.PackEnd(_focusControlArea); - - _behavior = FlyoutBehavior.Flyout; - - _drawerBox.KeyUp += (s, e) => - { - if (e.KeyName == "Return" || e.KeyName == "Right") - { - IsOpen = false; - } - }; - - _mainBox.KeyUp += (s, e) => - { - if (e.KeyName == "Left") - { - if (_focusControlArea.IsFocused) - IsOpen = true; - } - else - { - // Workaround to prevent unexpected movement of the focus to drawer during page pushing. - if (_behavior == FlyoutBehavior.Locked) - _drawerBox.AllowTreeFocus = true; - } - }; - - _mainBox.KeyDown += (s, e) => - { - if (e.KeyName != "Left") - { - // Workaround to prevent unexpected movement of the focus to drawer during page pushing. - if (_behavior == FlyoutBehavior.Locked) - _drawerBox.AllowTreeFocus = false; - } - }; - - UpdateFocusPolicy(); - } - - public event EventHandler? Toggled; - - public EvasObject TargetView => this; - - public EvasObject? NavigationView - { - get => _drawer; - set => UpdateNavigationView(value); - } - - public EvasObject? Main - { - get => _main; - set => UpdateMain(value); - } - - public bool IsOpen - { - get => _isOpen; - set => UpdateOpenState(value); - } - - public bool IsSplit { get; set; } - - public void UpdateBehavior(FlyoutBehavior behavior) - { - _behavior = behavior; - _focusControlArea.IsEnabled = _behavior == FlyoutBehavior.Flyout; - - var open = false; - - if (_behavior == FlyoutBehavior.Locked) - open = true; - else if (_behavior == FlyoutBehavior.Disabled) - open = false; - else - open = _drawerBox.IsFocused; - - UpdateOpenState(open); - } - - void UpdateNavigationView(EvasObject? navigationView) - { - if (_drawer != null) - { - _drawerBox.UnPack(_drawer); - _drawer.Hide(); - } - - _drawer = navigationView; - - if (_drawer != null) - { - _drawer.SetAlignment(-1, -1); - _drawer.SetWeight(1, 1); - _drawer.Show(); - _drawerBox.PackEnd(_drawer); - } - } - - void UpdateMain(EvasObject? main) - { - if (_main != null) - { - _mainBox.UnPack(_main); - _main.Hide(); - } - _main = main; - - if (_main != null) - { - _main.SetAlignment(-1, -1); - _main.SetWeight(1, 1); - _main.Show(); - _mainBox.PackStart(_main); - } - } - - void OnMainBoxLayout() - { - if (_main != null) - { - _main.Geometry = _mainBox.Geometry; - } - - var focusedButtonGeometry = _mainBox.Geometry; - focusedButtonGeometry.X = focusedButtonGeometry.X - 100; - focusedButtonGeometry.Width = 0; - focusedButtonGeometry.Height = (int)((_drawer as ITNavigationView)?.GetTvFlyoutItemHeight()).GetValueOrDefault(); - _focusControlArea.Geometry = focusedButtonGeometry; - } - - void OnLayout() - { - if (Geometry.Width == 0 || Geometry.Height == 0) - return; - - var bound = Geometry; - - var ratioMax = this.GetTvFlyoutRatio(Geometry.Width, Geometry.Height); - var ratioMin = (_behavior == FlyoutBehavior.Disabled) ? 0 : this.GetTvFlyoutRatioMin(); - var drawerWidthMax = (int)(bound.Width * ratioMax); - var drawerWidthMin = (int)(bound.Width * ratioMin); - - var drawerWidthOutBound = (int)((drawerWidthMax - drawerWidthMin) * (1 - _openRatio)); - var drawerWidthInBound = drawerWidthMax - drawerWidthOutBound; - - var drawerGeometry = bound; - drawerGeometry.Width = drawerWidthInBound; - _drawerBox.Geometry = drawerGeometry; - - var containerGeometry = bound; - containerGeometry.X = drawerWidthInBound; - containerGeometry.Width = (_behavior == FlyoutBehavior.Locked) ? (bound.Width - drawerWidthInBound) : (bound.Width - drawerWidthMin); - _mainBox.Geometry = containerGeometry; - } - - void UpdateOpenState(bool isOpen) - { - if (_behavior == FlyoutBehavior.Locked && !isOpen) - return; - - double endState = ((_behavior != FlyoutBehavior.Disabled) && isOpen) ? 1 : 0; - new Animation((r) => - { - _openRatio = r; - OnLayout(); - }, _openRatio, endState, Easing.SinOut).Commit(Shell.Current, "DrawerMove", finished: (f, aborted) => - { - if (!aborted) - { - if (_isOpen != isOpen) - { - _isOpen = isOpen; - UpdateFocusPolicy(); - Toggled?.Invoke(this, EventArgs.Empty); - } - } - }); - } - - void UpdateFocusPolicy() - { - if (_isOpen) - { - if (_behavior == FlyoutBehavior.Locked) - { - _drawerBox.AllowTreeFocus = true; - _mainBox.AllowTreeFocus = true; - } - else - { - _mainBox.AllowTreeFocus = false; - _drawerBox.AllowTreeFocus = true; - _drawerBox.SetFocus(true); - } - } - else - { - _mainBox.AllowTreeFocus = true; - _drawerBox.AllowTreeFocus = false; - _mainBox.SetFocus(true); - } - } - - void IFlyoutBehaviorObserver.OnFlyoutBehaviorChanged(FlyoutBehavior behavior) - { - UpdateBehavior(behavior); - } - } -} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationView.cs deleted file mode 100644 index e6b847ffa0d6..000000000000 --- a/src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationView.cs +++ /dev/null @@ -1,27 +0,0 @@ -using ElmSharp; -using EColor = ElmSharp.Color; -using TNavigationView = Tizen.UIExtensions.ElmSharp.NavigationView; - -namespace Microsoft.Maui.Controls.Platform -{ - public class TVNavigationView : TNavigationView - { - EColor _backgroundColor; - - public TVNavigationView(EvasObject parent) : base(parent) - { - BackgroundColor = this.GetTvDefaultBackgroundColor().ToNativeEFL(); - } - - public override EColor BackgroundColor - { - get => _backgroundColor; - set - { - _backgroundColor = value; - base.BackgroundColor = _backgroundColor.IsDefault ? this.GetTvDefaultBackgroundColor().ToNativeEFL() : _backgroundColor; - } - } - - } -} From 747cff0ad5e4052564974e7587a3eb6c3bd153ed Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 5 Nov 2021 10:09:30 +0900 Subject: [PATCH 079/266] [Tizen] Initial Multi Window support --- .../Application/ApplicationHandler.Tizen.cs | 5 ++ .../GraphicsView/GraphicsViewHandler.Tizen.cs | 5 ++ src/Core/src/MauiContext.cs | 8 +-- .../src/Platform/Tizen/CoreUIAppExtensions.cs | 63 +++++++++++++++++-- .../src/Platform/Tizen/MauiApplication.cs | 2 - 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs b/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs index b8c0d621c009..3cc2dba3db9d 100644 --- a/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs +++ b/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs @@ -21,5 +21,10 @@ public static void MapCloseWindow(ApplicationHandler handler, IApplication appli //TODO : Need to implementation } } + + public static void MapOpenWindow(ApplicationHandler handler, IApplication application, object? args) + { + handler.NativeView?.RequestNewWindow(application, args as OpenWindowRequest); + } } } \ No newline at end of file diff --git a/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs index f37d204da2af..d611c0ec19d9 100644 --- a/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs @@ -21,5 +21,10 @@ public static void MapInvalidate(IGraphicsViewHandler handler, IGraphicsView gra { handler.PlatformView?.Invalidate(); } + + public static void MapInvalidate(GraphicsViewHandler handler, IGraphicsView graphicsView, object? arg) + { + handler.NativeView?.Invalidate(); + } } } \ No newline at end of file diff --git a/src/Core/src/MauiContext.cs b/src/Core/src/MauiContext.cs index b7ce80111b14..e8bc9c88076c 100644 --- a/src/Core/src/MauiContext.cs +++ b/src/Core/src/MauiContext.cs @@ -20,17 +20,11 @@ public MauiContext(IServiceProvider services, Android.Content.Context context) AddWeakSpecific(context); } #elif TIZEN - public MauiContext(IServiceProvider services, Tizen.Applications.CoreUIApplication application, CoreUIAppContext context, IMauiContext? parent = null) - : this(services, parent) - { - AddSpecific(application); - AddWeakSpecific(context.MainWindow); - } - public MauiContext(IServiceProvider services, CoreUIAppContext context, IMauiContext? parent = null) : this(services, parent) { AddWeakSpecific(context); + AddWeakSpecific(context.MainWindow); } #endif diff --git a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs index c730e41e1cbb..ef728e58a9dd 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs @@ -1,4 +1,6 @@ using System; +using Microsoft.Maui.Handlers; +using Microsoft.Maui.LifecycleEvents; using Tizen.Applications; using EWindow = ElmSharp.Window; @@ -8,10 +10,7 @@ internal static class CoreUIAppExtensions { public static IWindow GetWindow(this CoreUIApplication application) { - if (MauiApplication.Current.VirtualWindow != null) - return MauiApplication.Current.VirtualWindow; - - var nativeWindow = MauiApplication.Current.MainWindow; + var nativeWindow = CoreUIAppContext.GetInstance(application)?.MainWindow; foreach (var window in MauiApplication.Current.Application.Windows) { @@ -21,5 +20,61 @@ public static IWindow GetWindow(this CoreUIApplication application) throw new InvalidOperationException("Window Not Found"); } + + public static void RequestNewWindow(this CoreUIApplication nativeApplication, IApplication application, OpenWindowRequest? args) + { + if (application.Handler?.MauiContext is not IMauiContext applicationContext) + return; + + var state = args?.State; + var bundle = state.ToBundle(); + + //TODO : Need to implementation + } + + public static void CreateNativeWindow(this CoreUIApplication nativeApplication, IApplication application) + { + if (application.Handler?.MauiContext is not IMauiContext applicationContext) + return; + + var context = CoreUIAppContext.GetInstance(nativeApplication); + var mauiContext = applicationContext.MakeScoped(context); + + applicationContext.Services.InvokeLifecycleEvents(del => del(mauiContext)); + + var tizenWindow = mauiContext.Context?.MainWindow; + + if (tizenWindow == null) + throw new InvalidOperationException($"The {nameof(tizenWindow)} instance was not found."); + + var activationState = new ActivationState(mauiContext); + var window = application.CreateWindow(activationState); + + tizenWindow.SetWindowHandler(window, mauiContext); + } + + public static Bundle ToBundle(this IPersistedState? state) + { + var userInfo = new Bundle(); + + var keyset = userInfo.Keys; + if (keyset != null) + { + foreach (var k in keyset) + { + userInfo?.GetItem(k); + } + } + + if (state is not null) + { + foreach (var pair in state) + { + userInfo.AddItem(pair.Key, pair.Value); + } + } + + return userInfo; + } } } diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index baf9ffd7d275..6f647b675674 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -135,8 +135,6 @@ protected override void OnTerminate() internal IMauiContext MauiApplicationContext { get; private set; } = null!; - public Window MainWindow { get; protected set; } = null!; - public IServiceProvider Services { get; protected set; } = null!; public IApplication Application { get; protected set; } = null!; From 6a781c12b18638057d066295563298ba50f3fd45 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 5 Nov 2021 14:31:19 +0900 Subject: [PATCH 080/266] [Tizen] Fix MauiContext --- src/Core/src/MauiContext.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Core/src/MauiContext.cs b/src/Core/src/MauiContext.cs index e8bc9c88076c..c44d80dc20e2 100644 --- a/src/Core/src/MauiContext.cs +++ b/src/Core/src/MauiContext.cs @@ -20,6 +20,14 @@ public MauiContext(IServiceProvider services, Android.Content.Context context) AddWeakSpecific(context); } #elif TIZEN + public MauiContext(IServiceProvider services, Tizen.Applications.CoreUIApplication application, CoreUIAppContext context, IMauiContext? parent = null) + : this(services, parent) + { + AddSpecific(application); + AddWeakSpecific(context); + AddWeakSpecific(context.MainWindow); + } + public MauiContext(IServiceProvider services, CoreUIAppContext context, IMauiContext? parent = null) : this(services, parent) { From 0c34844dd254e94b2ca3fab80516389b05767acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 15 Nov 2021 16:59:45 +0900 Subject: [PATCH 081/266] [Tizen] Refactor Border by defining MauiDrawable (#248) * [Tizen] Refactor Border by defining MauiDrawable * [Tizen] Apply review comments * [Tizen] Remove unnecessary type casting * [Tizen] Move getting path logic to drawable --- .../src/Graphics/PaintExtensions.Tizen.cs | 82 ------------------- .../src/Platform/Tizen/BackgroundDrawable.cs | 36 -------- src/Core/src/Platform/Tizen/BorderDrawable.cs | 39 --------- .../src/Platform/Tizen/IWrapperViewCanvas.cs | 8 -- src/Core/src/Platform/Tizen/ShadowDrawable.cs | 40 --------- src/Core/src/Platform/Tizen/WrapperView.cs | 12 ++- 6 files changed, 8 insertions(+), 209 deletions(-) delete mode 100644 src/Core/src/Graphics/PaintExtensions.Tizen.cs delete mode 100644 src/Core/src/Platform/Tizen/BackgroundDrawable.cs delete mode 100644 src/Core/src/Platform/Tizen/BorderDrawable.cs delete mode 100644 src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs delete mode 100644 src/Core/src/Platform/Tizen/ShadowDrawable.cs diff --git a/src/Core/src/Graphics/PaintExtensions.Tizen.cs b/src/Core/src/Graphics/PaintExtensions.Tizen.cs deleted file mode 100644 index c94f14e13962..000000000000 --- a/src/Core/src/Graphics/PaintExtensions.Tizen.cs +++ /dev/null @@ -1,82 +0,0 @@ -using TColor = Tizen.UIExtensions.Common.Color; - -namespace Microsoft.Maui.Graphics -{ - public static partial class PaintExtensions - { - public static TColor ToPlatform(this Paint paint) - { - var color = paint.ToColor(); - return color != null ? color.ToPlatform() : TColor.Default; - } - - public static MauiDrawable? ToDrawable(this Paint paint) - { - if (paint is SolidPaint solidPaint) - return solidPaint.CreateDrawable(); - - if (paint is LinearGradientPaint linearGradientPaint) - return linearGradientPaint.CreateDrawable(); - - if (paint is RadialGradientPaint radialGradientPaint) - return radialGradientPaint.CreateDrawable(); - - if (paint is ImagePaint imagePaint) - return imagePaint.CreateDrawable(); - - if (paint is PatternPaint patternPaint) - return patternPaint.CreateDrawable(); - - return null; - } - - public static MauiDrawable? CreateDrawable(this SolidPaint solidPaint) - { - return new MauiDrawable - { - Background = solidPaint - }; - } - - public static MauiDrawable? CreateDrawable(this LinearGradientPaint linearGradientPaint) - { - if (!linearGradientPaint.IsValid()) - return null; - - return new MauiDrawable - { - Background = linearGradientPaint - }; - } - - public static MauiDrawable? CreateDrawable(this RadialGradientPaint radialGradientPaint) - { - if (!radialGradientPaint.IsValid()) - return null; - - return new MauiDrawable - { - Background = radialGradientPaint - }; - } - - public static MauiDrawable? CreateDrawable(this ImagePaint imagePaint) - { - return new MauiDrawable - { - Background = imagePaint - }; - } - - public static MauiDrawable? CreateDrawable(this PatternPaint patternPaint) - { - return new MauiDrawable - { - Background = patternPaint - }; - } - - static bool IsValid(this GradientPaint? gradienPaint) => - gradienPaint?.GradientStops?.Length > 0; - } -} diff --git a/src/Core/src/Platform/Tizen/BackgroundDrawable.cs b/src/Core/src/Platform/Tizen/BackgroundDrawable.cs deleted file mode 100644 index eca0551560bd..000000000000 --- a/src/Core/src/Platform/Tizen/BackgroundDrawable.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.Maui.Graphics; - -namespace Microsoft.Maui -{ - public class BackgroundDrawable : IDrawable - { - Paint _paint; - PathF _path; - - public BackgroundDrawable(Paint paint, PathF path) - { - _paint = paint; - _path = path; - } - - public void UpdatePaint(Paint paint) - { - _paint = paint; - } - - public void UpdatePath(PathF path) - { - _path = path; - } - - public void Draw(ICanvas canvas, RectangleF dirtyRect) - { - canvas.SaveState(); - - canvas.SetFillPaint(_paint, dirtyRect); - canvas.FillPath(_path); - - canvas.RestoreState(); - } - } -} diff --git a/src/Core/src/Platform/Tizen/BorderDrawable.cs b/src/Core/src/Platform/Tizen/BorderDrawable.cs deleted file mode 100644 index 915fd337e932..000000000000 --- a/src/Core/src/Platform/Tizen/BorderDrawable.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Microsoft.Maui.Graphics; - -namespace Microsoft.Maui -{ - public class BorderDrawable : IDrawable - { - Paint _paint; - IBorder _border; - - public BorderDrawable(Paint paint, IBorder border) - { - _paint = paint; - _border = border; - } - - public void Draw(ICanvas canvas, RectangleF dirtyRect) - { - canvas.SaveState(); - - var borderPath = _border.Shape?.PathForBounds(dirtyRect) ?? null; - if (borderPath != null) - { - canvas.MiterLimit = _border.StrokeMiterLimit; - canvas.StrokeColor = _border.Stroke.ToColor(); - canvas.StrokeDashPattern = _border.StrokeDashPattern; - canvas.StrokeLineCap = _border.StrokeLineCap; - canvas.StrokeLineJoin = _border.StrokeLineJoin; - canvas.StrokeSize = (float)_border.StrokeThickness; - - canvas.DrawPath(borderPath); - - canvas.SetFillPaint(_paint, dirtyRect); - canvas.FillPath(borderPath); - } - - canvas.RestoreState(); - } - } -} diff --git a/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs b/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs deleted file mode 100644 index 8c203a2666c4..000000000000 --- a/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs +++ /dev/null @@ -1,8 +0,0 @@ - -namespace Microsoft.Maui -{ - public interface IWrapperViewCanvas - { - public IWrapperViewDrawables Drawables { get; } - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ShadowDrawable.cs b/src/Core/src/Platform/Tizen/ShadowDrawable.cs deleted file mode 100644 index 62a56575db8b..000000000000 --- a/src/Core/src/Platform/Tizen/ShadowDrawable.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.Maui.Graphics; - -namespace Microsoft.Maui -{ - public class ShadowDrawable : IDrawable - { - IShadow _shadow; - PathF _path; - - public ShadowDrawable(IShadow shadow, PathF path) - { - _shadow = shadow; - _path = path; - } - - public void UpdateShadow(IShadow shadow, PathF path) - { - _shadow = shadow; - _path = path; - } - - public void Draw(ICanvas canvas, RectangleF dirtyRect) - { - canvas.SaveState(); - Color color = _shadow.Paint.ToColor() != null ? _shadow.Paint.ToColor()!.MultiplyAlpha(_shadow.Opacity) : Colors.Black.MultiplyAlpha(_shadow.Opacity); - canvas.SetShadow( - new SizeF((float)_shadow.Offset.X, (float)_shadow.Offset.Y), - (int)_shadow.Radius, - color); - canvas.FillPath(_path); - canvas.RestoreState(); - - canvas.SaveState(); - canvas.StrokeColor = Colors.Transparent; - canvas.DrawPath(_path); - canvas.ClipPath(_path, WindingMode.EvenOdd); - canvas.RestoreState(); - } - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index d7586aae5262..1a9642125782 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -11,7 +11,7 @@ namespace Microsoft.Maui.Platform { - public partial class WrapperView : Canvas, IWrapperViewCanvas + public partial class WrapperView : Canvas { public SkiaGraphicsView BackgroundCanvas { get; } } @@ -21,10 +21,11 @@ public partial class WrapperView : Canvas, IBackgroundCanvas Lazy _drawableCanvas; Lazy _clipperView; EvasObject? _content; - IShape? _shape; + MauiDrawable _mauiDrawable; public WrapperView(EvasObject parent) : base(parent) { + _mauiDrawable = new MauiDrawable(); _drawableCanvas = new Lazy(() => { var view = new SkiaGraphicsView(parent) @@ -34,7 +35,6 @@ public WrapperView(EvasObject parent) : base(parent) PassEvents = true }; view.Show(); - view.PassEvents = true; Children.Add(view); view.Lower(); Content?.RaiseTop(); @@ -75,7 +75,7 @@ public void UpdateBorder(IBorderStroke border) UpdateShape(border.Shape); } - partial void ShadowChanged() + public void UpdateBorder(IBorder border) { if (!_drawableCanvas.IsValueCreated && Shadow is null) return; @@ -145,6 +145,10 @@ void OnClipPaint(object? sender, DrawClipEventArgs e) } canvas.FillPath(clipPath); Content?.SetClipperCanvas(_clipperView.Value); + if (_drawableCanvas.IsValueCreated) + { + _drawableCanvas.Value.SetClipperCanvas(_clipperView.Value); + } } void OnLayout(object? sender, LayoutEventArgs e) From 4ca192e127da094cbdccd0dc1746146cd624634f Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 15 Nov 2021 20:32:37 +0900 Subject: [PATCH 082/266] [Tizen] Obsolete AndExpand & Remove IsolatedStorage --- .../src/Handlers/Application/ApplicationHandler.Tizen.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs b/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs index 3cc2dba3db9d..fb17eb324757 100644 --- a/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs +++ b/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs @@ -26,5 +26,13 @@ public static void MapOpenWindow(ApplicationHandler handler, IApplication applic { handler.NativeView?.RequestNewWindow(application, args as OpenWindowRequest); } + + public static void MapCloseWindow(ApplicationHandler handler, IApplication application, object? args) + { + if (args is IWindow window) + { + //TODO : Need to implementation + } + } } } \ No newline at end of file From cd7a29e4d3b1809c8b7bb523c5b815fa7b42e65b Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 17 Nov 2021 10:08:28 +0900 Subject: [PATCH 083/266] Fix tizen solution (.sln) correctly --- ._Microsoft.Maui.Tizen.sln | 124 +------------------------------------ 1 file changed, 3 insertions(+), 121 deletions(-) diff --git a/._Microsoft.Maui.Tizen.sln b/._Microsoft.Maui.Tizen.sln index 53f703a58728..08e5ae6e3d5a 100644 --- a/._Microsoft.Maui.Tizen.sln +++ b/._Microsoft.Maui.Tizen.sln @@ -68,18 +68,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{99FDF6CA-D EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.UnitTests", "src\Essentials\test\UnitTests\Essentials.UnitTests.csproj", "{2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Essentials.DeviceTests.iOS", "src\Essentials\test\DeviceTests.iOS\Essentials.DeviceTests.iOS.csproj", "{B73EB308-70BE-49FD-91A7-1D1495663D6D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.DeviceTests.Shared", "src\Essentials\test\DeviceTests.Shared\Essentials.DeviceTests.Shared.csproj", "{81128D28-CFC8-4EA4-B68D-9939339C461A}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5817A848-0B04-4035-9F7E-B8621B61CBDD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.Samples", "src\Essentials\samples\Samples\Essentials.Samples.csproj", "{2C69EB76-02C4-4921-96A1-4D70CB7CE744}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.Samples", "src\Essentials\samples\Samples\Essentials.Sample.csproj", "{2C69EB76-02C4-4921-96A1-4D70CB7CE744}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.Sample.Server.WebAuthenticator", "src\Essentials\samples\Sample.Server.WebAuthenticator\Essentials.Sample.Server.WebAuthenticator.csproj", "{0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.Benchmarks", "src\Core\tests\Benchmarks\Core.Benchmarks.csproj", "{73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{806499EB-C2CC-4E85-BC19-613F3DE5E0C3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Sample", "src\Controls\samples\Controls.Sample\Controls.Sample.csproj", "{90B727DD-4C7B-4462-950F-61842A87DE8A}" @@ -90,9 +84,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Xaml.UnitTests", " EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestUtils", "TestUtils", "{0F9BA970-11B1-4ACA-AF41-1021AFC0F29C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils", "src\TestUtils\TestUtils\src\TestUtils.csproj", "{E4CB9988-7348-4D55-A08E-85907732F8DA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils", "src\TestUtils\src\TestUtils\TestUtils.csproj", "{E4CB9988-7348-4D55-A08E-85907732F8DA}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils.DeviceTests", "src\TestUtils\TestUtils.DeviceTests\src\TestUtils.DeviceTests.csproj", "{551B2209-4298-4D60-B55C-79077B8BC244}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils.DeviceTests", "src\TestUtils\src\DeviceTests\TestUtils.DeviceTests.csproj", "{551B2209-4298-4D60-B55C-79077B8BC244}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resizetizer", "Resizetizer", "{4A3BAF64-E9D9-4036-9FDA-8B326C382667}" EndProject @@ -118,8 +112,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.SourceGen", "src\C EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Sample.Tizen", "src\Controls\samples\Controls.Sample.Tizen\Controls.Sample.Tizen.csproj", "{4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.Samples.Tizen", "src\Essentials\samples\Samples.Tizen\Essentials.Samples.Tizen.csproj", "{64483F36-30C0-412D-8230-F69669486F8A}" -EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Compatibility\ControlGallery\src\Issues.Shared\Compatibility.ControlGallery.Issues.Shared.projitems*{ae2513cb-4e5e-4e5c-8237-88954d4c9433}*SharedItemsImports = 13 @@ -394,56 +386,6 @@ Global {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x64.Build.0 = Release|Any CPU {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x86.ActiveCfg = Release|Any CPU {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x86.Build.0 = Release|Any CPU - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|ARM.ActiveCfg = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|ARM64.ActiveCfg = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhone.ActiveCfg = Debug|iPhone - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhone.Build.0 = Debug|iPhone - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhone.Deploy.0 = Debug|iPhone - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|x64.ActiveCfg = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|x64.Build.0 = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|x64.Deploy.0 = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|ARM.ActiveCfg = Release|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|ARM64.ActiveCfg = Release|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|iPhone.ActiveCfg = Release|iPhone - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|iPhone.Build.0 = Release|iPhone - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|x64.ActiveCfg = Release|iPhoneSimulator - {B73EB308-70BE-49FD-91A7-1D1495663D6D}.Release|x86.ActiveCfg = Release|iPhoneSimulator - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|ARM.ActiveCfg = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|ARM.Build.0 = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|ARM64.Build.0 = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|iPhone.Build.0 = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|x64.ActiveCfg = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|x64.Build.0 = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|x86.ActiveCfg = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Debug|x86.Build.0 = Debug|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|Any CPU.Build.0 = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|ARM.ActiveCfg = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|ARM.Build.0 = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|ARM64.ActiveCfg = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|ARM64.Build.0 = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|iPhone.ActiveCfg = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|iPhone.Build.0 = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|x64.ActiveCfg = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|x64.Build.0 = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|x86.ActiveCfg = Release|Any CPU - {81128D28-CFC8-4EA4-B68D-9939339C461A}.Release|x86.Build.0 = Release|Any CPU {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|Any CPU.Build.0 = Debug|Any CPU {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|ARM.ActiveCfg = Debug|Any CPU @@ -500,34 +442,6 @@ Global {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x64.Build.0 = Release|Any CPU {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x86.ActiveCfg = Release|Any CPU {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x86.Build.0 = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|Any CPU.Build.0 = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|ARM.ActiveCfg = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|ARM.Build.0 = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|ARM64.Build.0 = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|iPhone.Build.0 = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|x64.ActiveCfg = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|x64.Build.0 = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|x86.ActiveCfg = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Debug|x86.Build.0 = Debug|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|Any CPU.ActiveCfg = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|Any CPU.Build.0 = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|ARM.ActiveCfg = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|ARM.Build.0 = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|ARM64.ActiveCfg = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|ARM64.Build.0 = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|iPhone.ActiveCfg = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|iPhone.Build.0 = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|x64.ActiveCfg = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|x64.Build.0 = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|x86.ActiveCfg = Release|Any CPU - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424}.Release|x86.Build.0 = Release|Any CPU {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|Any CPU.Build.0 = Debug|Any CPU {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|ARM.ActiveCfg = Debug|Any CPU @@ -864,34 +778,6 @@ Global {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x64.Build.0 = Release|Any CPU {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x86.ActiveCfg = Release|Any CPU {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x86.Build.0 = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|ARM.ActiveCfg = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|ARM.Build.0 = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|ARM64.Build.0 = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|iPhone.Build.0 = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|x64.ActiveCfg = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|x64.Build.0 = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|x86.ActiveCfg = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Debug|x86.Build.0 = Debug|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|Any CPU.Build.0 = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|ARM.ActiveCfg = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|ARM.Build.0 = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|ARM64.ActiveCfg = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|ARM64.Build.0 = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|iPhone.ActiveCfg = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|iPhone.Build.0 = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|x64.ActiveCfg = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|x64.Build.0 = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|x86.ActiveCfg = Release|Any CPU - {64483F36-30C0-412D-8230-F69669486F8A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -914,12 +800,9 @@ Global {8CB95D25-8442-42BC-82BE-319D21138549} = {7E12E071-51C0-4668-9FF3-E2DE9DC51962} {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} = {DFD73007-5DB1-43AD-87A8-BD8622C2B192} {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886} = {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} - {B73EB308-70BE-49FD-91A7-1D1495663D6D} = {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} - {81128D28-CFC8-4EA4-B68D-9939339C461A} = {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} {5817A848-0B04-4035-9F7E-B8621B61CBDD} = {DFD73007-5DB1-43AD-87A8-BD8622C2B192} {2C69EB76-02C4-4921-96A1-4D70CB7CE744} = {5817A848-0B04-4035-9F7E-B8621B61CBDD} {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C} = {5817A848-0B04-4035-9F7E-B8621B61CBDD} - {73100F0D-C0BB-4F16-8FC2-FA3FA8ACD424} = {2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA} {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} = {9AD757F5-E57A-459D-A0A7-E0675E045B84} {90B727DD-4C7B-4462-950F-61842A87DE8A} = {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} {F2379E0F-524F-47BC-877C-0428E4C836D4} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} @@ -937,7 +820,6 @@ Global {9FAA9654-80E6-4664-9702-47998A04E8FE} = {29AC50BF-B4FB-450B-9386-0C5AD4B84226} {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6} = {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} - {64483F36-30C0-412D-8230-F69669486F8A} = {5817A848-0B04-4035-9F7E-B8621B61CBDD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {650AE971-2F29-46A8-822C-FB4FCDC6A9A0} From a3645b1a6c83b7a4c14c9bfd89b72dfe278b7ac0 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 17 Nov 2021 10:10:41 +0900 Subject: [PATCH 084/266] [Tizen] Add VerticalTextAlignment --- src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs index beddec9055ca..9d4df05d5f1e 100644 --- a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs +++ b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs @@ -123,6 +123,11 @@ public static void MapHorizontalTextAlignment(EditorHandler handler, IEditor edi handler.NativeView?.UpdateHorizontalTextAlignment(editor); } + public static void MapVerticalTextAlignment(EditorHandler handler, IEditor editor) + { + handler.NativeView?.UpdateVerticalTextAlignment(editor); + } + [MissingMapper] public static void MapCharacterSpacing(IEditorHandler handler, IEditor editor) { } From 289cffb685af3476a825384df1cab7311b9418b0 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 19 Nov 2021 12:53:13 +0900 Subject: [PATCH 085/266] [Tizen] Fix Scoping of MauiContext --- src/Core/src/MauiContext.cs | 13 ++----------- src/Core/src/MauiContextExtensions.cs | 3 +++ src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs | 3 ++- src/Core/src/Platform/Tizen/HandlerExtensions.cs | 10 ++-------- src/Core/src/Platform/Tizen/MauiApplication.cs | 8 ++++---- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/Core/src/MauiContext.cs b/src/Core/src/MauiContext.cs index c44d80dc20e2..aab57cbf6271 100644 --- a/src/Core/src/MauiContext.cs +++ b/src/Core/src/MauiContext.cs @@ -20,19 +20,10 @@ public MauiContext(IServiceProvider services, Android.Content.Context context) AddWeakSpecific(context); } #elif TIZEN - public MauiContext(IServiceProvider services, Tizen.Applications.CoreUIApplication application, CoreUIAppContext context, IMauiContext? parent = null) - : this(services, parent) - { - AddSpecific(application); - AddWeakSpecific(context); - AddWeakSpecific(context.MainWindow); - } - - public MauiContext(IServiceProvider services, CoreUIAppContext context, IMauiContext? parent = null) - : this(services, parent) + public MauiContext(IServiceProvider services, CoreUIAppContext context) + : this(services) { AddWeakSpecific(context); - AddWeakSpecific(context.MainWindow); } #endif diff --git a/src/Core/src/MauiContextExtensions.cs b/src/Core/src/MauiContextExtensions.cs index 5532ec41776b..4f734ca41eda 100644 --- a/src/Core/src/MauiContextExtensions.cs +++ b/src/Core/src/MauiContextExtensions.cs @@ -52,6 +52,9 @@ public static IMauiContext MakeWindowScope(this IMauiContext mauiContext, Native #if ANDROID var scopedContext = new MauiContext(scope.ServiceProvider, platformWindow); +#elif TIZEN + var scopedContext = new MauiContext(scope.ServiceProvider, platformWindow); + scopedContext.AddWeakSpecific(platformWindow.MainWindow); #else var scopedContext = new MauiContext(scope.ServiceProvider); #endif diff --git a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs index ef728e58a9dd..03ba6c1f5215 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs @@ -38,7 +38,8 @@ public static void CreateNativeWindow(this CoreUIApplication nativeApplication, return; var context = CoreUIAppContext.GetInstance(nativeApplication); - var mauiContext = applicationContext.MakeScoped(context); + + var mauiContext = applicationContext.MakeWindowScope(context, out var windowScope); applicationContext.Services.InvokeLifecycleEvents(del => del(mauiContext)); diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index bb8896c0a96c..3f89727e1d68 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -38,17 +38,11 @@ public static EvasObject ToNative(this IElement view, IMauiContext context) return result; } - public static void SetApplicationHandler(this CoreUIApplication nativeApplication, IApplication application, IMauiContext context) - { - _ = nativeApplication ?? throw new ArgumentNullException(nameof(nativeApplication)); + public static void SetApplicationHandler(this CoreUIApplication nativeApplication, IApplication application, IMauiContext context) => SetHandler(application, context); - } - public static void SetWindowHandler(this Window nativeWindow, IWindow window, IMauiContext context) - { - _ = nativeWindow ?? throw new ArgumentNullException(nameof(nativeWindow)); + public static void SetWindowHandler(this Window nativeWindow, IWindow window, IMauiContext context) => SetHandler(window, context); - } static void SetHandler(IElement element, IMauiContext context) { diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index 6f647b675674..fc3d4da7fbca 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -46,9 +46,11 @@ protected override void OnPreCreate() var mauiApp = CreateMauiApp(); - MauiApplicationContext = new MauiContext(mauiApp.Services, this, CoreUIAppContext.GetInstance(this)); + var rootContext = new MauiContext(mauiApp.Services, CoreUIAppContext.GetInstance(this)); - Services = mauiApp.Services; + _applicationContext = rootContext.MakeApplicationScope(this); + + Services = _applicationContext.Services; Current.Services?.InvokeLifecycleEvents(del => del(this)); } @@ -133,8 +135,6 @@ protected override void OnTerminate() public static new MauiApplication Current { get; private set; } = null!; - internal IMauiContext MauiApplicationContext { get; private set; } = null!; - public IServiceProvider Services { get; protected set; } = null!; public IApplication Application { get; protected set; } = null!; From 751249f37d934d49fca6b519aceded9968c27e83 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 22 Nov 2021 18:54:57 +0900 Subject: [PATCH 086/266] [Tizen] Use CoreApplication as native app type --- src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs index 03ba6c1f5215..345bb33a02e3 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs @@ -21,7 +21,7 @@ public static IWindow GetWindow(this CoreUIApplication application) throw new InvalidOperationException("Window Not Found"); } - public static void RequestNewWindow(this CoreUIApplication nativeApplication, IApplication application, OpenWindowRequest? args) + public static void RequestNewWindow(this CoreApplication nativeApplication, IApplication application, OpenWindowRequest? args) { if (application.Handler?.MauiContext is not IMauiContext applicationContext) return; From 8d16642d8542c83be63246d1719eab8ea96345d7 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 3 Dec 2021 09:18:23 +0900 Subject: [PATCH 087/266] [Tizen] Applying upstream changes --- .../src/Platform/Tizen/SemanticExtensions.cs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/SemanticExtensions.cs diff --git a/src/Core/src/Platform/Tizen/SemanticExtensions.cs b/src/Core/src/Platform/Tizen/SemanticExtensions.cs deleted file mode 100644 index 6a4c0bbc720e..000000000000 --- a/src/Core/src/Platform/Tizen/SemanticExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using ElmSharp.Accessible; - -namespace Microsoft.Maui -{ - public static partial class SemanticExtensions - { - public static void SetSemanticFocus(this IView element) - { - if (element?.Handler?.NativeView == null) - throw new NullReferenceException("Can't access view from a null handler"); - - if (element.Handler.NativeView is not AccessibleObject) - return; - - //TODO : Need to implement - } - } -} From 9c73cd1ae594fc46880f0635b3146dd2d990b523 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 3 Dec 2021 09:47:51 +0900 Subject: [PATCH 088/266] [Tizen] Add ContainerView to Layout if it's present --- .../Handlers/Layout/LayoutHandler.Tizen.cs | 2 +- .../src/Platform/Tizen/HandlerExtensions.cs | 36 ++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs index 0f44ad28dc2e..dbb1706555ae 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs @@ -178,7 +178,7 @@ public void Update(int index, IView child) NativeView.Children.RemoveAt(index); toBeRemoved.Unrealize(); - NativeView.Children.Insert(index, child.ToNative(MauiContext)); + NativeView.Children.Insert(index, child.ToNative(MauiContext, true)); if (child.Handler is INativeViewHandler childHandler) { childHandler?.SetParent(this); diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 3f89727e1d68..77665f8d898b 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -6,7 +6,37 @@ namespace Microsoft.Maui { public static class HandlerExtensions { + internal static EvasObject? GetNative(this IElement view, bool returnWrappedIfPresent) + { + if (view.Handler is INativeViewHandler nativeHandler && nativeHandler.NativeView != null) + return nativeHandler.NativeView; + + return (view.Handler?.NativeView as EvasObject); + } + + internal static EvasObject ToNative(this IElement view, IMauiContext context, bool returnWrappedIfPresent) + { + var nativeView = view.ToNative(context); + + if (view.Handler is INativeViewHandler nativeHandler && nativeHandler.NativeView != null) + return nativeHandler.NativeView; + + return nativeView; + } + public static EvasObject ToNative(this IElement view, IMauiContext context) + { + var handler = view.ToHandler(context); + + if (handler.NativeView is not EvasObject result) + { + throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); + } + + return result; + } + + public static INativeViewHandler ToHandler(this IElement view, IMauiContext context) { _ = view ?? throw new ArgumentNullException(nameof(view)); _ = context ?? throw new ArgumentNullException(nameof(context)); @@ -16,6 +46,7 @@ public static EvasObject ToNative(this IElement view, IMauiContext context) view = ir.ReplacedView; var handler = view.Handler; + if (handler?.MauiContext != null && handler.MauiContext != context) handler = null; @@ -32,10 +63,7 @@ public static EvasObject ToNative(this IElement view, IMauiContext context) if (handler.VirtualView != view) handler.SetVirtualView(view); - if (((INativeViewHandler)handler).NativeView is not EvasObject result) - throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); - - return result; + return (INativeViewHandler)handler; } public static void SetApplicationHandler(this CoreUIApplication nativeApplication, IApplication application, IMauiContext context) => From 019e7a88019c05af41ce2d75add1410e09c73d59 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 3 Dec 2021 10:23:18 +0900 Subject: [PATCH 089/266] [Tizen] Initial Reloadyfy support --- src/Core/src/Platform/Tizen/ContainerView.cs | 4 ++++ src/Core/src/Platform/Tizen/HandlerExtensions.cs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/Core/src/Platform/Tizen/ContainerView.cs b/src/Core/src/Platform/Tizen/ContainerView.cs index d4039213bd7a..ea0ce2299fec 100644 --- a/src/Core/src/Platform/Tizen/ContainerView.cs +++ b/src/Core/src/Platform/Tizen/ContainerView.cs @@ -65,7 +65,11 @@ void SetView(IElement? view, bool forceRefresh = false) if (_view != null) { _ = _context ?? throw new ArgumentNullException(nameof(_context)); +<<<<<<< HEAD MainView = _view.ToPlatform(_context); +======= + MainView = _view.ToNative(_context); +>>>>>>> 87f5fa6cb ([Tizen] Initial Reloadyfy support) } } diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 77665f8d898b..025617f1eb56 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -24,6 +24,9 @@ internal static EvasObject ToNative(this IElement view, IMauiContext context, bo return nativeView; } + public static EvasObject ToContainerView(this IElement view, IMauiContext context) => + new ContainerView(context) { CurrentView = view }; + public static EvasObject ToNative(this IElement view, IMauiContext context) { var handler = view.ToHandler(context); From 005dd5ec3d95782f367ddc2e8147c229bcbd96d6 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 3 Dec 2021 11:31:40 +0900 Subject: [PATCH 090/266] [Tizen] Initial IVisualDiagnosticOveraly support --- src/Core/src/Platform/Tizen/ViewExtensions.cs | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/Core/src/Platform/Tizen/ViewExtensions.cs b/src/Core/src/Platform/Tizen/ViewExtensions.cs index 916898887a6a..9289c7e425a5 100644 --- a/src/Core/src/Platform/Tizen/ViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/ViewExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Numerics; using System.Threading.Tasks; @@ -315,5 +315,57 @@ internal static IDisposable OnUnloaded(this EvasObject view, Action action) view.Deleted += deletedEventHandler; return disposable; } + + internal static Rectangle GetNativeViewBounds(this IView view) + { + var nativeView = view?.GetNative(true); + if (nativeView == null) + { + return new Rectangle(); + } + + return nativeView.GetNativeViewBounds(); + } + + internal static Rectangle GetNativeViewBounds(this EvasObject nativeView) + { + if (nativeView == null) + return new Rectangle(); + + return new Rectangle( + nativeView.Geometry.X, + nativeView.Geometry.Y, + nativeView.Geometry.Width, + nativeView.Geometry.Height); + } + + internal static Matrix4x4 GetViewTransform(this IView view) + { + var nativeView = view?.GetNative(true); + if (nativeView == null) + return new Matrix4x4(); + return nativeView.GetViewTransform(); + } + + internal static Matrix4x4 GetViewTransform(this EvasObject nativeView) + => nativeView.GetViewTransform(); + + internal static Graphics.Rectangle GetBoundingBox(this IView view) + => view.GetNative(true).GetBoundingBox(); + + internal static Graphics.Rectangle GetBoundingBox(this EvasObject? nativeView) + { + if (nativeView == null) + return new Rectangle(); + + var rect = nativeView.Geometry; + + var nvb = nativeView.GetNativeViewBounds(); + var transform = nativeView.GetViewTransform(); + var radians = transform.ExtractAngleInRadians(); + //TODO: Need to impl + + return new Rectangle(nvb.X, nvb.Y, nvb.Width, nvb.Height); + } } } From d6d2a98f6f9902a0d250dd18dac9ff2c1e85549e Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 6 Dec 2021 09:17:24 +0900 Subject: [PATCH 091/266] [Tizen] Move types in the Platform folder into the Platform namespaces --- src/Core/src/Platform/Tizen/CoreUIAppContext.cs | 2 +- src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs | 3 +-- src/Core/src/Platform/Tizen/GeometryExtensions.cs | 3 ++- src/Core/src/Platform/Tizen/HandlerExtensions.cs | 2 +- src/Core/src/Platform/Tizen/LayoutCanvas.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index 135a534276b5..763fcdaf8362 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -8,7 +8,7 @@ using Tizen.UIExtensions.Common; using ELayout = ElmSharp.Layout; -namespace Microsoft.Maui +namespace Microsoft.Maui.Platform { public class CoreUIAppContext { diff --git a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs index 345bb33a02e3..c6edaddfd97a 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs @@ -1,10 +1,9 @@ using System; -using Microsoft.Maui.Handlers; using Microsoft.Maui.LifecycleEvents; using Tizen.Applications; using EWindow = ElmSharp.Window; -namespace Microsoft.Maui +namespace Microsoft.Maui.Platform { internal static class CoreUIAppExtensions { diff --git a/src/Core/src/Platform/Tizen/GeometryExtensions.cs b/src/Core/src/Platform/Tizen/GeometryExtensions.cs index a9a604efefe3..27b8f5b269b0 100644 --- a/src/Core/src/Platform/Tizen/GeometryExtensions.cs +++ b/src/Core/src/Platform/Tizen/GeometryExtensions.cs @@ -1,7 +1,8 @@ using System; using ElmSharp; +using Tizen.UIExtensions.ElmSharp; -namespace Microsoft.Maui +namespace Microsoft.Maui.Platform { internal static class GeometryExtensions { diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 025617f1eb56..b27d6d5a2840 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -2,7 +2,7 @@ using Tizen.Applications; using ElmSharp; -namespace Microsoft.Maui +namespace Microsoft.Maui.Platform { public static class HandlerExtensions { diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs index 7d5117ee2174..1461cb0dc541 100644 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -6,7 +6,7 @@ using Size = Microsoft.Maui.Graphics.Size; using TSize = Tizen.UIExtensions.Common.Size; -namespace Microsoft.Maui +namespace Microsoft.Maui.Platform { public class LayoutCanvas : Canvas, IMeasurable { From 35bdcb01db0c2d6230e9976ac433104d7195b11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 6 Dec 2021 11:24:42 +0900 Subject: [PATCH 092/266] Fix CollectionView layout issue (#288) * Fix CollectionView layout issue * Remove unnecessary code --- .../src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs index 457ab97476bc..3b7f107924ac 100644 --- a/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs +++ b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs @@ -56,5 +56,10 @@ public static void MapIsVisible(ItemsViewHandler handler, ItemsView public static void MapItemsUpdatingScrollMode(ItemsViewHandler handler, ItemsView itemsView) { } + + public override Size GetDesiredSize(double widthConstraint, double heightConstraint) + { + return VirtualView.Measure(widthConstraint, heightConstraint, MeasureFlags.IncludeMargins).Request; + } } } From 2fad74e7ddd18d5344bf8fc808c735327cb15400 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 6 Dec 2021 13:01:50 +0900 Subject: [PATCH 093/266] [Tizen] ZIndex proof-of-concept --- .../Handlers/Layout/LayoutHandler.Tizen.cs | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs index dbb1706555ae..a8c72c6b0845 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs @@ -178,11 +178,55 @@ public void Update(int index, IView child) NativeView.Children.RemoveAt(index); toBeRemoved.Unrealize(); - NativeView.Children.Insert(index, child.ToNative(MauiContext, true)); + var targetIndex = VirtualView.GetLayoutHandlerIndex(child); + NativeView.Children.Insert(targetIndex, child.ToNative(MauiContext, true)); if (child.Handler is INativeViewHandler childHandler) { childHandler?.SetParent(this); } } + + public void UpdateZIndex(IView child) + { + _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); + _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + EnsureZIndexOrder(child); + } + + void EnsureZIndexOrder(IView child) + { + if (NativeView.Children.Count == 0) + { + return; + } + + var nativeChildView = child.ToNative(MauiContext!, true); + var currentIndex = NativeView.Children.IndexOf(nativeChildView); + + if (currentIndex == -1) + { + return; + } + + var targetIndex = VirtualView.GetLayoutHandlerIndex(child); + if (targetIndex > currentIndex) + { + child.ToNative(MauiContext!, true).RaiseTop(); + for (int i = targetIndex+1; i < NativeView.Children.Count; i++) + { + NativeView.Children[i].RaiseTop(); + } + } + else + { + child.ToNative(MauiContext!, true).Lower(); + for (int i = targetIndex-1; i >= 0; i--) + { + NativeView.Children[i].Lower(); + } + } + } } } From 6d1678d7850c8aa899de5ad18064d63627282386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 6 Dec 2021 19:34:19 +0900 Subject: [PATCH 094/266] Fix ScrollView ContentSize and Padding margin (#291) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix ScrollView ContentSize and Padding margin * Fix MapRequestScrollTo * Update src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs Co-authored-by: 허강호/Common Platform Lab(SR)/Principal Engineer/삼성전자 * Update src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs Co-authored-by: 허강호/Common Platform Lab(SR)/Principal Engineer/삼성전자 * Remove MapContentSize Co-authored-by: 허강호/Common Platform Lab(SR)/Principal Engineer/삼성전자 --- .../Handlers/ScrollView/ScrollViewHandler.Tizen.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs index da8ce2bf7ea3..a8fd0ba2457a 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs @@ -83,7 +83,11 @@ void OnContentLayoutUpdated(object? sender, LayoutEventArgs e) if (VirtualView != null && VirtualView.PresentedContent != null) { var frame = VirtualView.PresentedContent.Frame; +<<<<<<< HEAD VirtualView.PresentedContent.ToPlatform(MauiContext!)?.Move((int)e.Geometry.X + frame.X.ToScaledPixel(), (int)e.Geometry.Y + frame.Y.ToScaledPixel()); +======= + VirtualView.PresentedContent.ToNative(MauiContext!)?.Move((int)e.Geometry.X + frame.X.ToScaledPixel(), (int)e.Geometry.Y + frame.Y.ToScaledPixel()); +>>>>>>> dea789f26 (Fix ScrollView ContentSize and Padding margin (#291)) } UpdateContentSize(); @@ -151,10 +155,17 @@ public static void MapRequestScrollTo(IScrollViewHandler handler, IScrollView sc { X = x.ToScaledPixel(), Y = y.ToScaledPixel(), +<<<<<<< HEAD Width = handler.PlatformView!.Geometry.Width, Height = handler.PlatformView!.Geometry.Height }; handler.PlatformView.ScrollTo(region, !request.Instant); +======= + Width = handler.NativeView!.Geometry.Width, + Height = handler.NativeView!.Geometry.Height + }; + handler.NativeView.ScrollTo(region, !request.Instant); +>>>>>>> dea789f26 (Fix ScrollView ContentSize and Padding margin (#291)) if (request.Instant) { From 99402e568f48dcdfde9d8c3756bd63642c936916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 8 Dec 2021 13:49:18 +0900 Subject: [PATCH 095/266] Implements WindowOverlay and VisualDiagnosticsOverlay (#294) * Implements WindowOverlay and VisualDiagnosticsOverlay * Apply code review --- src/Core/src/Platform/Tizen/CoreUIAppContext.cs | 13 ++++++++----- src/Core/src/Platform/Tizen/ViewExtensions.cs | 17 +++-------------- .../src/WindowOverlay/WindowOverlay.Tizen.cs | 8 ++++++++ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index 763fcdaf8362..9af6e64da630 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -87,6 +87,14 @@ public void SetContent(EvasObject content) ModalStack.Push(content); } + public void SetOverlay(EvasObject? content) + { + content?.SetAlignment(-1, -1); + content?.SetWeight(1, 1); + content?.Show(); + MainWindow.AddResizeObject(content); + } + public void SetBackButtonPressedHandler(Func handler) { _handleBackButtonPressed = handler; @@ -130,11 +138,6 @@ void InitializeMainWindow() BaseCircleSurface = new CircleSurface(conformant); } conformant.SetContent(BaseLayout); - - if (DeviceType == DeviceType.Watch) - { - BaseCircleSurface = new CircleSurface(conformant); - } } MainWindow.Active(); diff --git a/src/Core/src/Platform/Tizen/ViewExtensions.cs b/src/Core/src/Platform/Tizen/ViewExtensions.cs index 9289c7e425a5..b1577d3108b0 100644 --- a/src/Core/src/Platform/Tizen/ViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/ViewExtensions.cs @@ -332,11 +332,7 @@ internal static Rectangle GetNativeViewBounds(this EvasObject nativeView) if (nativeView == null) return new Rectangle(); - return new Rectangle( - nativeView.Geometry.X, - nativeView.Geometry.Y, - nativeView.Geometry.Width, - nativeView.Geometry.Height); + return nativeView.Geometry.ToDP(); } internal static Matrix4x4 GetViewTransform(this IView view) @@ -348,7 +344,7 @@ internal static Matrix4x4 GetViewTransform(this IView view) } internal static Matrix4x4 GetViewTransform(this EvasObject nativeView) - => nativeView.GetViewTransform(); + => new Matrix4x4(); internal static Graphics.Rectangle GetBoundingBox(this IView view) => view.GetNative(true).GetBoundingBox(); @@ -358,14 +354,7 @@ internal static Graphics.Rectangle GetBoundingBox(this EvasObject? nativeView) if (nativeView == null) return new Rectangle(); - var rect = nativeView.Geometry; - - var nvb = nativeView.GetNativeViewBounds(); - var transform = nativeView.GetViewTransform(); - var radians = transform.ExtractAngleInRadians(); - //TODO: Need to impl - - return new Rectangle(nvb.X, nvb.Y, nvb.Width, nvb.Height); + return nativeView.Geometry.ToDP(); } } } diff --git a/src/Core/src/WindowOverlay/WindowOverlay.Tizen.cs b/src/Core/src/WindowOverlay/WindowOverlay.Tizen.cs index e22b038c00cd..18fa01a15ea4 100644 --- a/src/Core/src/WindowOverlay/WindowOverlay.Tizen.cs +++ b/src/Core/src/WindowOverlay/WindowOverlay.Tizen.cs @@ -73,5 +73,13 @@ partial void OnDisableUITouchEventPassthroughSet() _graphicsView.RepeatEvents = !DisableUITouchEventPassthrough; } } + + partial void OnDisableUITouchEventPassthroughSet() + { + if (_graphicsView != null) + { + _graphicsView.RepeatEvents = !DisableUITouchEventPassthrough; + } + } } } \ No newline at end of file From 0a49bf4c4365ec051ae201b2f552ebb2c34adf8b Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 9 Dec 2021 17:02:14 +0900 Subject: [PATCH 096/266] [Tizen] Fix Image Handler --- .../src/Handlers/Image/ImageHandler.Tizen.cs | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs b/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs index 7f4d4113c5fe..f0604f542f4b 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs @@ -44,34 +44,4 @@ void OnSetImageSource(Image? obj) // Empty on purpose } } - - // TODO : Will be removed. Use ImageEx temporaily before Tizen.UIExtension.Image fixing. - class ImageEx : Image, IMeasurable - { - public ImageEx(ElmSharp.EvasObject parent) : base(parent) { } - - Size IMeasurable.Measure(double availableWidth, double availableHeight) - { - var imageSize = ObjectSize; - var size = new Size() - { - Width = imageSize.Width, - Height = imageSize.Height, - }; - - if (0 != availableWidth && 0 != availableHeight - && (imageSize.Width > availableWidth || imageSize.Height > availableHeight)) - { - // when available size is limited and insufficient for the image ... - double imageRatio = imageSize.Width / imageSize.Height; - double availableRatio = availableWidth / availableHeight; - // depending on the relation between availableRatio and imageRatio, copy the availableWidth or availableHeight - // and calculate the size which preserves the image ratio, but does not exceed the available size - size.Width = availableRatio > imageRatio ? imageSize.Width * availableHeight / imageSize.Height : availableWidth; - size.Height = availableRatio > imageRatio ? availableHeight : imageSize.Height * availableWidth / imageSize.Width; - } - - return size; - } - } } \ No newline at end of file From 033c6ff52169dce9b92aaf9b9bc95066ee19e14c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 9 Dec 2021 18:41:34 +0900 Subject: [PATCH 097/266] Remove GetDesiredSize (#295) --- .../src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs index 3b7f107924ac..457ab97476bc 100644 --- a/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs +++ b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs @@ -56,10 +56,5 @@ public static void MapIsVisible(ItemsViewHandler handler, ItemsView public static void MapItemsUpdatingScrollMode(ItemsViewHandler handler, ItemsView itemsView) { } - - public override Size GetDesiredSize(double widthConstraint, double heightConstraint) - { - return VirtualView.Measure(widthConstraint, heightConstraint, MeasureFlags.IncludeMargins).Request; - } } } From 69c163afbd885725db61f29b5c33f051f0256d76 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 10 Dec 2021 09:28:31 +0900 Subject: [PATCH 098/266] [Tizen] Fix ButtonHandler --- src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs | 8 ++++++-- src/Core/src/Platform/ImageSourcePartLoader.cs | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs index bbac0ca9b951..1a23e85c1195 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs @@ -46,11 +46,15 @@ public static Task MapImageSourceAsync(IButtonHandler handler, IImage image) return handler.ImageSourceLoader.UpdateImageSourceAsync(); } - public static void MapImageSource(IButtonHandler handler, IButton image) => + public static void MapImageSource(IButtonHandler handler, IImageButton image) => MapImageSourceAsync(handler, image).FireAndForget(handler); - public static Task MapImageSourceAsync(IButtonHandler handler, IButton image) + public static Task MapImageSourceAsync(IButtonHandler handler, IImageButton image) { + if (image.Source == null) + { + return Task.CompletedTask; + } return handler.ImageSourceLoader.UpdateImageSourceAsync(); } diff --git a/src/Core/src/Platform/ImageSourcePartLoader.cs b/src/Core/src/Platform/ImageSourcePartLoader.cs index fbd2c1d7bff6..d80a4ad5ba6e 100644 --- a/src/Core/src/Platform/ImageSourcePartLoader.cs +++ b/src/Core/src/Platform/ImageSourcePartLoader.cs @@ -70,6 +70,12 @@ public async Task UpdateImageSourceAsync() .ConfigureAwait(false); SourceManager.CompleteLoad(result); +#elif TIZEN + PlatformImage image = (PlatformView as PlatformImage)??new PlatformImage(PlatformView); + var result = await imageSource.UpdateSourceAsync(image, ImageSourceServiceProvider, SetImage!, token) + .ConfigureAwait(false); + + SourceManager.CompleteLoad(result); #else await Task.CompletedTask; #endif From b4ca897c2a8fdd485111a418a3e52fcc93aa3621 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 10 Dec 2021 17:34:01 +0900 Subject: [PATCH 099/266] [Tizen] Organize and centralize HandlerExtensions --- .../src/Platform/Tizen/HandlerExtensions.cs | 98 ------------------- 1 file changed, 98 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/HandlerExtensions.cs diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs deleted file mode 100644 index b27d6d5a2840..000000000000 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using Tizen.Applications; -using ElmSharp; - -namespace Microsoft.Maui.Platform -{ - public static class HandlerExtensions - { - internal static EvasObject? GetNative(this IElement view, bool returnWrappedIfPresent) - { - if (view.Handler is INativeViewHandler nativeHandler && nativeHandler.NativeView != null) - return nativeHandler.NativeView; - - return (view.Handler?.NativeView as EvasObject); - } - - internal static EvasObject ToNative(this IElement view, IMauiContext context, bool returnWrappedIfPresent) - { - var nativeView = view.ToNative(context); - - if (view.Handler is INativeViewHandler nativeHandler && nativeHandler.NativeView != null) - return nativeHandler.NativeView; - - return nativeView; - } - - public static EvasObject ToContainerView(this IElement view, IMauiContext context) => - new ContainerView(context) { CurrentView = view }; - - public static EvasObject ToNative(this IElement view, IMauiContext context) - { - var handler = view.ToHandler(context); - - if (handler.NativeView is not EvasObject result) - { - throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); - } - - return result; - } - - public static INativeViewHandler ToHandler(this IElement view, IMauiContext context) - { - _ = view ?? throw new ArgumentNullException(nameof(view)); - _ = context ?? throw new ArgumentNullException(nameof(context)); - - //This is how MVU works. It collapses views down - if (view is IReplaceableView ir) - view = ir.ReplacedView; - - var handler = view.Handler; - - if (handler?.MauiContext != null && handler.MauiContext != context) - handler = null; - - if (handler == null) - handler = context.Handlers.GetHandler(view.GetType()); - - if (handler == null) - throw new Exception($"Handler not found for view {view}."); - - handler.SetMauiContext(context); - - view.Handler = handler; - - if (handler.VirtualView != view) - handler.SetVirtualView(view); - - return (INativeViewHandler)handler; - } - - public static void SetApplicationHandler(this CoreUIApplication nativeApplication, IApplication application, IMauiContext context) => - SetHandler(application, context); - - public static void SetWindowHandler(this Window nativeWindow, IWindow window, IMauiContext context) => - SetHandler(window, context); - - static void SetHandler(IElement element, IMauiContext context) - { - _ = element ?? throw new ArgumentNullException(nameof(element)); - _ = context ?? throw new ArgumentNullException(nameof(context)); - - var handler = element.Handler; - if (handler == null) - handler = context.Handlers.GetHandler(element.GetType()); - - if (handler == null) - throw new Exception($"Handler not found for view {element}."); - - handler.SetMauiContext(context); - - element.Handler = handler; - - if (handler.VirtualView != element) - handler.SetVirtualView(element); - } - } -} \ No newline at end of file From e4d8612eb89da2bab552e08bfafcaac484a96054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 13 Dec 2021 18:30:59 +0900 Subject: [PATCH 100/266] Refactor WrapperView and Fix Issue (#302) * Refactor WrapperView * Use Thickness type for Shadow margin * Update variable name * Update class name to GraphicsExtensions --- .../src/Platform/Tizen/GeometryExtensions.cs | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/GeometryExtensions.cs diff --git a/src/Core/src/Platform/Tizen/GeometryExtensions.cs b/src/Core/src/Platform/Tizen/GeometryExtensions.cs deleted file mode 100644 index 27b8f5b269b0..000000000000 --- a/src/Core/src/Platform/Tizen/GeometryExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using ElmSharp; -using Tizen.UIExtensions.ElmSharp; - -namespace Microsoft.Maui.Platform -{ - internal static class GeometryExtensions - { - public static Rect ExpandTo(this Rect geometry, IShadow? shadow) - { - double left = 0; - double top = 0; - double right = 0; - double bottom = 0; - - var scaledOffsetX = shadow == null ? 0 : shadow.Offset.X.ToScaledPixel(); - var scaledOffsetY = shadow == null ? 0 : shadow.Offset.Y.ToScaledPixel(); - var scaledBlurRadius = shadow == null ? 0 : ((double)shadow.Radius).ToScaledPixel(); - var spreadSize = scaledBlurRadius * 3; - var spreadLeft = scaledOffsetX - spreadSize; - var spreadRight = scaledOffsetX + spreadSize; - var spreadTop = scaledOffsetY - spreadSize; - var spreadBottom = scaledOffsetY + spreadSize; - if (left > spreadLeft) - left = spreadLeft; - if (top > spreadTop) - top = spreadTop; - if (right < spreadRight) - right = spreadRight; - if (bottom < spreadBottom) - bottom = spreadBottom; - - var canvasGeometry = new Rect( - geometry.X + (int)left, - geometry.Y + (int)top, - geometry.Width + (int)right - (int)left, - geometry.Height + (int)bottom - (int)top); - - return canvasGeometry; - } - } -} \ No newline at end of file From 115bb2c5508576f69fed2c974be77454d839c127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 13 Dec 2021 18:37:36 +0900 Subject: [PATCH 101/266] Fix essentials sample for Tizen (#305) --- src/Essentials/samples/Samples/Essentials.Sample.csproj | 1 - src/Essentials/samples/Samples/Platforms/Tizen/Program.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Essentials/samples/Samples/Essentials.Sample.csproj b/src/Essentials/samples/Samples/Essentials.Sample.csproj index 59ae2ce826ee..04b4aeb752c9 100644 --- a/src/Essentials/samples/Samples/Essentials.Sample.csproj +++ b/src/Essentials/samples/Samples/Essentials.Sample.csproj @@ -32,7 +32,6 @@ - diff --git a/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs b/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs index ba600d072e83..4602bc64c8f2 100644 --- a/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs +++ b/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs @@ -13,4 +13,4 @@ static void Main(string[] args) app.Run(args); } } -} \ No newline at end of file +} From 71d532e39911abd73708dc34999b07b16aec129d Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 14 Dec 2021 18:58:58 +0900 Subject: [PATCH 102/266] [Tizen] Fix NativeView casting issue --- .../Handlers/ScrollView/ScrollViewHandler.Tizen.cs | 11 ----------- src/Core/src/Platform/Tizen/ContainerView.cs | 4 ---- 2 files changed, 15 deletions(-) diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs index a8fd0ba2457a..da8ce2bf7ea3 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs @@ -83,11 +83,7 @@ void OnContentLayoutUpdated(object? sender, LayoutEventArgs e) if (VirtualView != null && VirtualView.PresentedContent != null) { var frame = VirtualView.PresentedContent.Frame; -<<<<<<< HEAD VirtualView.PresentedContent.ToPlatform(MauiContext!)?.Move((int)e.Geometry.X + frame.X.ToScaledPixel(), (int)e.Geometry.Y + frame.Y.ToScaledPixel()); -======= - VirtualView.PresentedContent.ToNative(MauiContext!)?.Move((int)e.Geometry.X + frame.X.ToScaledPixel(), (int)e.Geometry.Y + frame.Y.ToScaledPixel()); ->>>>>>> dea789f26 (Fix ScrollView ContentSize and Padding margin (#291)) } UpdateContentSize(); @@ -155,17 +151,10 @@ public static void MapRequestScrollTo(IScrollViewHandler handler, IScrollView sc { X = x.ToScaledPixel(), Y = y.ToScaledPixel(), -<<<<<<< HEAD Width = handler.PlatformView!.Geometry.Width, Height = handler.PlatformView!.Geometry.Height }; handler.PlatformView.ScrollTo(region, !request.Instant); -======= - Width = handler.NativeView!.Geometry.Width, - Height = handler.NativeView!.Geometry.Height - }; - handler.NativeView.ScrollTo(region, !request.Instant); ->>>>>>> dea789f26 (Fix ScrollView ContentSize and Padding margin (#291)) if (request.Instant) { diff --git a/src/Core/src/Platform/Tizen/ContainerView.cs b/src/Core/src/Platform/Tizen/ContainerView.cs index ea0ce2299fec..d4039213bd7a 100644 --- a/src/Core/src/Platform/Tizen/ContainerView.cs +++ b/src/Core/src/Platform/Tizen/ContainerView.cs @@ -65,11 +65,7 @@ void SetView(IElement? view, bool forceRefresh = false) if (_view != null) { _ = _context ?? throw new ArgumentNullException(nameof(_context)); -<<<<<<< HEAD MainView = _view.ToPlatform(_context); -======= - MainView = _view.ToNative(_context); ->>>>>>> 87f5fa6cb ([Tizen] Initial Reloadyfy support) } } From e9eb4545f9be3d57ce7a76a37b72d3638b99024c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 24 Dec 2021 08:21:00 +0900 Subject: [PATCH 103/266] Fix BlazorWebview binary resource issue (#317) --- .../src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs | 4 +++- src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs index d4cdf0de679f..32d9bb5ca742 100644 --- a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs +++ b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using Microsoft.AspNetCore.Components.Web; using Microsoft.Extensions.FileProviders; using Microsoft.Maui; using Microsoft.Maui.Dispatching; @@ -121,6 +120,9 @@ private void StartWebViewCoreIfPossible() // unclear there's any other use case. We can add more options later if so. var contentRootDir = Path.GetDirectoryName(HostPage!) ?? string.Empty; var hostPageRelativePath = Path.GetRelativePath(contentRootDir, HostPage!); + + var customFileProvider = VirtualView.CreateFileProvider(contentRootDir); + var resContentRootDir = Path.Combine(TApplication.Current.DirectoryInfo.Resource, contentRootDir); var mauiAssetFileProvider = new PhysicalFileProvider(resContentRootDir); diff --git a/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs b/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs index 5df674fa296c..c083546fd9c3 100644 --- a/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs +++ b/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs @@ -26,14 +26,12 @@ public static void SetInspectorStart(this TWebView webView, uint port) ewk_context_inspector_server_start(contextHandle.Value, port); } - public static bool SetInterceptRequestResponse(this TWebView webView, IntPtr request, string header, string body, uint length) -#pragma warning restore IDE0060 // Remove unused parameter + public static bool SetInterceptRequestResponse(this TWebView webView, IntPtr request, string header, byte[] body, uint length) { return ewk_intercept_request_response_set(request, header, body, length); } - public static bool IgnoreInterceptRequest(this TWebView webView, IntPtr request) -#pragma warning restore IDE0060 // Remove unused parameter + public static bool IgnoreInterceptRequest(this TWebView webView, IntPtr request) { return ewk_intercept_request_ignore(request); } @@ -71,5 +69,8 @@ internal static string ewk_intercept_request_http_method_get(IntPtr request) [DllImport(ChromiumEwk)] internal static extern bool ewk_intercept_request_response_set(IntPtr request, string header, string body, uint length); + + [DllImport(ChromiumEwk)] + internal static extern bool ewk_intercept_request_response_set(IntPtr request, string header, byte[] body, uint length); } } From 1fa4f9254b164d8d478fb599dabda3532bc5e921 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 24 Dec 2021 14:01:03 +0900 Subject: [PATCH 104/266] [Tizen] Handle query strings in Blazor static assets by trimming them out --- src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs index 32d9bb5ca742..0dbbc7a73827 100644 --- a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs +++ b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs @@ -5,7 +5,6 @@ using Microsoft.Maui.Dispatching; using Microsoft.Maui.Handlers; using Tizen.WebView; -using TApplication = Tizen.Applications.Application; using TChromium = Tizen.WebView.Chromium; using TWebView = Tizen.WebView.WebView; From 5c10a7b08e82611785d4130428233bcdbd973d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 3 Jan 2022 16:51:20 +0900 Subject: [PATCH 105/266] Refactor MauiContext (#330) --- src/Core/src/IMauiContext.cs | 2 - src/Core/src/MauiContext.cs | 6 - src/Core/src/MauiContextExtensions.cs | 3 - .../src/Platform/Tizen/CoreUIAppContext.cs | 165 ------------------ .../src/Platform/Tizen/CoreUIAppExtensions.cs | 80 --------- .../src/Platform/Tizen/MauiApplication.cs | 9 +- 6 files changed, 8 insertions(+), 257 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/CoreUIAppContext.cs delete mode 100644 src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index 11b1593bb241..cf899f3188b5 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -10,8 +10,6 @@ public interface IMauiContext #if __ANDROID__ Android.Content.Context? Context { get; } -#elif TIZEN - CoreUIAppContext? Context { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/MauiContext.cs b/src/Core/src/MauiContext.cs index aab57cbf6271..341f0a423205 100644 --- a/src/Core/src/MauiContext.cs +++ b/src/Core/src/MauiContext.cs @@ -19,12 +19,6 @@ public MauiContext(IServiceProvider services, Android.Content.Context context) { AddWeakSpecific(context); } -#elif TIZEN - public MauiContext(IServiceProvider services, CoreUIAppContext context) - : this(services) - { - AddWeakSpecific(context); - } #endif public MauiContext(IServiceProvider services) diff --git a/src/Core/src/MauiContextExtensions.cs b/src/Core/src/MauiContextExtensions.cs index 4f734ca41eda..5532ec41776b 100644 --- a/src/Core/src/MauiContextExtensions.cs +++ b/src/Core/src/MauiContextExtensions.cs @@ -52,9 +52,6 @@ public static IMauiContext MakeWindowScope(this IMauiContext mauiContext, Native #if ANDROID var scopedContext = new MauiContext(scope.ServiceProvider, platformWindow); -#elif TIZEN - var scopedContext = new MauiContext(scope.ServiceProvider, platformWindow); - scopedContext.AddWeakSpecific(platformWindow.MainWindow); #else var scopedContext = new MauiContext(scope.ServiceProvider); #endif diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs deleted file mode 100644 index 9af6e64da630..000000000000 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Reflection; -using Tizen.Common; -using Tizen.Applications; -using ElmSharp; -using ElmSharp.Wearable; -using Tizen.UIExtensions.ElmSharp; -using Tizen.UIExtensions.Common; -using ELayout = ElmSharp.Layout; - -namespace Microsoft.Maui.Platform -{ - public class CoreUIAppContext - { - static CoreUIAppContext? _instance = null; - - Func? _handleBackButtonPressed; - - public static bool IsInitialized { get; private set; } - - public static CoreUIAppContext GetInstance(CoreApplication application, Window? window = null) - { - if (IsInitialized) - return _instance!; - - _instance = (window == null) ? new CoreUIAppContext(application) : new CoreUIAppContext(application, window); - return _instance; - } - - public CoreApplication CurrentApplication { get; private set; } - - public string ResourceDir => CurrentApplication.DirectoryInfo.Resource; - - public EvasObject NativeParent => BaseLayout; - - public Window MainWindow { get; set; } - - public ELayout BaseLayout { get; set; } - - public ModalStack ModalStack { get; private set; } - - public CircleSurface? BaseCircleSurface { get; set; } - - public DeviceType DeviceType => DeviceInfo.GetDeviceType(); - - protected CoreUIAppContext(CoreApplication application) : this(application, CreateDefaultWindow()) - { - } - - protected CoreUIAppContext(CoreApplication application, Window window) - { - _ = application ?? throw new ArgumentNullException(nameof(application)); - _ = window ?? throw new ArgumentNullException(nameof(window)); - - Elementary.Initialize(); - Elementary.ThemeOverlay(); - CurrentApplication = application; - MainWindow = window; - InitializeMainWindow(); - - _ = BaseLayout ?? throw new ArgumentNullException(nameof(BaseLayout)); - - if (DotnetUtil.TizenAPIVersion < 5) - { - // We should set the env variable to support IsolatedStorageFile on tizen 4.0 or lower version. - Environment.SetEnvironmentVariable("XDG_DATA_HOME", CurrentApplication.DirectoryInfo.Data); - } - - ModalStack = new ModalStack(NativeParent) - { - AlignmentX = -1, - AlignmentY = -1, - WeightX = 1, - WeightY= 1, - }; - ModalStack.Show(); - BaseLayout.SetContent(ModalStack); - - IsInitialized = true; - } - - public void SetContent(EvasObject content) - { - content.SetAlignment(-1, -1); - content.SetWeight(1, 1); - content.Show(); - ModalStack.Push(content); - } - - public void SetOverlay(EvasObject? content) - { - content?.SetAlignment(-1, -1); - content?.SetWeight(1, 1); - content?.Show(); - MainWindow.AddResizeObject(content); - } - - public void SetBackButtonPressedHandler(Func handler) - { - _handleBackButtonPressed = handler; - } - - static Window CreateDefaultWindow() - { - return GetPreloadedWindow() ?? new Window("MauiDefaultWindow"); - } - - static Window? GetPreloadedWindow() - { - var type = typeof(Window); - // Use reflection to avoid breaking compatibility. ElmSharp.Window.CreateWindow() is has been added since API6. - var methodInfo = type.GetMethod("CreateWindow", BindingFlags.NonPublic | BindingFlags.Static); - - return (Window?)methodInfo?.Invoke(null, new object[] { "FormsWindow" }); - } - - void InitializeMainWindow() - { -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. -#pragma warning disable CS8601 // Possible null reference assignment. - BaseLayout = (ELayout)MainWindow.GetType().GetProperty("BaseLayout")?.GetValue(MainWindow); - BaseCircleSurface = (CircleSurface)MainWindow.GetType().GetProperty("BaseCircleSurface")?.GetValue(MainWindow); -#pragma warning restore CS8601 // Possible null reference assignment. -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. - - if (BaseLayout == null) - { - var conformant = new Conformant(MainWindow); - conformant.Show(); - - var layout = new ApplicationLayout(conformant); - layout.Show(); - - BaseLayout = layout; - - if (DeviceType == DeviceType.Watch) - { - BaseCircleSurface = new CircleSurface(conformant); - } - conformant.SetContent(BaseLayout); - } - - MainWindow.Active(); - MainWindow.Show(); - MainWindow.AvailableRotations = DisplayRotation.Degree_0 | DisplayRotation.Degree_90 | DisplayRotation.Degree_180 | DisplayRotation.Degree_270; - - MainWindow.Deleted += (s, e) => CurrentApplication.Exit(); - - MainWindow.RotationChanged += (sender, e) => - { - // TODO : should update later - }; - - MainWindow.BackButtonPressed += OnBackButtonPressed; - } - - void OnBackButtonPressed(object? sender, EventArgs e) - { - if (!(_handleBackButtonPressed?.Invoke() ?? false)) - { - CurrentApplication.Exit(); - } - } - } -} diff --git a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs deleted file mode 100644 index c6edaddfd97a..000000000000 --- a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using Microsoft.Maui.LifecycleEvents; -using Tizen.Applications; -using EWindow = ElmSharp.Window; - -namespace Microsoft.Maui.Platform -{ - internal static class CoreUIAppExtensions - { - public static IWindow GetWindow(this CoreUIApplication application) - { - var nativeWindow = CoreUIAppContext.GetInstance(application)?.MainWindow; - - foreach (var window in MauiApplication.Current.Application.Windows) - { - if (window?.Handler?.NativeView is EWindow win && win == nativeWindow) - return window; - } - - throw new InvalidOperationException("Window Not Found"); - } - - public static void RequestNewWindow(this CoreApplication nativeApplication, IApplication application, OpenWindowRequest? args) - { - if (application.Handler?.MauiContext is not IMauiContext applicationContext) - return; - - var state = args?.State; - var bundle = state.ToBundle(); - - //TODO : Need to implementation - } - - public static void CreateNativeWindow(this CoreUIApplication nativeApplication, IApplication application) - { - if (application.Handler?.MauiContext is not IMauiContext applicationContext) - return; - - var context = CoreUIAppContext.GetInstance(nativeApplication); - - var mauiContext = applicationContext.MakeWindowScope(context, out var windowScope); - - applicationContext.Services.InvokeLifecycleEvents(del => del(mauiContext)); - - var tizenWindow = mauiContext.Context?.MainWindow; - - if (tizenWindow == null) - throw new InvalidOperationException($"The {nameof(tizenWindow)} instance was not found."); - - var activationState = new ActivationState(mauiContext); - var window = application.CreateWindow(activationState); - - tizenWindow.SetWindowHandler(window, mauiContext); - } - - public static Bundle ToBundle(this IPersistedState? state) - { - var userInfo = new Bundle(); - - var keyset = userInfo.Keys; - if (keyset != null) - { - foreach (var k in keyset) - { - userInfo?.GetItem(k); - } - } - - if (state is not null) - { - foreach (var pair in state) - { - userInfo.AddItem(pair.Key, pair.Value); - } - } - - return userInfo; - } - } -} diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index fc3d4da7fbca..e9e3c454708b 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -44,9 +44,16 @@ protected override void OnPreCreate() Services = _applicationContext.Services; + Elementary.Initialize(); + Elementary.ThemeOverlay(); + var mauiApp = CreateMauiApp(); - var rootContext = new MauiContext(mauiApp.Services, CoreUIAppContext.GetInstance(this)); + var rootContext = new MauiContext(mauiApp.Services); + + var nativeWindow = CoreAppExtensions.GetDefaultWindow(); + nativeWindow.Initialize(); + rootContext.AddWeakSpecific(nativeWindow); _applicationContext = rootContext.MakeApplicationScope(this); From 30461ef989cc5dbd32a527d6aa6156fd161c41a9 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 3 Jan 2022 21:13:11 +0900 Subject: [PATCH 106/266] [Tizen] Adds PaintExtensions --- .../src/Graphics/PaintExtensions.Tizen.cs | 89 +++++++++++++++++++ src/Core/src/Platform/Tizen/WrapperView.cs | 2 - 2 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/Core/src/Graphics/PaintExtensions.Tizen.cs diff --git a/src/Core/src/Graphics/PaintExtensions.Tizen.cs b/src/Core/src/Graphics/PaintExtensions.Tizen.cs new file mode 100644 index 000000000000..452db3e1e3c0 --- /dev/null +++ b/src/Core/src/Graphics/PaintExtensions.Tizen.cs @@ -0,0 +1,89 @@ +using EColor = ElmSharp.Color; +using TColor = Tizen.UIExtensions.Common.Color; + +namespace Microsoft.Maui.Graphics +{ + public static partial class PaintExtensions + { + public static EColor ToNativeEFL(this Paint paint) + { + var color = paint.ToColor(); + return color != null ? color.ToNativeEFL() : EColor.Default; + } + + public static TColor ToNative(this Paint paint) + { + var color = paint.ToColor(); + return color != null ? color.ToNative() : TColor.Default; + } + + public static MauiDrawable? ToDrawable(this Paint paint) + { + if (paint is SolidPaint solidPaint) + return solidPaint.CreateDrawable(); + + if (paint is LinearGradientPaint linearGradientPaint) + return linearGradientPaint.CreateDrawable(); + + if (paint is RadialGradientPaint radialGradientPaint) + return radialGradientPaint.CreateDrawable(); + + if (paint is ImagePaint imagePaint) + return imagePaint.CreateDrawable(); + + if (paint is PatternPaint patternPaint) + return patternPaint.CreateDrawable(); + + return null; + } + + public static MauiDrawable? CreateDrawable(this SolidPaint solidPaint) + { + return new MauiDrawable + { + Background = solidPaint + }; + } + + public static MauiDrawable? CreateDrawable(this LinearGradientPaint linearGradientPaint) + { + if (!linearGradientPaint.IsValid()) + return null; + + return new MauiDrawable + { + Background = linearGradientPaint + }; + } + + public static MauiDrawable? CreateDrawable(this RadialGradientPaint radialGradientPaint) + { + if (!radialGradientPaint.IsValid()) + return null; + + return new MauiDrawable + { + Background = radialGradientPaint + }; + } + + public static MauiDrawable? CreateDrawable(this ImagePaint imagePaint) + { + return new MauiDrawable + { + Background = imagePaint + }; + } + + public static MauiDrawable? CreateDrawable(this PatternPaint patternPaint) + { + return new MauiDrawable + { + Background = patternPaint + }; + } + + static bool IsValid(this GradientPaint? gradienPaint) => + gradienPaint?.GradientStops?.Length > 0; + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index 1a9642125782..54c201db38d7 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -21,11 +21,9 @@ public partial class WrapperView : Canvas, IBackgroundCanvas Lazy _drawableCanvas; Lazy _clipperView; EvasObject? _content; - MauiDrawable _mauiDrawable; public WrapperView(EvasObject parent) : base(parent) { - _mauiDrawable = new MauiDrawable(); _drawableCanvas = new Lazy(() => { var view = new SkiaGraphicsView(parent) From c57e0dedf92826aa266671a5a48741e83b0ed10e Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 14 Jan 2022 18:09:12 +0900 Subject: [PATCH 107/266] [Tizen] Implement CursorPosition in IEditor/ITextInput Handlers --- src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs | 10 ++++++++++ src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs | 4 ++-- src/Core/src/Platform/Tizen/EntryExtensions.cs | 6 +++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs index 9d4df05d5f1e..1de6837a3c9b 100644 --- a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs +++ b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs @@ -128,6 +128,16 @@ public static void MapVerticalTextAlignment(EditorHandler handler, IEditor edito handler.NativeView?.UpdateVerticalTextAlignment(editor); } + public static void MapCursorPosition(EditorHandler handler, ITextInput editor) + { + handler.NativeView?.UpdateSelectionLength(editor); + } + + public static void MapSelectionLength(EditorHandler handler, ITextInput editor) + { + handler.NativeView?.UpdateSelectionLength(editor); + } + [MissingMapper] public static void MapCharacterSpacing(IEditorHandler handler, IEditor editor) { } diff --git a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs index 172585a09cae..ee540d37bb09 100644 --- a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs +++ b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs @@ -166,9 +166,9 @@ public static void MapCursorPosition(EntryHandler handler, IEntry entry) handler.NativeView?.UpdateSelectionLength(entry); } - public static void MapKeyboard(EditorHandler handler, IEditor editor) + public static void MapKeyboard(EditorHandler handler, IEntry entry) { - handler.NativeView?.UpdateKeyboard(editor); + handler.NativeView?.UpdateKeyboard(entry); } [MissingMapper] diff --git a/src/Core/src/Platform/Tizen/EntryExtensions.cs b/src/Core/src/Platform/Tizen/EntryExtensions.cs index d5deaf79e40c..48a1f22ca88c 100644 --- a/src/Core/src/Platform/Tizen/EntryExtensions.cs +++ b/src/Core/src/Platform/Tizen/EntryExtensions.cs @@ -143,7 +143,7 @@ static int GetSelectionEnd(Entry platformEntry, ITextInput entry, int start) /* Updates both the IEntry.CursorPosition and IEntry.SelectionLength properties. */ [PortHandler] - public static void UpdateSelectionLength(this Entry nativeEntry, IEntry entry) + public static void UpdateSelectionLength(this Entry nativeEntry, ITextInput entry) { if (nativeEntry.IsUpdatingCursorPosition) return; @@ -161,7 +161,7 @@ public static void UpdateSelectionLength(this Entry nativeEntry, IEntry entry) } } - static int GetSelectionStart(Entry nativeEntry, IEntry entry) + static int GetSelectionStart(Entry nativeEntry, ITextInput entry) { int start = nativeEntry.Text?.Length ?? 0; int cursorPosition = entry.CursorPosition; @@ -175,7 +175,7 @@ static int GetSelectionStart(Entry nativeEntry, IEntry entry) return start; } - static int GetSelectionEnd(Entry nativeEntry, IEntry entry, int start) + static int GetSelectionEnd(Entry nativeEntry, ITextInput entry, int start) { int end = Math.Max(start, Math.Min(nativeEntry.Text?.Length ?? 0, start + entry.SelectionLength)); int selectionLength = end - start; From 8d06c4b16e944988fc49f509bff9dd5061f40e65 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 17 Jan 2022 13:23:09 +0900 Subject: [PATCH 108/266] [Tizen] Remove GetNative --- src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs | 8 ++++---- src/Core/src/Platform/Tizen/ViewExtensions.cs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs index a8c72c6b0845..5f8e1fadc77d 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs @@ -179,7 +179,7 @@ public void Update(int index, IView child) toBeRemoved.Unrealize(); var targetIndex = VirtualView.GetLayoutHandlerIndex(child); - NativeView.Children.Insert(targetIndex, child.ToNative(MauiContext, true)); + NativeView.Children.Insert(targetIndex, child.ToNative(MauiContext)); if (child.Handler is INativeViewHandler childHandler) { childHandler?.SetParent(this); @@ -202,7 +202,7 @@ void EnsureZIndexOrder(IView child) return; } - var nativeChildView = child.ToNative(MauiContext!, true); + var nativeChildView = child.ToNative(MauiContext!); var currentIndex = NativeView.Children.IndexOf(nativeChildView); if (currentIndex == -1) @@ -213,7 +213,7 @@ void EnsureZIndexOrder(IView child) var targetIndex = VirtualView.GetLayoutHandlerIndex(child); if (targetIndex > currentIndex) { - child.ToNative(MauiContext!, true).RaiseTop(); + child.ToNative(MauiContext!).RaiseTop(); for (int i = targetIndex+1; i < NativeView.Children.Count; i++) { NativeView.Children[i].RaiseTop(); @@ -221,7 +221,7 @@ void EnsureZIndexOrder(IView child) } else { - child.ToNative(MauiContext!, true).Lower(); + child.ToNative(MauiContext!).Lower(); for (int i = targetIndex-1; i >= 0; i--) { NativeView.Children[i].Lower(); diff --git a/src/Core/src/Platform/Tizen/ViewExtensions.cs b/src/Core/src/Platform/Tizen/ViewExtensions.cs index b1577d3108b0..20813554ad2a 100644 --- a/src/Core/src/Platform/Tizen/ViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/ViewExtensions.cs @@ -318,7 +318,7 @@ internal static IDisposable OnUnloaded(this EvasObject view, Action action) internal static Rectangle GetNativeViewBounds(this IView view) { - var nativeView = view?.GetNative(true); + var nativeView = view?.ToNative(); if (nativeView == null) { return new Rectangle(); @@ -337,7 +337,7 @@ internal static Rectangle GetNativeViewBounds(this EvasObject nativeView) internal static Matrix4x4 GetViewTransform(this IView view) { - var nativeView = view?.GetNative(true); + var nativeView = view?.ToNative(); if (nativeView == null) return new Matrix4x4(); return nativeView.GetViewTransform(); @@ -347,7 +347,7 @@ internal static Matrix4x4 GetViewTransform(this EvasObject nativeView) => new Matrix4x4(); internal static Graphics.Rectangle GetBoundingBox(this IView view) - => view.GetNative(true).GetBoundingBox(); + => view.ToNative().GetBoundingBox(); internal static Graphics.Rectangle GetBoundingBox(this EvasObject? nativeView) { From e61a78c7704c9abbdd93aa843ea0bacf91c4eaf7 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 18 Jan 2022 16:08:37 +0900 Subject: [PATCH 109/266] [Tizen] Update Microsoft.NET.Sdk.Maui/WorkloadManifest --- src/Workload/Microsoft.NET.Sdk.Maui/WorkloadManifest.in.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workload/Microsoft.NET.Sdk.Maui/WorkloadManifest.in.json b/src/Workload/Microsoft.NET.Sdk.Maui/WorkloadManifest.in.json index 341426f01a2a..62507bb87c65 100644 --- a/src/Workload/Microsoft.NET.Sdk.Maui/WorkloadManifest.in.json +++ b/src/Workload/Microsoft.NET.Sdk.Maui/WorkloadManifest.in.json @@ -123,7 +123,7 @@ "maui-tizen": { "description": ".NET MAUI SDK for Tizen", "extends": [ - "maui-core", + "maui-blazor", "tizen" ], "packs": [ From 30622a16048da011ddc03435f61252dd4930712d Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 19 Jan 2022 11:52:02 +0900 Subject: [PATCH 110/266] [Tizen] Bump to latest --- .../SwipeItemMenuItemHandler.Tizen.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs diff --git a/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs b/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs new file mode 100644 index 000000000000..e87ad23e1b9e --- /dev/null +++ b/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + //TODO : Need to implement + public partial class SwipeItemMenuItemHandler : ElementHandler + { + protected override EvasObject CreateNativeElement() + { + throw new NotImplementedException(); + } + + public static void MapTextColor(SwipeItemMenuItemHandler handler, ITextStyle view) { } + + public static void MapCharacterSpacing(SwipeItemMenuItemHandler handler, ITextStyle view) { } + + public static void MapFont(SwipeItemMenuItemHandler handler, ITextStyle view) { } + + public static void MapText(SwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } + + public static void MapBackground(SwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } + + public static void MapVisibility(SwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } + + void OnSetImageSource(EvasObject? obj) + { + throw new NotImplementedException(); + } + } +} From 3e6b0fbeb6b68cbdd9dace42bcf50703d1629bdc Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 21 Jan 2022 11:36:51 +0900 Subject: [PATCH 111/266] [Tizen] Use legacy compat renderers temporarily --- .../SwipeView/SwipeItemViewHandler.Tizen.cs | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs diff --git a/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs b/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs new file mode 100644 index 000000000000..7dbd73c1f1e6 --- /dev/null +++ b/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs @@ -0,0 +1,97 @@ +using System; +using Microsoft.Maui.Platform; + +namespace Microsoft.Maui.Handlers +{ + public class SwipeItemViewHandler : ViewHandler + { + INativeViewHandler? _contentHandler; + + public static IPropertyMapper Mapper = new PropertyMapper(ViewHandler.ViewMapper) + { + [nameof(ISwipeItemView.Content)] = MapContent, + [nameof(ISwipeItemView.Visibility)] = MapVisibility + }; + + public static CommandMapper CommandMapper = new(ViewHandler.ViewCommandMapper) + { + }; + + public SwipeItemViewHandler() : base(Mapper, CommandMapper) + { + + } + + protected SwipeItemViewHandler(IPropertyMapper mapper, CommandMapper? commandMapper = null) + : base(mapper, commandMapper ?? CommandMapper) + { + } + + public SwipeItemViewHandler(IPropertyMapper? mapper = null) : base(mapper ?? Mapper) + { + + } + + protected override ContentCanvas CreateNativeView() + { + _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} must be set to create a Page"); + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} cannot be null"); + + var view = new ContentCanvas(NativeParent, VirtualView) + { + CrossPlatformMeasure = VirtualView.CrossPlatformMeasure, + CrossPlatformArrange = VirtualView.CrossPlatformArrange + }; + + view.Show(); + return view; + } + + public override void SetVirtualView(IView view) + { + base.SetVirtualView(view); + _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); + _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); + + NativeView.CrossPlatformMeasure = VirtualView.CrossPlatformMeasure; + NativeView.CrossPlatformArrange = VirtualView.CrossPlatformArrange; + } + + void UpdateContent() + { + _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); + _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + // Cleanup the old view when reused + NativeView.Children.Clear(); + _contentHandler?.Dispose(); + _contentHandler = null; + + if (VirtualView.PresentedContent is IView view) + { + NativeView.Children.Add(view.ToNative(MauiContext)); + if (view.Handler is INativeViewHandler thandler) + { + thandler?.SetParent(this); + _contentHandler = thandler; + } + } + } + + public static void MapContent(SwipeItemViewHandler handler, ISwipeItemView page) + { + handler.UpdateContent(); + } + + public static void MapVisibility(SwipeItemViewHandler handler, ISwipeItemView view) + { + //TODO : need to update + //var swipeView = handler.NativeView.GetParentOfType(); + //if (swipeView != null) + // swipeView.UpdateIsVisibleSwipeItem(view); + + //handler.NativeView.UpdateVisibility(view.Visibility); + } + } +} From b4a66d3ac62e92c5e8f6b1420d91a4839bce11d3 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 27 Jan 2022 17:31:00 +0900 Subject: [PATCH 112/266] [Tizen] Implement IPlatformApplication.Current --- .../TabbedPage/TabbedPageHandler.Tizen.cs | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs diff --git a/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs b/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs new file mode 100644 index 000000000000..673b5c6200c4 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Maui.Handlers; +using ElmSharp; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class TabbedPageHandler : ViewHandler + { + protected override EvasObject CreateNativeView() + { + // TODO : Need to impl + throw new NotImplementedException(); + } + + public static void MapBarBackground(TabbedPageHandler handler, TabbedPage view) + { + } + public static void MapBarBackgroundColor(TabbedPageHandler handler, TabbedPage view) + { + } + public static void MapBarTextColor(TabbedPageHandler handler, TabbedPage view) + { + } + public static void MapUnselectedTabColor(TabbedPageHandler handler, TabbedPage view) + { + } + public static void MapSelectedTabColor(TabbedPageHandler handler, TabbedPage view) + { + } + + public static void MapItemsSource(TabbedPageHandler handler, TabbedPage view) + { + } + public static void MapItemTemplate(TabbedPageHandler handler, TabbedPage view) + { + } + public static void MapSelectedItem(TabbedPageHandler handler, TabbedPage view) + { + } + public static void MapCurrentPage(TabbedPageHandler handler, TabbedPage view) + { + + } + } +} From 3457dbfe24f3d593d84c57ae1b5737b3d4dc2628 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 4 Feb 2022 14:45:02 +0900 Subject: [PATCH 113/266] [Tizen] Fix INativeViewHandler to return more expected NativeView --- .../ActivityIndicator/ActivityIndicatorHandler.cs | 4 ++++ src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs | 8 ++++---- src/Core/src/Handlers/Page/PageHandler.Tizen.cs | 2 +- .../src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs | 2 +- src/Core/src/Platform/Tizen/ViewExtensions.cs | 6 +++--- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.cs b/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.cs index 586468529a61..bba609f4f57e 100644 --- a/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.cs +++ b/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.cs @@ -3,7 +3,11 @@ #elif MONOANDROID using PlatformView = Android.Widget.ProgressBar; #elif WINDOWS +<<<<<<< HEAD using PlatformView = Microsoft.UI.Xaml.Controls.ProgressRing; +======= +using PlatformView = Microsoft.Maui.Platform.MauiActivityIndicator; +>>>>>>> bb8b370f1 ([Tizen] Fix INativeViewHandler to return more expected NativeView) #elif TIZEN using PlatformView = ElmSharp.ProgressBar; #elif (NETSTANDARD || !PLATFORM) || (NET6_0_OR_GREATER && !IOS && !ANDROID && !TIZEN) diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs index 5f8e1fadc77d..d95ab08bbd54 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs @@ -179,7 +179,7 @@ public void Update(int index, IView child) toBeRemoved.Unrealize(); var targetIndex = VirtualView.GetLayoutHandlerIndex(child); - NativeView.Children.Insert(targetIndex, child.ToNative(MauiContext)); + NativeView.Children.Insert(targetIndex, child.ToPlatform(MauiContext)); if (child.Handler is INativeViewHandler childHandler) { childHandler?.SetParent(this); @@ -202,7 +202,7 @@ void EnsureZIndexOrder(IView child) return; } - var nativeChildView = child.ToNative(MauiContext!); + var nativeChildView = child.ToPlatform(MauiContext!); var currentIndex = NativeView.Children.IndexOf(nativeChildView); if (currentIndex == -1) @@ -213,7 +213,7 @@ void EnsureZIndexOrder(IView child) var targetIndex = VirtualView.GetLayoutHandlerIndex(child); if (targetIndex > currentIndex) { - child.ToNative(MauiContext!).RaiseTop(); + child.ToPlatform(MauiContext!).RaiseTop(); for (int i = targetIndex+1; i < NativeView.Children.Count; i++) { NativeView.Children[i].RaiseTop(); @@ -221,7 +221,7 @@ void EnsureZIndexOrder(IView child) } else { - child.ToNative(MauiContext!).Lower(); + child.ToPlatform(MauiContext!).Lower(); for (int i = targetIndex-1; i >= 0; i--) { NativeView.Children[i].Lower(); diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index 47ec3d6b686b..3eeb114a0a30 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -33,7 +33,7 @@ public override void NativeArrange(Graphics.Rectangle frame) { handler.NativeView.BackgroundColor = EColor.Transparent; } - handler.GetWrappedNativeView()?.UpdateBackground(page); + handler.ToPlatform()?.UpdateBackground(page); } [MissingMapper] diff --git a/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs b/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs index 7dbd73c1f1e6..2101be435e69 100644 --- a/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs @@ -70,7 +70,7 @@ void UpdateContent() if (VirtualView.PresentedContent is IView view) { - NativeView.Children.Add(view.ToNative(MauiContext)); + NativeView.Children.Add(view.ToPlatform(MauiContext)); if (view.Handler is INativeViewHandler thandler) { thandler?.SetParent(this); diff --git a/src/Core/src/Platform/Tizen/ViewExtensions.cs b/src/Core/src/Platform/Tizen/ViewExtensions.cs index 20813554ad2a..6e882fdeb35e 100644 --- a/src/Core/src/Platform/Tizen/ViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/ViewExtensions.cs @@ -318,7 +318,7 @@ internal static IDisposable OnUnloaded(this EvasObject view, Action action) internal static Rectangle GetNativeViewBounds(this IView view) { - var nativeView = view?.ToNative(); + var nativeView = view?.ToPlatform(); if (nativeView == null) { return new Rectangle(); @@ -337,7 +337,7 @@ internal static Rectangle GetNativeViewBounds(this EvasObject nativeView) internal static Matrix4x4 GetViewTransform(this IView view) { - var nativeView = view?.ToNative(); + var nativeView = view?.ToPlatform(); if (nativeView == null) return new Matrix4x4(); return nativeView.GetViewTransform(); @@ -347,7 +347,7 @@ internal static Matrix4x4 GetViewTransform(this EvasObject nativeView) => new Matrix4x4(); internal static Graphics.Rectangle GetBoundingBox(this IView view) - => view.ToNative().GetBoundingBox(); + => view.ToPlatform().GetBoundingBox(); internal static Graphics.Rectangle GetBoundingBox(this EvasObject? nativeView) { From 5fe11573c9f2f1afdd31c9be6abbd3100851fb29 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 4 Feb 2022 15:10:32 +0900 Subject: [PATCH 114/266] [Tizen] Remove legacy TFMs --- ._Microsoft.Maui.Tizen.sln | 827 ------------------ ...osoft.Maui.Controls.MultiTargeting.targets | 7 - 2 files changed, 834 deletions(-) delete mode 100644 ._Microsoft.Maui.Tizen.sln diff --git a/._Microsoft.Maui.Tizen.sln b/._Microsoft.Maui.Tizen.sln deleted file mode 100644 index 08e5ae6e3d5a..000000000000 --- a/._Microsoft.Maui.Tizen.sln +++ /dev/null @@ -1,827 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30503.244 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Controls", "Controls", "{9AD757F5-E57A-459D-A0A7-E0675E045B84}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compatibility", "Compatibility", "{29AC50BF-B4FB-450B-9386-0C5AD4B84226}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuspec", ".nuspec", "{7E12C50D-A570-4DF1-94E1-8599843FA87C}" - ProjectSection(SolutionItems) = preProject - eng\dogfood.ps1 = eng\dogfood.ps1 - .nuspec\Microsoft.Maui.Controls.Compatibility.AppLinks.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.AppLinks.nuspec - .nuspec\Microsoft.Maui.Controls.Compatibility.GTK.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.GTK.nuspec - .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.GTK.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.GTK.nuspec - .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.nuspec - .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.WPF.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.Maps.WPF.nuspec - .nuspec\Microsoft.Maui.Controls.Compatibility.Visual.Material.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.Visual.Material.nuspec - .nuspec\Microsoft.Maui.Controls.Compatibility.Visual.Material.targets = .nuspec\Microsoft.Maui.Controls.Compatibility.Visual.Material.targets - .nuspec\Microsoft.Maui.Controls.Compatibility.WPF.nuspec = .nuspec\Microsoft.Maui.Controls.Compatibility.WPF.nuspec - .nuspec\Microsoft.Maui.Controls.Debug.targets = .nuspec\Microsoft.Maui.Controls.Debug.targets - .nuspec\Microsoft.Maui.Controls.DefaultItems.props = .nuspec\Microsoft.Maui.Controls.DefaultItems.props - .nuspec\Microsoft.Maui.Controls.DefaultItems.targets = .nuspec\Microsoft.Maui.Controls.DefaultItems.targets - .nuspec\Microsoft.Maui.Controls.DualScreen.nuspec = .nuspec\Microsoft.Maui.Controls.DualScreen.nuspec - .nuspec\Microsoft.Maui.Controls.MultiTargeting.targets = .nuspec\Microsoft.Maui.Controls.MultiTargeting.targets - .nuspec\Microsoft.Maui.Controls.nuspec = .nuspec\Microsoft.Maui.Controls.nuspec - .nuspec\Microsoft.Maui.Controls.props = .nuspec\Microsoft.Maui.Controls.props - .nuspec\Microsoft.Maui.Controls.SingleProject.props = .nuspec\Microsoft.Maui.Controls.SingleProject.props - .nuspec\Microsoft.Maui.Controls.SingleProject.targets = .nuspec\Microsoft.Maui.Controls.SingleProject.targets - .nuspec\Microsoft.Maui.Controls.targets = .nuspec\Microsoft.Maui.Controls.targets - .nuspec\Microsoft.Maui.Resizetizer.targets = .nuspec\Microsoft.Maui.Resizetizer.targets - eng\package.ps1 = eng\package.ps1 - .nuspec\proguard.cfg = .nuspec\proguard.cfg - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Core", "src\Controls\src\Core\Controls.Core.csproj", "{57B8B73D-C3B5-4C42-869E-7B2F17D354AC}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{31721EFD-3238-462B-B501-41F3D2B50E92}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Controls", "Controls", "{97FA536A-675D-41C7-A90E-97E2F79D1AE2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{423C21C8-84CB-4A3C-BEB9-1C23D752D90F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\src\Core.csproj", "{29913989-0F70-48D8-8EDE-B1DD217F21D1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D5B986A3-7FC9-437E-8030-349AA4698DFD}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{75A2CD30-BB85-4CA6-AC95-86A8A538A690}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Core.UnitTests", "src\Controls\tests\Core.UnitTests\Controls.Core.UnitTests.csproj", "{00259593-A283-47A5-ACB7-9C3819B16364}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Xaml", "src\Controls\src\Xaml\Controls.Xaml.csproj", "{BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Build.Tasks", "src\Controls\src\Build.Tasks\Controls.Build.Tasks.csproj", "{C328C538-B69F-43D2-80EE-3C1EB8254CBA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.UnitTests", "src\Core\tests\UnitTests\Core.UnitTests.csproj", "{7A753001-1C3D-404D-A421-2E052A545EAC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.DeviceTests", "src\Core\tests\DeviceTests\Core.DeviceTests.csproj", "{DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Essentials", "Essentials", "{DFD73007-5DB1-43AD-87A8-BD8622C2B192}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7E12E071-51C0-4668-9FF3-E2DE9DC51962}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials", "src\Essentials\src\Essentials.csproj", "{8CB95D25-8442-42BC-82BE-319D21138549}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.UnitTests", "src\Essentials\test\UnitTests\Essentials.UnitTests.csproj", "{2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5817A848-0B04-4035-9F7E-B8621B61CBDD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.Samples", "src\Essentials\samples\Samples\Essentials.Sample.csproj", "{2C69EB76-02C4-4921-96A1-4D70CB7CE744}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Essentials.Sample.Server.WebAuthenticator", "src\Essentials\samples\Sample.Server.WebAuthenticator\Essentials.Sample.Server.WebAuthenticator.csproj", "{0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{806499EB-C2CC-4E85-BC19-613F3DE5E0C3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Sample", "src\Controls\samples\Controls.Sample\Controls.Sample.csproj", "{90B727DD-4C7B-4462-950F-61842A87DE8A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Maps", "src\Controls\Maps\src\Controls.Maps.csproj", "{F2379E0F-524F-47BC-877C-0428E4C836D4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Xaml.UnitTests", "src\Controls\tests\Xaml.UnitTests\Controls.Xaml.UnitTests.csproj", "{F905B72C-4DF7-408B-8B2B-50F9B8246A5E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestUtils", "TestUtils", "{0F9BA970-11B1-4ACA-AF41-1021AFC0F29C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils", "src\TestUtils\src\TestUtils\TestUtils.csproj", "{E4CB9988-7348-4D55-A08E-85907732F8DA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils.DeviceTests", "src\TestUtils\src\DeviceTests\TestUtils.DeviceTests.csproj", "{551B2209-4298-4D60-B55C-79077B8BC244}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Resizetizer", "Resizetizer", "{4A3BAF64-E9D9-4036-9FDA-8B326C382667}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F83AC93C-9694-4A01-B9CB-7AA8E514B01F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{08F720FF-7530-43BF-A252-8946927669E3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resizetizer", "src\SingleProject\Resizetizer\src\Resizetizer.csproj", "{3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Resizetizer.UnitTests", "src\SingleProject\Resizetizer\test\UnitTests\Resizetizer.UnitTests.csproj", "{BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SingleProject", "SingleProject", "{15878D2D-B0F1-4EE9-875D-4A643DB0C842}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.CustomAttributes", "src\Controls\tests\CustomAttributes\Controls.CustomAttributes.csproj", "{D816B818-F58F-4738-93AE-924EFAB7A07F}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Compatibility.ControlGallery.Issues.Shared", "src\Compatibility\ControlGallery\src\Issues.Shared\Compatibility.ControlGallery.Issues.Shared.shproj", "{AE2513CB-4E5E-4E5C-8237-88954D4C9433}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Compatibility.ControlGallery.Core", "src\Compatibility\ControlGallery\src\Core\Compatibility.ControlGallery.Core.csproj", "{B5F94CCB-5868-43BD-89B5-B66C97C3A741}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Compatibility", "src\Compatibility\Core\src\Compatibility.csproj", "{9FAA9654-80E6-4664-9702-47998A04E8FE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.SourceGen", "src\Controls\src\SourceGen\Controls.SourceGen.csproj", "{061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Sample.Tizen", "src\Controls\samples\Controls.Sample.Tizen\Controls.Sample.Tizen.csproj", "{4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}" -EndProject -Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - src\Compatibility\ControlGallery\src\Issues.Shared\Compatibility.ControlGallery.Issues.Shared.projitems*{ae2513cb-4e5e-4e5c-8237-88954d4c9433}*SharedItemsImports = 13 - src\Compatibility\ControlGallery\src\Issues.Shared\Compatibility.ControlGallery.Issues.Shared.projitems*{b5f94ccb-5868-43bd-89b5-b66c97c3a741}*SharedItemsImports = 5 - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|ARM64 = Debug|ARM64 - Debug|iPhone = Debug|iPhone - Debug|iPhoneSimulator = Debug|iPhoneSimulator - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|ARM64 = Release|ARM64 - Release|iPhone = Release|iPhone - Release|iPhoneSimulator = Release|iPhoneSimulator - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|ARM.ActiveCfg = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|ARM.Build.0 = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|ARM64.Build.0 = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|iPhone.Build.0 = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|x64.ActiveCfg = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|x64.Build.0 = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|x86.ActiveCfg = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|x86.Build.0 = Debug|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|Any CPU.Build.0 = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|ARM.ActiveCfg = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|ARM.Build.0 = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|ARM64.ActiveCfg = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|ARM64.Build.0 = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|iPhone.ActiveCfg = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|iPhone.Build.0 = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|x64.ActiveCfg = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|x64.Build.0 = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|x86.ActiveCfg = Release|Any CPU - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|x86.Build.0 = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|ARM.ActiveCfg = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|ARM.Build.0 = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|ARM64.Build.0 = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|iPhone.Build.0 = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|x64.ActiveCfg = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|x64.Build.0 = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|x86.ActiveCfg = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Debug|x86.Build.0 = Debug|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|Any CPU.Build.0 = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|ARM.ActiveCfg = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|ARM.Build.0 = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|ARM64.ActiveCfg = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|ARM64.Build.0 = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|iPhone.ActiveCfg = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|iPhone.Build.0 = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|x64.ActiveCfg = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|x64.Build.0 = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|x86.ActiveCfg = Release|Any CPU - {29913989-0F70-48D8-8EDE-B1DD217F21D1}.Release|x86.Build.0 = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|Any CPU.Build.0 = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|ARM.ActiveCfg = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|ARM.Build.0 = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|ARM64.Build.0 = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|iPhone.Build.0 = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|x64.ActiveCfg = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|x64.Build.0 = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|x86.ActiveCfg = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Debug|x86.Build.0 = Debug|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|Any CPU.ActiveCfg = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|Any CPU.Build.0 = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|ARM.ActiveCfg = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|ARM.Build.0 = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|ARM64.ActiveCfg = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|ARM64.Build.0 = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|iPhone.ActiveCfg = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|iPhone.Build.0 = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|x64.ActiveCfg = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|x64.Build.0 = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|x86.ActiveCfg = Release|Any CPU - {00259593-A283-47A5-ACB7-9C3819B16364}.Release|x86.Build.0 = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|ARM.ActiveCfg = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|ARM.Build.0 = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|ARM64.Build.0 = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|iPhone.Build.0 = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|x64.ActiveCfg = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|x64.Build.0 = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|x86.ActiveCfg = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Debug|x86.Build.0 = Debug|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|Any CPU.Build.0 = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|ARM.ActiveCfg = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|ARM.Build.0 = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|ARM64.ActiveCfg = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|ARM64.Build.0 = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|iPhone.ActiveCfg = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|iPhone.Build.0 = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|x64.ActiveCfg = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|x64.Build.0 = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|x86.ActiveCfg = Release|Any CPU - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27}.Release|x86.Build.0 = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|ARM.ActiveCfg = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|ARM.Build.0 = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|ARM64.Build.0 = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|iPhone.Build.0 = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|x64.ActiveCfg = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|x64.Build.0 = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|x86.ActiveCfg = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Debug|x86.Build.0 = Debug|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|Any CPU.Build.0 = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|ARM.ActiveCfg = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|ARM.Build.0 = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|ARM64.ActiveCfg = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|ARM64.Build.0 = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|iPhone.ActiveCfg = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|iPhone.Build.0 = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|x64.ActiveCfg = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|x64.Build.0 = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|x86.ActiveCfg = Release|Any CPU - {C328C538-B69F-43D2-80EE-3C1EB8254CBA}.Release|x86.Build.0 = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|ARM.ActiveCfg = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|ARM.Build.0 = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|ARM64.Build.0 = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|iPhone.Build.0 = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|x64.ActiveCfg = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|x64.Build.0 = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|x86.ActiveCfg = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Debug|x86.Build.0 = Debug|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|Any CPU.Build.0 = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|ARM.ActiveCfg = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|ARM.Build.0 = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|ARM64.ActiveCfg = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|ARM64.Build.0 = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|iPhone.ActiveCfg = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|iPhone.Build.0 = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|x64.ActiveCfg = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|x64.Build.0 = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|x86.ActiveCfg = Release|Any CPU - {7A753001-1C3D-404D-A421-2E052A545EAC}.Release|x86.Build.0 = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|ARM.ActiveCfg = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|ARM.Build.0 = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|ARM64.Build.0 = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|iPhone.Build.0 = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|x64.ActiveCfg = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|x64.Build.0 = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|x86.ActiveCfg = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Debug|x86.Build.0 = Debug|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|Any CPU.Build.0 = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|ARM.ActiveCfg = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|ARM.Build.0 = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|ARM64.ActiveCfg = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|ARM64.Build.0 = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|iPhone.ActiveCfg = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|iPhone.Build.0 = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|x64.ActiveCfg = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|x64.Build.0 = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|x86.ActiveCfg = Release|Any CPU - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6}.Release|x86.Build.0 = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|ARM.ActiveCfg = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|ARM.Build.0 = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|ARM64.Build.0 = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|iPhone.Build.0 = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|x64.ActiveCfg = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|x64.Build.0 = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|x86.ActiveCfg = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Debug|x86.Build.0 = Debug|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|Any CPU.Build.0 = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|ARM.ActiveCfg = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|ARM.Build.0 = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|ARM64.ActiveCfg = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|ARM64.Build.0 = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|iPhone.ActiveCfg = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|iPhone.Build.0 = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|x64.ActiveCfg = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|x64.Build.0 = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|x86.ActiveCfg = Release|Any CPU - {8CB95D25-8442-42BC-82BE-319D21138549}.Release|x86.Build.0 = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|ARM.ActiveCfg = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|ARM.Build.0 = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|ARM64.Build.0 = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|iPhone.Build.0 = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|x64.ActiveCfg = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|x64.Build.0 = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|x86.ActiveCfg = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Debug|x86.Build.0 = Debug|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|Any CPU.Build.0 = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|ARM.ActiveCfg = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|ARM.Build.0 = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|ARM64.ActiveCfg = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|ARM64.Build.0 = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|iPhone.ActiveCfg = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|iPhone.Build.0 = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x64.ActiveCfg = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x64.Build.0 = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x86.ActiveCfg = Release|Any CPU - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886}.Release|x86.Build.0 = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|ARM.ActiveCfg = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|ARM.Build.0 = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|ARM64.Build.0 = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|iPhone.Build.0 = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|x64.ActiveCfg = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|x64.Build.0 = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|x86.ActiveCfg = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Debug|x86.Build.0 = Debug|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|Any CPU.Build.0 = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|ARM.ActiveCfg = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|ARM.Build.0 = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|ARM64.ActiveCfg = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|ARM64.Build.0 = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|iPhone.ActiveCfg = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|iPhone.Build.0 = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|x64.ActiveCfg = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|x64.Build.0 = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|x86.ActiveCfg = Release|Any CPU - {2C69EB76-02C4-4921-96A1-4D70CB7CE744}.Release|x86.Build.0 = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|ARM.ActiveCfg = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|ARM.Build.0 = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|ARM64.Build.0 = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|iPhone.Build.0 = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|x64.ActiveCfg = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|x64.Build.0 = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|x86.ActiveCfg = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Debug|x86.Build.0 = Debug|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|Any CPU.Build.0 = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|ARM.ActiveCfg = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|ARM.Build.0 = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|ARM64.ActiveCfg = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|ARM64.Build.0 = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|iPhone.ActiveCfg = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|iPhone.Build.0 = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x64.ActiveCfg = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x64.Build.0 = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x86.ActiveCfg = Release|Any CPU - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C}.Release|x86.Build.0 = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|ARM.ActiveCfg = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|ARM.Build.0 = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|ARM64.Build.0 = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|iPhone.Build.0 = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|x64.ActiveCfg = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|x64.Build.0 = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|x86.ActiveCfg = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Debug|x86.Build.0 = Debug|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|Any CPU.Build.0 = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|ARM.ActiveCfg = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|ARM.Build.0 = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|ARM64.ActiveCfg = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|ARM64.Build.0 = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|iPhone.ActiveCfg = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|iPhone.Build.0 = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|x64.ActiveCfg = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|x64.Build.0 = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|x86.ActiveCfg = Release|Any CPU - {90B727DD-4C7B-4462-950F-61842A87DE8A}.Release|x86.Build.0 = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|ARM.ActiveCfg = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|ARM.Build.0 = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|ARM64.Build.0 = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|iPhone.Build.0 = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|x64.ActiveCfg = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|x64.Build.0 = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|x86.ActiveCfg = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Debug|x86.Build.0 = Debug|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|Any CPU.Build.0 = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|ARM.ActiveCfg = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|ARM.Build.0 = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|ARM64.ActiveCfg = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|ARM64.Build.0 = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|iPhone.ActiveCfg = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|iPhone.Build.0 = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|x64.ActiveCfg = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|x64.Build.0 = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|x86.ActiveCfg = Release|Any CPU - {F2379E0F-524F-47BC-877C-0428E4C836D4}.Release|x86.Build.0 = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|ARM.ActiveCfg = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|ARM.Build.0 = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|ARM64.Build.0 = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|iPhone.Build.0 = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|x64.ActiveCfg = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|x64.Build.0 = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|x86.ActiveCfg = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Debug|x86.Build.0 = Debug|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|Any CPU.Build.0 = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|ARM.ActiveCfg = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|ARM.Build.0 = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|ARM64.ActiveCfg = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|ARM64.Build.0 = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|iPhone.ActiveCfg = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|iPhone.Build.0 = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|x64.ActiveCfg = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|x64.Build.0 = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|x86.ActiveCfg = Release|Any CPU - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E}.Release|x86.Build.0 = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|ARM.ActiveCfg = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|ARM.Build.0 = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|ARM64.Build.0 = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|iPhone.Build.0 = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|x64.ActiveCfg = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|x64.Build.0 = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|x86.ActiveCfg = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Debug|x86.Build.0 = Debug|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|Any CPU.Build.0 = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|ARM.ActiveCfg = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|ARM.Build.0 = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|ARM64.ActiveCfg = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|ARM64.Build.0 = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|iPhone.ActiveCfg = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|iPhone.Build.0 = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|x64.ActiveCfg = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|x64.Build.0 = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|x86.ActiveCfg = Release|Any CPU - {E4CB9988-7348-4D55-A08E-85907732F8DA}.Release|x86.Build.0 = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|Any CPU.Build.0 = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|ARM.ActiveCfg = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|ARM.Build.0 = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|ARM64.Build.0 = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|iPhone.Build.0 = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|x64.ActiveCfg = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|x64.Build.0 = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|x86.ActiveCfg = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Debug|x86.Build.0 = Debug|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|Any CPU.ActiveCfg = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|Any CPU.Build.0 = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|ARM.ActiveCfg = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|ARM.Build.0 = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|ARM64.ActiveCfg = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|ARM64.Build.0 = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|iPhone.ActiveCfg = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|iPhone.Build.0 = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|x64.ActiveCfg = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|x64.Build.0 = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|x86.ActiveCfg = Release|Any CPU - {551B2209-4298-4D60-B55C-79077B8BC244}.Release|x86.Build.0 = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|ARM.ActiveCfg = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|ARM.Build.0 = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|ARM64.Build.0 = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|iPhone.Build.0 = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|x64.ActiveCfg = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|x64.Build.0 = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|x86.ActiveCfg = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Debug|x86.Build.0 = Debug|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|Any CPU.Build.0 = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|ARM.ActiveCfg = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|ARM.Build.0 = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|ARM64.ActiveCfg = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|ARM64.Build.0 = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|iPhone.ActiveCfg = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|iPhone.Build.0 = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|x64.ActiveCfg = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|x64.Build.0 = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|x86.ActiveCfg = Release|Any CPU - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C}.Release|x86.Build.0 = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|ARM.ActiveCfg = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|ARM.Build.0 = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|ARM64.Build.0 = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|iPhone.Build.0 = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|x64.ActiveCfg = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|x64.Build.0 = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|x86.ActiveCfg = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Debug|x86.Build.0 = Debug|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|Any CPU.Build.0 = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|ARM.ActiveCfg = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|ARM.Build.0 = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|ARM64.ActiveCfg = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|ARM64.Build.0 = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|iPhone.ActiveCfg = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|iPhone.Build.0 = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|x64.ActiveCfg = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|x64.Build.0 = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|x86.ActiveCfg = Release|Any CPU - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5}.Release|x86.Build.0 = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|ARM.ActiveCfg = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|ARM.Build.0 = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|ARM64.Build.0 = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|iPhone.Build.0 = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|x64.ActiveCfg = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|x64.Build.0 = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|x86.ActiveCfg = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Debug|x86.Build.0 = Debug|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|Any CPU.Build.0 = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|ARM.ActiveCfg = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|ARM.Build.0 = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|ARM64.ActiveCfg = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|ARM64.Build.0 = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|iPhone.ActiveCfg = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|iPhone.Build.0 = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|x64.ActiveCfg = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|x64.Build.0 = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|x86.ActiveCfg = Release|Any CPU - {D816B818-F58F-4738-93AE-924EFAB7A07F}.Release|x86.Build.0 = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|ARM.ActiveCfg = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|ARM.Build.0 = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|ARM64.Build.0 = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|iPhone.Build.0 = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|x64.ActiveCfg = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|x64.Build.0 = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|x86.ActiveCfg = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Debug|x86.Build.0 = Debug|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|Any CPU.Build.0 = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|ARM.ActiveCfg = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|ARM.Build.0 = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|ARM64.ActiveCfg = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|ARM64.Build.0 = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|iPhone.ActiveCfg = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|iPhone.Build.0 = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|x64.ActiveCfg = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|x64.Build.0 = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|x86.ActiveCfg = Release|Any CPU - {B5F94CCB-5868-43BD-89B5-B66C97C3A741}.Release|x86.Build.0 = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|ARM.ActiveCfg = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|ARM.Build.0 = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|ARM64.Build.0 = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|iPhone.Build.0 = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|x64.ActiveCfg = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|x64.Build.0 = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|x86.ActiveCfg = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Debug|x86.Build.0 = Debug|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|Any CPU.Build.0 = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|ARM.ActiveCfg = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|ARM.Build.0 = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|ARM64.ActiveCfg = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|ARM64.Build.0 = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|iPhone.ActiveCfg = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|iPhone.Build.0 = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|x64.ActiveCfg = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|x64.Build.0 = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|x86.ActiveCfg = Release|Any CPU - {9FAA9654-80E6-4664-9702-47998A04E8FE}.Release|x86.Build.0 = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|ARM.ActiveCfg = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|ARM.Build.0 = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|ARM64.Build.0 = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|iPhone.Build.0 = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|x64.ActiveCfg = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|x64.Build.0 = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|x86.ActiveCfg = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Debug|x86.Build.0 = Debug|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|Any CPU.Build.0 = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|ARM.ActiveCfg = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|ARM.Build.0 = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|ARM64.ActiveCfg = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|ARM64.Build.0 = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|iPhone.ActiveCfg = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|iPhone.Build.0 = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|x64.ActiveCfg = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|x64.Build.0 = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|x86.ActiveCfg = Release|Any CPU - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD}.Release|x86.Build.0 = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|ARM.ActiveCfg = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|ARM.Build.0 = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|ARM64.Build.0 = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|iPhone.Build.0 = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|x64.ActiveCfg = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|x64.Build.0 = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|x86.ActiveCfg = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Debug|x86.Build.0 = Debug|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|Any CPU.Build.0 = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|ARM.ActiveCfg = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|ARM.Build.0 = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|ARM64.ActiveCfg = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|ARM64.Build.0 = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|iPhone.ActiveCfg = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|iPhone.Build.0 = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x64.ActiveCfg = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x64.Build.0 = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x86.ActiveCfg = Release|Any CPU - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {9AD757F5-E57A-459D-A0A7-E0675E045B84} = {97FA536A-675D-41C7-A90E-97E2F79D1AE2} - {29AC50BF-B4FB-450B-9386-0C5AD4B84226} = {97FA536A-675D-41C7-A90E-97E2F79D1AE2} - {57B8B73D-C3B5-4C42-869E-7B2F17D354AC} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} - {423C21C8-84CB-4A3C-BEB9-1C23D752D90F} = {31721EFD-3238-462B-B501-41F3D2B50E92} - {2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA} = {31721EFD-3238-462B-B501-41F3D2B50E92} - {29913989-0F70-48D8-8EDE-B1DD217F21D1} = {423C21C8-84CB-4A3C-BEB9-1C23D752D90F} - {D5B986A3-7FC9-437E-8030-349AA4698DFD} = {9AD757F5-E57A-459D-A0A7-E0675E045B84} - {75A2CD30-BB85-4CA6-AC95-86A8A538A690} = {9AD757F5-E57A-459D-A0A7-E0675E045B84} - {00259593-A283-47A5-ACB7-9C3819B16364} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} - {BB98A559-62C4-4C98-90A0-9E4D8DF1CA27} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} - {C328C538-B69F-43D2-80EE-3C1EB8254CBA} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} - {7A753001-1C3D-404D-A421-2E052A545EAC} = {2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA} - {DA9E4D76-8CA4-4CC3-A47C-BA75DFF805C6} = {2ACC7FFA-238F-44FD-93CB-4D9B17D8C4BA} - {7E12E071-51C0-4668-9FF3-E2DE9DC51962} = {DFD73007-5DB1-43AD-87A8-BD8622C2B192} - {8CB95D25-8442-42BC-82BE-319D21138549} = {7E12E071-51C0-4668-9FF3-E2DE9DC51962} - {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} = {DFD73007-5DB1-43AD-87A8-BD8622C2B192} - {2E0EB4A3-3C4A-4A5E-8D2F-F77C62464886} = {99FDF6CA-DCF8-4CB2-B2EA-E24CCB601232} - {5817A848-0B04-4035-9F7E-B8621B61CBDD} = {DFD73007-5DB1-43AD-87A8-BD8622C2B192} - {2C69EB76-02C4-4921-96A1-4D70CB7CE744} = {5817A848-0B04-4035-9F7E-B8621B61CBDD} - {0C1B038F-F5CD-4E3C-B9D7-040F020BA44C} = {5817A848-0B04-4035-9F7E-B8621B61CBDD} - {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} = {9AD757F5-E57A-459D-A0A7-E0675E045B84} - {90B727DD-4C7B-4462-950F-61842A87DE8A} = {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} - {F2379E0F-524F-47BC-877C-0428E4C836D4} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} - {F905B72C-4DF7-408B-8B2B-50F9B8246A5E} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} - {E4CB9988-7348-4D55-A08E-85907732F8DA} = {0F9BA970-11B1-4ACA-AF41-1021AFC0F29C} - {551B2209-4298-4D60-B55C-79077B8BC244} = {0F9BA970-11B1-4ACA-AF41-1021AFC0F29C} - {4A3BAF64-E9D9-4036-9FDA-8B326C382667} = {15878D2D-B0F1-4EE9-875D-4A643DB0C842} - {F83AC93C-9694-4A01-B9CB-7AA8E514B01F} = {4A3BAF64-E9D9-4036-9FDA-8B326C382667} - {08F720FF-7530-43BF-A252-8946927669E3} = {4A3BAF64-E9D9-4036-9FDA-8B326C382667} - {3E1D0DED-6B13-42C8-AA15-2EDFD8ECE80C} = {08F720FF-7530-43BF-A252-8946927669E3} - {BDFA84D6-6C6B-44C9-ABC5-563CFD0C4DB5} = {F83AC93C-9694-4A01-B9CB-7AA8E514B01F} - {D816B818-F58F-4738-93AE-924EFAB7A07F} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} - {AE2513CB-4E5E-4E5C-8237-88954D4C9433} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} - {B5F94CCB-5868-43BD-89B5-B66C97C3A741} = {75A2CD30-BB85-4CA6-AC95-86A8A538A690} - {9FAA9654-80E6-4664-9702-47998A04E8FE} = {29AC50BF-B4FB-450B-9386-0C5AD4B84226} - {061EC251-FB7A-43B2-A6AD-065D2CCEF1BD} = {D5B986A3-7FC9-437E-8030-349AA4698DFD} - {4D5FF3BF-5C21-4DE9-B752-2F92BCB2F7A6} = {806499EB-C2CC-4E85-BC19-613F3DE5E0C3} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {650AE971-2F29-46A8-822C-FB4FCDC6A9A0} - EndGlobalSection -EndGlobal diff --git a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets index cecf6d5cd201..bfa81e0fadab 100644 --- a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets +++ b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets @@ -29,14 +29,7 @@ - - - - - - - From fca50e7504e83b84f1eb6459647f735656a3a330 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 8 Feb 2022 11:27:41 +0900 Subject: [PATCH 115/266] [Tizen] Remove `IPlatformInvalidate` and `Device.Invalidate() --- .../Core/src/Tizen/PlatformInvalidate.cs | 20 +++++++++++++++++++ src/Core/src/Platform/Tizen/ViewExtensions.cs | 5 +++++ 2 files changed, 25 insertions(+) create mode 100644 src/Compatibility/Core/src/Tizen/PlatformInvalidate.cs diff --git a/src/Compatibility/Core/src/Tizen/PlatformInvalidate.cs b/src/Compatibility/Core/src/Tizen/PlatformInvalidate.cs new file mode 100644 index 000000000000..6ac1a8dedcd2 --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/PlatformInvalidate.cs @@ -0,0 +1,20 @@ +using Microsoft.Maui.Controls.Internals; + +[assembly: Microsoft.Maui.Controls.Dependency(typeof(Microsoft.Maui.Controls.Compatibility.Platform.Tizen.PlatformInvalidate))] + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + class PlatformInvalidate : IPlatformInvalidate + { + public void Invalidate(VisualElement visualElement) + { + var renderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Platform.GetRenderer(visualElement); + if (renderer == null || !renderer.NativeView.IsRealized) + { + return; + } + + renderer.NativeView.MarkChanged(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ViewExtensions.cs b/src/Core/src/Platform/Tizen/ViewExtensions.cs index 6e882fdeb35e..e79acaf888e8 100644 --- a/src/Core/src/Platform/Tizen/ViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/ViewExtensions.cs @@ -356,5 +356,10 @@ internal static Graphics.Rectangle GetBoundingBox(this EvasObject? nativeView) return nativeView.Geometry.ToDP(); } + + internal static EvasObject? GetParent(this EvasObject? view) + { + return view?.Parent; + } } } From b976b89589082b74b06e552ca7b8e2f955a24deb Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 10 Feb 2022 20:25:22 +0900 Subject: [PATCH 116/266] [Tizen] Fix Essential sample build error --- src/Essentials/samples/Samples/Startup.cs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Essentials/samples/Samples/Startup.cs b/src/Essentials/samples/Samples/Startup.cs index 539c469ddc68..ad47411ef175 100644 --- a/src/Essentials/samples/Samples/Startup.cs +++ b/src/Essentials/samples/Samples/Startup.cs @@ -31,20 +31,19 @@ public static MauiApp CreateMauiApp() }); #if TIZEN - builder - .ConfigureServices(services => + var services = builder.Services; + + services + .AddTransient((_) => { - services.AddTransient((_) => + var option = new InitializationOptions { - var option = new InitializationOptions - { - DisplayResolutionUnit = DisplayResolutionUnit.DP(true), - }; - return option; - }); -#endif + DisplayResolutionUnit = DisplayResolutionUnit.DP(true), + UseSkiaSharp = true + }; + return option; }); - +#endif return builder.Build(); } } From c72411ca10ceb4d39f1f493e0c0bf233927dc300 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 21 Feb 2022 15:12:57 +0900 Subject: [PATCH 117/266] [Tizen] Refactor Essential's implementations --- src/Essentials/src/Battery/Battery.tizen.cs | 2 +- src/Essentials/src/TextToSpeech/TextToSpeech.tizen.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Essentials/src/Battery/Battery.tizen.cs b/src/Essentials/src/Battery/Battery.tizen.cs index 6aee8be5fa0e..e430d087ed4f 100755 --- a/src/Essentials/src/Battery/Battery.tizen.cs +++ b/src/Essentials/src/Battery/Battery.tizen.cs @@ -7,7 +7,7 @@ namespace Microsoft.Maui.Devices partial class BatteryImplementation : IBattery { void OnChanged(object sender, object e) - => MainThread.BeginInvokeOnMainThread(OnBatteryInfoChanged); + => MainThread.BeginInvokeOnMainThread(Battery.OnBatteryInfoChanged); void StartBatteryListeners() { diff --git a/src/Essentials/src/TextToSpeech/TextToSpeech.tizen.cs b/src/Essentials/src/TextToSpeech/TextToSpeech.tizen.cs index f90bd7bc649f..899cbd1b13d2 100644 --- a/src/Essentials/src/TextToSpeech/TextToSpeech.tizen.cs +++ b/src/Essentials/src/TextToSpeech/TextToSpeech.tizen.cs @@ -43,7 +43,7 @@ async Task PlatformSpeakAsync(string text, SpeechOptions options, CancellationTo var pitch = 0; if (options?.Pitch.HasValue ?? false) - pitch = (int)Math.Round(options.Pitch.Value / PitchMax * tts.GetSpeedRange().Max, MidpointRounding.AwayFromZero); + pitch = (int)Math.Round(options.Pitch.Value / TextToSpeech.PitchMax * tts.GetSpeedRange().Max, MidpointRounding.AwayFromZero); tts.AddText(text, language, (int)voiceType, pitch); tts.Play(); From ec7eeddca1b2567659fddcd6c468c866cfaaa33e Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 21 Feb 2022 15:26:57 +0900 Subject: [PATCH 118/266] [Tizen] Renaming public APIs Native -> Platform --- .../src/Tizen/Extensions/ColorExtensions.cs | 2 +- .../TabbedPage/TabbedPageHandler.Tizen.cs | 2 +- .../Tizen/Extensions/ShellExtensions.cs | 2 +- src/Core/src/Animations/NativeTicker.Tizen.cs | 42 ------------------- .../src/Graphics/PaintExtensions.Tizen.cs | 8 ++-- .../Application/ApplicationHandler.Tizen.cs | 2 +- .../CheckBox/CheckBoxHandler.Tizen.cs | 2 +- .../Handlers/Editor/EditorHandler.Tizen.cs | 20 ++++----- .../src/Handlers/Entry/EntryHandler.Tizen.cs | 22 +++++----- .../GraphicsView/GraphicsViewHandler.Tizen.cs | 4 +- .../Handlers/Layout/LayoutHandler.Tizen.cs | 20 ++++----- .../src/Handlers/Page/PageHandler.Tizen.cs | 8 ++-- .../ProgressBar/ProgressBarHandler.Tizen.cs | 2 +- .../RadioButton/RadioButtonHandler.Tizen.cs | 9 ++++ .../SearchBar/SearchBarHandler.Tizen.cs | 2 +- .../SwipeItemMenuItemHandler.Tizen.cs | 2 +- .../SwipeView/SwipeItemViewHandler.Tizen.cs | 22 +++++----- .../src/Handlers/View/ViewHandler.Tizen.cs | 18 ++++---- .../src/Platform/Tizen/CheckBoxExtensions.cs | 4 +- .../src/Platform/Tizen/EntryExtensions.cs | 22 +++++----- src/Core/src/Platform/Tizen/LayoutCanvas.cs | 12 +++--- .../src/Platform/Tizen/MauiApplication.cs | 6 +-- ...ensions.cs => PlatformWindowExtensions.cs} | 0 .../Platform/Tizen/ProgressBarExtensions.cs | 4 +- src/Core/src/Platform/Tizen/ViewExtensions.cs | 28 ++++++------- 25 files changed, 116 insertions(+), 149 deletions(-) delete mode 100644 src/Core/src/Animations/NativeTicker.Tizen.cs rename src/Core/src/Platform/Tizen/{WindowExtensions.cs => PlatformWindowExtensions.cs} (100%) diff --git a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs index 472f073f47e4..0f86966258f1 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs @@ -10,7 +10,7 @@ public static class ColorExtensions /// /// ElmSharp.Color instance representing a color which corresponds to the provided Microsoft.Maui.Controls.Compatibility.Color /// The Microsoft.Maui.Controls.Compatibility.Color instance which will be converted to a ElmSharp.Color - public static EColor ToPlatform(this Color c) + public static EColor ToNative(this Color c) { if (c == null) { diff --git a/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs b/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs index 673b5c6200c4..8a577f73bc7a 100644 --- a/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs +++ b/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs @@ -8,7 +8,7 @@ namespace Microsoft.Maui.Controls.Handlers { public partial class TabbedPageHandler : ViewHandler { - protected override EvasObject CreateNativeView() + protected override EvasObject CreatePlatformView() { // TODO : Need to impl throw new NotImplementedException(); diff --git a/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs index 134b7962375d..fc30d0f8f202 100644 --- a/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs @@ -4,7 +4,7 @@ namespace Microsoft.Maui.Controls.Platform { public static class ShellExtensions { - public static DrawerBehavior ToNative(this FlyoutBehavior behavior) + public static DrawerBehavior ToPlatform(this FlyoutBehavior behavior) { if (behavior == FlyoutBehavior.Disabled) return DrawerBehavior.Disabled; diff --git a/src/Core/src/Animations/NativeTicker.Tizen.cs b/src/Core/src/Animations/NativeTicker.Tizen.cs deleted file mode 100644 index 2cba99d1f71c..000000000000 --- a/src/Core/src/Animations/NativeTicker.Tizen.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Threading; -using Tizen.Applications; - -namespace Microsoft.Maui.Animations -{ - public class NativeTicker : Ticker - { - readonly Timer _timer; - readonly SynchronizationContext? _context; - bool _isRunning; - - public override bool IsRunning => _isRunning; - - public NativeTicker() - { - if (SynchronizationContext.Current == null) - { - TizenSynchronizationContext.Initialize(); - } - - _context = SynchronizationContext.Current; - _timer = new Timer((object? o) => HandleElapsed(o), this, Timeout.Infinite, Timeout.Infinite); - } - - public override void Start() - { - _timer.Change(16, 16); - _isRunning = true; - } - - public override void Stop() - { - _timer.Change(-1, -1); - _isRunning = false; - } - - void HandleElapsed(object? state) - { - _context?.Post((o) => Fire?.Invoke(), null); - } - } -} \ No newline at end of file diff --git a/src/Core/src/Graphics/PaintExtensions.Tizen.cs b/src/Core/src/Graphics/PaintExtensions.Tizen.cs index 452db3e1e3c0..01b7453a18de 100644 --- a/src/Core/src/Graphics/PaintExtensions.Tizen.cs +++ b/src/Core/src/Graphics/PaintExtensions.Tizen.cs @@ -5,16 +5,16 @@ namespace Microsoft.Maui.Graphics { public static partial class PaintExtensions { - public static EColor ToNativeEFL(this Paint paint) + public static EColor ToPlatformEFL(this Paint paint) { var color = paint.ToColor(); - return color != null ? color.ToNativeEFL() : EColor.Default; + return color != null ? color.ToPlatformEFL() : EColor.Default; } - public static TColor ToNative(this Paint paint) + public static TColor ToPlatform(this Paint paint) { var color = paint.ToColor(); - return color != null ? color.ToNative() : TColor.Default; + return color != null ? color.ToPlatform() : TColor.Default; } public static MauiDrawable? ToDrawable(this Paint paint) diff --git a/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs b/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs index fb17eb324757..418453ebf5cf 100644 --- a/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs +++ b/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs @@ -24,7 +24,7 @@ public static void MapCloseWindow(ApplicationHandler handler, IApplication appli public static void MapOpenWindow(ApplicationHandler handler, IApplication application, object? args) { - handler.NativeView?.RequestNewWindow(application, args as OpenWindowRequest); + handler.PlatformView?.RequestNewWindow(application, args as OpenWindowRequest); } public static void MapCloseWindow(ApplicationHandler handler, IApplication application, object? args) diff --git a/src/Core/src/Handlers/CheckBox/CheckBoxHandler.Tizen.cs b/src/Core/src/Handlers/CheckBox/CheckBoxHandler.Tizen.cs index 490971f929a9..4718a4a313a3 100644 --- a/src/Core/src/Handlers/CheckBox/CheckBoxHandler.Tizen.cs +++ b/src/Core/src/Handlers/CheckBox/CheckBoxHandler.Tizen.cs @@ -31,7 +31,7 @@ public static void MapForeground(ICheckBoxHandler handler, ICheckBox check) public static void MapForeground(CheckBoxHandler handler, ICheckBox check) { - handler.NativeView?.UpdateForeground(check); + handler.PlatformView?.UpdateForeground(check); } void OnStateChanged(object? sender, EventArgs e) diff --git a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs index 1de6837a3c9b..a30a0da50a94 100644 --- a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs +++ b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs @@ -113,29 +113,29 @@ public static void MapSelectionLength(IEditorHandler handler, ITextInput editor) handler.PlatformView?.UpdateSelectionLength(editor); } - public static void MapKeyboard(EditorHandler handler, IEditor editor) + public static void MapKeyboard(IEditorHandler handler, IEditor editor) { - handler.NativeView?.UpdateKeyboard(editor); + handler.PlatformView?.UpdateKeyboard(editor); } - public static void MapHorizontalTextAlignment(EditorHandler handler, IEditor editor) + public static void MapHorizontalTextAlignment(IEditorHandler handler, IEditor editor) { - handler.NativeView?.UpdateHorizontalTextAlignment(editor); + handler.PlatformView?.UpdateHorizontalTextAlignment(editor); } - public static void MapVerticalTextAlignment(EditorHandler handler, IEditor editor) + public static void MapVerticalTextAlignment(IEditorHandler handler, IEditor editor) { - handler.NativeView?.UpdateVerticalTextAlignment(editor); + handler.PlatformView?.UpdateVerticalTextAlignment(editor); } - public static void MapCursorPosition(EditorHandler handler, ITextInput editor) + public static void MapCursorPosition(IEditorHandler handler, ITextInput editor) { - handler.NativeView?.UpdateSelectionLength(editor); + handler.PlatformView?.UpdateSelectionLength(editor); } - public static void MapSelectionLength(EditorHandler handler, ITextInput editor) + public static void MapSelectionLength(IEditorHandler handler, ITextInput editor) { - handler.NativeView?.UpdateSelectionLength(editor); + handler.PlatformView?.UpdateSelectionLength(editor); } [MissingMapper] diff --git a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs index ee540d37bb09..4a96affd2ad5 100644 --- a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs +++ b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs @@ -156,19 +156,19 @@ public static void MapKeyboard(EditorHandler handler, IEntry entry) handler.PlatformView?.UpdateKeyboard(entry); } - public static void MapSelectionLength(EntryHandler handler, IEntry entry) + public static void MapSelectionLength(IEntryHandler handler, IEntry entry) { - handler.NativeView?.UpdateSelectionLength(entry); + handler.PlatformView?.UpdateSelectionLength(entry); } - public static void MapCursorPosition(EntryHandler handler, IEntry entry) + public static void MapCursorPosition(IEntryHandler handler, IEntry entry) { - handler.NativeView?.UpdateSelectionLength(entry); + handler.PlatformView?.UpdateSelectionLength(entry); } public static void MapKeyboard(EditorHandler handler, IEntry entry) { - handler.NativeView?.UpdateKeyboard(entry); + handler.PlatformView?.UpdateKeyboard(entry); } [MissingMapper] @@ -226,12 +226,12 @@ void OnSelectionCleared(object? sender, EventArgs e) void OnCursorChanged(object? sender, EventArgs e) { - if (VirtualView == null || NativeView == null) + if (VirtualView == null || PlatformView == null) return; - var position = NativeView.CursorPosition; + var position = PlatformView.CursorPosition; - NativeView.GetSelectRegion(out int start, out int end); + PlatformView.GetSelectRegion(out int start, out int end); if (start > -1) { @@ -245,13 +245,13 @@ void OnCursorChanged(object? sender, EventArgs e) void OnSelectionCleared(object? sender, EventArgs e) { - if (VirtualView == null || NativeView == null) + if (VirtualView == null || PlatformView == null) return; - if (NativeView.IsFocused) + if (PlatformView.IsFocused) { VirtualView.SelectionLength = 0; - VirtualView.CursorPosition = NativeView.CursorPosition; + VirtualView.CursorPosition = PlatformView.CursorPosition; } } diff --git a/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs index d611c0ec19d9..3c4c9eaec130 100644 --- a/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs @@ -22,9 +22,9 @@ public static void MapInvalidate(IGraphicsViewHandler handler, IGraphicsView gra handler.PlatformView?.Invalidate(); } - public static void MapInvalidate(GraphicsViewHandler handler, IGraphicsView graphicsView, object? arg) + public static void MapInvalidate(IGraphicsViewHandler handler, IGraphicsView graphicsView, object? arg) { - handler.NativeView?.Invalidate(); + handler.PlatformView?.Invalidate(); } } } \ No newline at end of file diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs index d95ab08bbd54..3692c49927ef 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs @@ -174,13 +174,13 @@ public void Update(int index, IView child) _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); - var toBeRemoved = NativeView.Children[index]; - NativeView.Children.RemoveAt(index); + var toBeRemoved = PlatformView.Children[index]; + PlatformView.Children.RemoveAt(index); toBeRemoved.Unrealize(); var targetIndex = VirtualView.GetLayoutHandlerIndex(child); - NativeView.Children.Insert(targetIndex, child.ToPlatform(MauiContext)); - if (child.Handler is INativeViewHandler childHandler) + PlatformView.Children.Insert(targetIndex, child.ToPlatform(MauiContext)); + if (child.Handler is IPlatformViewHandler childHandler) { childHandler?.SetParent(this); } @@ -188,7 +188,7 @@ public void Update(int index, IView child) public void UpdateZIndex(IView child) { - _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); + _ = PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class."); _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); @@ -197,13 +197,13 @@ public void UpdateZIndex(IView child) void EnsureZIndexOrder(IView child) { - if (NativeView.Children.Count == 0) + if (PlatformView.Children.Count == 0) { return; } var nativeChildView = child.ToPlatform(MauiContext!); - var currentIndex = NativeView.Children.IndexOf(nativeChildView); + var currentIndex = PlatformView.Children.IndexOf(nativeChildView); if (currentIndex == -1) { @@ -214,9 +214,9 @@ void EnsureZIndexOrder(IView child) if (targetIndex > currentIndex) { child.ToPlatform(MauiContext!).RaiseTop(); - for (int i = targetIndex+1; i < NativeView.Children.Count; i++) + for (int i = targetIndex+1; i < PlatformView.Children.Count; i++) { - NativeView.Children[i].RaiseTop(); + PlatformView.Children[i].RaiseTop(); } } else @@ -224,7 +224,7 @@ void EnsureZIndexOrder(IView child) child.ToPlatform(MauiContext!).Lower(); for (int i = targetIndex-1; i >= 0; i--) { - NativeView.Children[i].Lower(); + PlatformView.Children[i].Lower(); } } } diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index 3eeb114a0a30..5e96c123a1e5 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -29,9 +29,9 @@ protected override ContentCanvas CreatePlatformView() public override void NativeArrange(Graphics.Rectangle frame) { handler.UpdateValue(nameof(handler.ContainerView)); - if (page.Background != null && handler.NativeView.BackgroundColor != EColor.Transparent) + if (page.Background != null && handler.PlatformView.BackgroundColor != EColor.Transparent) { - handler.NativeView.BackgroundColor = EColor.Transparent; + handler.PlatformView.BackgroundColor = EColor.Transparent; } handler.ToPlatform()?.UpdateBackground(page); } @@ -39,9 +39,9 @@ public override void NativeArrange(Graphics.Rectangle frame) [MissingMapper] public static void MapTitle(PageHandler handler, IContentView page) { } - protected override ContentCanvas CreateNativeView() + protected override ContentCanvas CreatePlatformView() { - var view = base.CreateNativeView(); + var view = base.CreatePlatformView(); view.BackgroundColor = (DeviceInfo.GetDeviceType() == DeviceType.TV) ? EColor.Transparent : EColor.White; return view; diff --git a/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs b/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs index 79e4a795cef1..ac5c69dd5786 100644 --- a/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs +++ b/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs @@ -32,7 +32,7 @@ public static void MapProgressColor(ProgressBarHandler handler, IProgress progre public static void MapProgressColor(ProgressBarHandler handler, IProgress progress) { - handler.NativeView?.UpdateProgressColor(progress); + handler.PlatformView?.UpdateProgressColor(progress); } } } \ No newline at end of file diff --git a/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs index 4827d5ead2ad..ac7e28fabbb7 100644 --- a/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs +++ b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs @@ -53,6 +53,15 @@ public static void MapStrokeThickness(IRadioButtonHandler handler, IRadioButton [MissingMapper] public static void MapCornerRadius(IRadioButtonHandler handler, IRadioButton radioButton) { } + [MissingMapper] + public static void MapStrokeColor(RadioButtonHandler handler, IRadioButton radioButton) { } + + [MissingMapper] + public static void MapStrokeThickness(RadioButtonHandler handler, IRadioButton radioButton) { } + + [MissingMapper] + public static void MapCornerRadius(RadioButtonHandler handler, IRadioButton radioButton) { } + void OnValueChanged(object? sender, EventArgs e) { VirtualView.IsChecked = PlatformView.GroupValue == 1 ? true : false; diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs index 514e50d84a36..4a0827c889b1 100644 --- a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs @@ -122,7 +122,7 @@ public static void MapCancelButtonColor(ISearchBarHandler handler, ISearchBar se public static void MapCancelButtonColor(SearchBarHandler handler, ISearchBar searchBar) { - handler.NativeView?.UpdateCancelButtonColor(searchBar); + handler.PlatformView?.UpdateCancelButtonColor(searchBar); } [MissingMapper] diff --git a/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs b/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs index e87ad23e1b9e..b2e6f29adb2d 100644 --- a/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs +++ b/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs @@ -8,7 +8,7 @@ namespace Microsoft.Maui.Handlers //TODO : Need to implement public partial class SwipeItemMenuItemHandler : ElementHandler { - protected override EvasObject CreateNativeElement() + protected override EvasObject CreatePlatformElement() { throw new NotImplementedException(); } diff --git a/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs b/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs index 2101be435e69..a4e89a37bf6d 100644 --- a/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs @@ -5,7 +5,7 @@ namespace Microsoft.Maui.Handlers { public class SwipeItemViewHandler : ViewHandler { - INativeViewHandler? _contentHandler; + IPlatformViewHandler? _contentHandler; public static IPropertyMapper Mapper = new PropertyMapper(ViewHandler.ViewMapper) { @@ -32,7 +32,7 @@ public SwipeItemViewHandler(IPropertyMapper? mapper = null) : base(mapper ?? Map } - protected override ContentCanvas CreateNativeView() + protected override ContentCanvas CreatePlatformView() { _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} must be set to create a Page"); _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} cannot be null"); @@ -51,27 +51,27 @@ public override void SetVirtualView(IView view) { base.SetVirtualView(view); _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); - _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); + _ = PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class."); - NativeView.CrossPlatformMeasure = VirtualView.CrossPlatformMeasure; - NativeView.CrossPlatformArrange = VirtualView.CrossPlatformArrange; + PlatformView.CrossPlatformMeasure = VirtualView.CrossPlatformMeasure; + PlatformView.CrossPlatformArrange = VirtualView.CrossPlatformArrange; } void UpdateContent() { - _ = NativeView ?? throw new InvalidOperationException($"{nameof(NativeView)} should have been set by base class."); + _ = PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class."); _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); // Cleanup the old view when reused - NativeView.Children.Clear(); + PlatformView.Children.Clear(); _contentHandler?.Dispose(); _contentHandler = null; if (VirtualView.PresentedContent is IView view) { - NativeView.Children.Add(view.ToPlatform(MauiContext)); - if (view.Handler is INativeViewHandler thandler) + PlatformView.Children.Add(view.ToPlatform(MauiContext)); + if (view.Handler is IPlatformViewHandler thandler) { thandler?.SetParent(this); _contentHandler = thandler; @@ -87,11 +87,11 @@ public static void MapContent(SwipeItemViewHandler handler, ISwipeItemView page) public static void MapVisibility(SwipeItemViewHandler handler, ISwipeItemView view) { //TODO : need to update - //var swipeView = handler.NativeView.GetParentOfType(); + //var swipeView = handler.PlatformView.GetParentOfType(); //if (swipeView != null) // swipeView.UpdateIsVisibleSwipeItem(view); - //handler.NativeView.UpdateVisibility(view.Visibility); + //handler.PlatformView.UpdateVisibility(view.Visibility); } } } diff --git a/src/Core/src/Handlers/View/ViewHandler.Tizen.cs b/src/Core/src/Handlers/View/ViewHandler.Tizen.cs index 3c49493d2c64..9dca5efc2fca 100644 --- a/src/Core/src/Handlers/View/ViewHandler.Tizen.cs +++ b/src/Core/src/Handlers/View/ViewHandler.Tizen.cs @@ -151,32 +151,32 @@ protected void OnUnfocused(object? sender, EventArgs e) OnUnfocused(); } - partial void ConnectingHandler(NativeView? nativeView) + partial void ConnectingHandler(PlatformView? platformView) { - if (nativeView == null) + if (platformView == null) return; - nativeView.Deleted += OnNativeViewDeleted; + platformView.Deleted += OnPlatformViewDeleted; - if (nativeView is Widget widget) + if (platformView is Widget widget) { widget.Focused += OnFocused; widget.Unfocused += OnUnfocused; } } - partial void DisconnectingHandler(NativeView nativeView) + partial void DisconnectingHandler(PlatformView platformView) { - if (nativeView == null) + if (platformView == null) return; - nativeView.Deleted -= OnNativeViewDeleted; + platformView.Deleted -= OnPlatformViewDeleted; } - void OnNativeViewDeleted(object? sender, EventArgs e) + void OnPlatformViewDeleted(object? sender, EventArgs e) { - OnNativeViewDeleted(); + OnPlatformViewDeleted(); } } } diff --git a/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs b/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs index 56be0cdf7d6e..3a139dd769fc 100644 --- a/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs +++ b/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs @@ -19,12 +19,12 @@ public static void UpdateForeground(this Check platformCheck, ICheckBox check) } } - public static void UpdateForeground(this Check nativeCheck, ICheckBox check) + public static void UpdateForeground(this Check platformCheck, ICheckBox check) { // For the moment, we're only supporting solid color Paint if (check.Foreground is SolidPaint solid) { - nativeCheck.Color = solid.Color.ToNativeEFL(); + platformCheck.Color = solid.Color.ToPlatformEFL(); } } } diff --git a/src/Core/src/Platform/Tizen/EntryExtensions.cs b/src/Core/src/Platform/Tizen/EntryExtensions.cs index 48a1f22ca88c..4817c6f559ef 100644 --- a/src/Core/src/Platform/Tizen/EntryExtensions.cs +++ b/src/Core/src/Platform/Tizen/EntryExtensions.cs @@ -143,30 +143,30 @@ static int GetSelectionEnd(Entry platformEntry, ITextInput entry, int start) /* Updates both the IEntry.CursorPosition and IEntry.SelectionLength properties. */ [PortHandler] - public static void UpdateSelectionLength(this Entry nativeEntry, ITextInput entry) + public static void UpdateSelectionLength(this Entry platformEntry, ITextInput entry) { - if (nativeEntry.IsUpdatingCursorPosition) + if (platformEntry.IsUpdatingCursorPosition) return; - int start = GetSelectionStart(nativeEntry, entry); - int end = GetSelectionEnd(nativeEntry, entry, start); + int start = GetSelectionStart(platformEntry, entry); + int end = GetSelectionEnd(platformEntry, entry, start); if (start < end) { - nativeEntry.SetSelectionRegion(start, end); + platformEntry.SetSelectionRegion(start, end); } else { - nativeEntry.CursorPosition = entry.CursorPosition; + platformEntry.CursorPosition = entry.CursorPosition; } } - static int GetSelectionStart(Entry nativeEntry, ITextInput entry) + static int GetSelectionStart(Entry platformEntry, ITextInput entry) { - int start = nativeEntry.Text?.Length ?? 0; + int start = platformEntry.Text?.Length ?? 0; int cursorPosition = entry.CursorPosition; - if (!string.IsNullOrEmpty(nativeEntry.Text)) + if (!string.IsNullOrEmpty(platformEntry.Text)) start = Math.Min(start, cursorPosition); if (start != cursorPosition) @@ -175,9 +175,9 @@ static int GetSelectionStart(Entry nativeEntry, ITextInput entry) return start; } - static int GetSelectionEnd(Entry nativeEntry, ITextInput entry, int start) + static int GetSelectionEnd(Entry platformEntry, ITextInput entry, int start) { - int end = Math.Max(start, Math.Min(nativeEntry.Text?.Length ?? 0, start + entry.SelectionLength)); + int end = Math.Max(start, Math.Min(platformEntry.Text?.Length ?? 0, start + entry.SelectionLength)); int selectionLength = end - start; if (selectionLength != entry.SelectionLength) entry.SelectionLength = selectionLength; diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs index 1461cb0dc541..39fdeed86abc 100644 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -29,20 +29,20 @@ public TSize Measure(double availableWidth, double availableHeight) protected void OnLayoutUpdated(object? sender, LayoutEventArgs e) { - var nativeGeometry = Geometry.ToDP(); + var platformGeometry = Geometry.ToDP(); - var measured = CrossPlatformMeasure!(nativeGeometry.Width, nativeGeometry.Height); + var measured = CrossPlatformMeasure!(platformGeometry.Width, platformGeometry.Height); if (measured != _measureCache && _virtualView?.Parent is IView parentView) { parentView?.InvalidateMeasure(); } _measureCache = measured; - if (nativeGeometry.Width > 0 && nativeGeometry.Height > 0) + if (platformGeometry.Width > 0 && platformGeometry.Height > 0) { - nativeGeometry.X = 0; - nativeGeometry.Y = 0; - CrossPlatformArrange!(nativeGeometry); + platformGeometry.X = 0; + platformGeometry.Y = 0; + CrossPlatformArrange!(platformGeometry); } } } diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index e9e3c454708b..d4010735e968 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -51,9 +51,9 @@ protected override void OnPreCreate() var rootContext = new MauiContext(mauiApp.Services); - var nativeWindow = CoreAppExtensions.GetDefaultWindow(); - nativeWindow.Initialize(); - rootContext.AddWeakSpecific(nativeWindow); + var platformWindow = CoreAppExtensions.GetDefaultWindow(); + platformWindow.Initialize(); + rootContext.AddWeakSpecific(platformWindow); _applicationContext = rootContext.MakeApplicationScope(this); diff --git a/src/Core/src/Platform/Tizen/WindowExtensions.cs b/src/Core/src/Platform/Tizen/PlatformWindowExtensions.cs similarity index 100% rename from src/Core/src/Platform/Tizen/WindowExtensions.cs rename to src/Core/src/Platform/Tizen/PlatformWindowExtensions.cs diff --git a/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs b/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs index d7e69723a472..62e1688b5489 100644 --- a/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs +++ b/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs @@ -14,9 +14,9 @@ public static void UpdateProgressColor(this ProgressBar platformProgressBar, IPr platformProgressBar.Color = progress.ProgressColor.ToPlatformEFL(); } - public static void UpdateProgressColor(this ProgressBar nativeProgressBar, IProgress progress) + public static void UpdateProgressColor(this ProgressBar platformProgressBar, IProgress progress) { - nativeProgressBar.Color = progress.ProgressColor.ToNativeEFL(); + platformProgressBar.Color = progress.ProgressColor.ToPlatformEFL(); } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ViewExtensions.cs b/src/Core/src/Platform/Tizen/ViewExtensions.cs index e79acaf888e8..e6fced159d8a 100644 --- a/src/Core/src/Platform/Tizen/ViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/ViewExtensions.cs @@ -316,45 +316,45 @@ internal static IDisposable OnUnloaded(this EvasObject view, Action action) return disposable; } - internal static Rectangle GetNativeViewBounds(this IView view) + internal static Rectangle GetPlatformViewBounds(this IView view) { - var nativeView = view?.ToPlatform(); - if (nativeView == null) + var platformView = view?.ToPlatform(); + if (platformView == null) { return new Rectangle(); } - return nativeView.GetNativeViewBounds(); + return platformView.GetPlatformViewBounds(); } - internal static Rectangle GetNativeViewBounds(this EvasObject nativeView) + internal static Rectangle GetPlatformViewBounds(this EvasObject platformView) { - if (nativeView == null) + if (platformView == null) return new Rectangle(); - return nativeView.Geometry.ToDP(); + return platformView.Geometry.ToDP(); } internal static Matrix4x4 GetViewTransform(this IView view) { - var nativeView = view?.ToPlatform(); - if (nativeView == null) + var platformView = view?.ToPlatform(); + if (platformView == null) return new Matrix4x4(); - return nativeView.GetViewTransform(); + return platformView.GetViewTransform(); } - internal static Matrix4x4 GetViewTransform(this EvasObject nativeView) + internal static Matrix4x4 GetViewTransform(this EvasObject platformView) => new Matrix4x4(); internal static Graphics.Rectangle GetBoundingBox(this IView view) => view.ToPlatform().GetBoundingBox(); - internal static Graphics.Rectangle GetBoundingBox(this EvasObject? nativeView) + internal static Graphics.Rectangle GetBoundingBox(this EvasObject? platformView) { - if (nativeView == null) + if (platformView == null) return new Rectangle(); - return nativeView.Geometry.ToDP(); + return platformView.Geometry.ToDP(); } internal static EvasObject? GetParent(this EvasObject? view) From efa6e99d4038220a1fb0a998533efbb7be37d103 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 24 Feb 2022 16:14:01 +0900 Subject: [PATCH 119/266] [Tizen] Interfaced Handler for Label, Page, NavigationView, Picker, ProgressBar, SwipeView --- src/Core/src/Handlers/Page/PageHandler.Tizen.cs | 2 +- .../SwipeView/SwipeItemMenuItemHandler.Tizen.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index 5e96c123a1e5..37251e0a3896 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -37,7 +37,7 @@ public override void NativeArrange(Graphics.Rectangle frame) } [MissingMapper] - public static void MapTitle(PageHandler handler, IContentView page) { } + public static void MapTitle(IPageHandler handler, IContentView page) { } protected override ContentCanvas CreatePlatformView() { diff --git a/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs b/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs index b2e6f29adb2d..e5a57db528fa 100644 --- a/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs +++ b/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs @@ -13,17 +13,17 @@ protected override EvasObject CreatePlatformElement() throw new NotImplementedException(); } - public static void MapTextColor(SwipeItemMenuItemHandler handler, ITextStyle view) { } + public static void MapTextColor(ISwipeItemMenuItemHandler handler, ITextStyle view) { } - public static void MapCharacterSpacing(SwipeItemMenuItemHandler handler, ITextStyle view) { } + public static void MapCharacterSpacing(ISwipeItemMenuItemHandler handler, ITextStyle view) { } - public static void MapFont(SwipeItemMenuItemHandler handler, ITextStyle view) { } + public static void MapFont(ISwipeItemMenuItemHandler handler, ITextStyle view) { } - public static void MapText(SwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } + public static void MapText(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } - public static void MapBackground(SwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } + public static void MapBackground(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } - public static void MapVisibility(SwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } + public static void MapVisibility(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } void OnSetImageSource(EvasObject? obj) { From 26e02875b3328d58409aedfbefc73acf495dca57 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 25 Feb 2022 13:11:59 +0900 Subject: [PATCH 120/266] [Tizen] Moved GetPlatformSize logic into a new service --- .../Core/src/Tizen/PlatformSizeService.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/Compatibility/Core/src/Tizen/PlatformSizeService.cs diff --git a/src/Compatibility/Core/src/Tizen/PlatformSizeService.cs b/src/Compatibility/Core/src/Tizen/PlatformSizeService.cs new file mode 100644 index 000000000000..2d6d2a0dfbee --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/PlatformSizeService.cs @@ -0,0 +1,14 @@ +using Microsoft.Maui.Controls.Internals; + +[assembly: Microsoft.Maui.Controls.Dependency(typeof(Microsoft.Maui.Controls.Compatibility.Platform.Tizen.PlatformSizeService))] + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + class PlatformSizeService : IPlatformSizeService + { + public SizeRequest GetPlatformSize(VisualElement view, double widthConstraint, double heightConstraint) + { + return Platform.GetNativeSize(view, widthConstraint, heightConstraint); + } + } +} \ No newline at end of file From df3cda9dfc06575e8f16ff868fd990f7db936416 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 25 Feb 2022 13:15:27 +0900 Subject: [PATCH 121/266] [Tizen] Interfaced handler for Switch, TimePicker, WebView, Slider, SearchBar, RefreshView, RadioButton --- .../src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs index ac7e28fabbb7..3d4cf8ade0fa 100644 --- a/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs +++ b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs @@ -54,13 +54,13 @@ public static void MapStrokeThickness(IRadioButtonHandler handler, IRadioButton public static void MapCornerRadius(IRadioButtonHandler handler, IRadioButton radioButton) { } [MissingMapper] - public static void MapStrokeColor(RadioButtonHandler handler, IRadioButton radioButton) { } + public static void MapStrokeColor(IRadioButtonHandler handler, IRadioButton radioButton) { } [MissingMapper] - public static void MapStrokeThickness(RadioButtonHandler handler, IRadioButton radioButton) { } + public static void MapStrokeThickness(IRadioButtonHandler handler, IRadioButton radioButton) { } [MissingMapper] - public static void MapCornerRadius(RadioButtonHandler handler, IRadioButton radioButton) { } + public static void MapCornerRadius(IRadioButtonHandler handler, IRadioButton radioButton) { } void OnValueChanged(object? sender, EventArgs e) { From 23094a222ccc493e2a047c5bffdb8fc0158a6174 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 28 Feb 2022 09:16:25 +0900 Subject: [PATCH 122/266] [Tizen] Fix build error after rebasing --- .../src/Maui/Tizen/WebViewExtension.cs | 5 +- .../SwipeItemMenuItemHandler.Tizen.cs | 33 ------- .../SwipeView/SwipeItemViewHandler.Tizen.cs | 97 ------------------- 3 files changed, 4 insertions(+), 131 deletions(-) delete mode 100644 src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs delete mode 100644 src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs diff --git a/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs b/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs index c083546fd9c3..54557d8eb5f8 100644 --- a/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs +++ b/src/BlazorWebView/src/Maui/Tizen/WebViewExtension.cs @@ -4,7 +4,10 @@ namespace Microsoft.AspNetCore.Components.WebView.Maui { - public static class WebViewExtension + /// + /// WebViewExtension + /// + internal static class WebViewExtension { public const string ChromiumEwk = "libchromium-ewk.so"; diff --git a/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs b/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs deleted file mode 100644 index e5a57db528fa..000000000000 --- a/src/Core/src/Handlers/SwipeView/SwipeItemMenuItemHandler.Tizen.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using ElmSharp; - -namespace Microsoft.Maui.Handlers -{ - //TODO : Need to implement - public partial class SwipeItemMenuItemHandler : ElementHandler - { - protected override EvasObject CreatePlatformElement() - { - throw new NotImplementedException(); - } - - public static void MapTextColor(ISwipeItemMenuItemHandler handler, ITextStyle view) { } - - public static void MapCharacterSpacing(ISwipeItemMenuItemHandler handler, ITextStyle view) { } - - public static void MapFont(ISwipeItemMenuItemHandler handler, ITextStyle view) { } - - public static void MapText(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } - - public static void MapBackground(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } - - public static void MapVisibility(ISwipeItemMenuItemHandler handler, ISwipeItemMenuItem view) { } - - void OnSetImageSource(EvasObject? obj) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs b/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs deleted file mode 100644 index a4e89a37bf6d..000000000000 --- a/src/Core/src/Handlers/SwipeView/SwipeItemViewHandler.Tizen.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using Microsoft.Maui.Platform; - -namespace Microsoft.Maui.Handlers -{ - public class SwipeItemViewHandler : ViewHandler - { - IPlatformViewHandler? _contentHandler; - - public static IPropertyMapper Mapper = new PropertyMapper(ViewHandler.ViewMapper) - { - [nameof(ISwipeItemView.Content)] = MapContent, - [nameof(ISwipeItemView.Visibility)] = MapVisibility - }; - - public static CommandMapper CommandMapper = new(ViewHandler.ViewCommandMapper) - { - }; - - public SwipeItemViewHandler() : base(Mapper, CommandMapper) - { - - } - - protected SwipeItemViewHandler(IPropertyMapper mapper, CommandMapper? commandMapper = null) - : base(mapper, commandMapper ?? CommandMapper) - { - } - - public SwipeItemViewHandler(IPropertyMapper? mapper = null) : base(mapper ?? Mapper) - { - - } - - protected override ContentCanvas CreatePlatformView() - { - _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} must be set to create a Page"); - _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} cannot be null"); - - var view = new ContentCanvas(NativeParent, VirtualView) - { - CrossPlatformMeasure = VirtualView.CrossPlatformMeasure, - CrossPlatformArrange = VirtualView.CrossPlatformArrange - }; - - view.Show(); - return view; - } - - public override void SetVirtualView(IView view) - { - base.SetVirtualView(view); - _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); - _ = PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class."); - - PlatformView.CrossPlatformMeasure = VirtualView.CrossPlatformMeasure; - PlatformView.CrossPlatformArrange = VirtualView.CrossPlatformArrange; - } - - void UpdateContent() - { - _ = PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class."); - _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); - _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); - - // Cleanup the old view when reused - PlatformView.Children.Clear(); - _contentHandler?.Dispose(); - _contentHandler = null; - - if (VirtualView.PresentedContent is IView view) - { - PlatformView.Children.Add(view.ToPlatform(MauiContext)); - if (view.Handler is IPlatformViewHandler thandler) - { - thandler?.SetParent(this); - _contentHandler = thandler; - } - } - } - - public static void MapContent(SwipeItemViewHandler handler, ISwipeItemView page) - { - handler.UpdateContent(); - } - - public static void MapVisibility(SwipeItemViewHandler handler, ISwipeItemView view) - { - //TODO : need to update - //var swipeView = handler.PlatformView.GetParentOfType(); - //if (swipeView != null) - // swipeView.UpdateIsVisibleSwipeItem(view); - - //handler.PlatformView.UpdateVisibility(view.Visibility); - } - } -} From 004285891880cbf4b7a5738715523a91f7ccca03 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 2 Mar 2022 17:25:44 +0900 Subject: [PATCH 123/266] [Tizen] Move TabbedPageHandler to TabbedViewHandler --- .../TabbedPage/TabbedPageHandler.Tizen.cs | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs diff --git a/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs b/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs deleted file mode 100644 index 8a577f73bc7a..000000000000 --- a/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPageHandler.Tizen.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.Maui.Handlers; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Handlers -{ - public partial class TabbedPageHandler : ViewHandler - { - protected override EvasObject CreatePlatformView() - { - // TODO : Need to impl - throw new NotImplementedException(); - } - - public static void MapBarBackground(TabbedPageHandler handler, TabbedPage view) - { - } - public static void MapBarBackgroundColor(TabbedPageHandler handler, TabbedPage view) - { - } - public static void MapBarTextColor(TabbedPageHandler handler, TabbedPage view) - { - } - public static void MapUnselectedTabColor(TabbedPageHandler handler, TabbedPage view) - { - } - public static void MapSelectedTabColor(TabbedPageHandler handler, TabbedPage view) - { - } - - public static void MapItemsSource(TabbedPageHandler handler, TabbedPage view) - { - } - public static void MapItemTemplate(TabbedPageHandler handler, TabbedPage view) - { - } - public static void MapSelectedItem(TabbedPageHandler handler, TabbedPage view) - { - } - public static void MapCurrentPage(TabbedPageHandler handler, TabbedPage view) - { - - } - } -} From bbfc78bae79726fa706730f577330b8657ff67ef Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 4 Mar 2022 17:12:07 +0900 Subject: [PATCH 124/266] [Tizen] Backport p14 changes --- .../src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs | 1 + .../Core/src/AppHostBuilderExtensions.Tizen.cs | 1 + src/Core/src/Platform/Tizen/LayoutCanvas.cs | 4 ++-- src/Core/src/Platform/Tizen/ViewExtensions.cs | 12 ++++++------ src/Core/src/Platform/Tizen/WrapperView.cs | 4 ++-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs index 0dbbc7a73827..6f7b2c42c4ee 100644 --- a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs +++ b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Maui; using Microsoft.Maui.Dispatching; diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs index 3142d9fcf9e2..038985315165 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs @@ -38,6 +38,7 @@ static void OnConfigureLifeCycle(ITizenLifecycleBuilder tizen) TDeviceInfo.DisplayResolutionUnit = options.DisplayResolutionUnit.ToDeviceInfo(); } options.Flags |= InitializationFlags.SkipRenderers; +#pragma warning disable CS0612 // Type or member is obsolete Forms.Init(state, options); #pragma warning disable CS0612 // Type or member is obsolete }) diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs index 39fdeed86abc..7aa89aa8ebc0 100644 --- a/src/Core/src/Platform/Tizen/LayoutCanvas.cs +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -2,7 +2,7 @@ using ElmSharp; using Tizen.UIExtensions.Common; using Tizen.UIExtensions.ElmSharp; -using Rectangle = Microsoft.Maui.Graphics.Rectangle; +using Rect = Microsoft.Maui.Graphics.Rect; using Size = Microsoft.Maui.Graphics.Size; using TSize = Tizen.UIExtensions.Common.Size; @@ -25,7 +25,7 @@ public TSize Measure(double availableWidth, double availableHeight) } internal Func? CrossPlatformMeasure { get; set; } - internal Func? CrossPlatformArrange { get; set; } + internal Func? CrossPlatformArrange { get; set; } protected void OnLayoutUpdated(object? sender, LayoutEventArgs e) { diff --git a/src/Core/src/Platform/Tizen/ViewExtensions.cs b/src/Core/src/Platform/Tizen/ViewExtensions.cs index e6fced159d8a..98cb6a7f9978 100644 --- a/src/Core/src/Platform/Tizen/ViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/ViewExtensions.cs @@ -321,16 +321,16 @@ internal static Rectangle GetPlatformViewBounds(this IView view) var platformView = view?.ToPlatform(); if (platformView == null) { - return new Rectangle(); + return new Rect(); } return platformView.GetPlatformViewBounds(); } - internal static Rectangle GetPlatformViewBounds(this EvasObject platformView) + internal static Rect GetPlatformViewBounds(this EvasObject platformView) { if (platformView == null) - return new Rectangle(); + return new Rect(); return platformView.Geometry.ToDP(); } @@ -346,13 +346,13 @@ internal static Matrix4x4 GetViewTransform(this IView view) internal static Matrix4x4 GetViewTransform(this EvasObject platformView) => new Matrix4x4(); - internal static Graphics.Rectangle GetBoundingBox(this IView view) + internal static Rect GetBoundingBox(this IView view) => view.ToPlatform().GetBoundingBox(); - internal static Graphics.Rectangle GetBoundingBox(this EvasObject? platformView) + internal static Rect GetBoundingBox(this EvasObject? platformView) { if (platformView == null) - return new Rectangle(); + return new Rect(); return platformView.Geometry.ToDP(); } diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index 54c201db38d7..119b6083d868 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -333,7 +333,7 @@ public DrawClipEventArgs(ICanvas canvas, RectangleF dirtyRect) public ICanvas Canvas { get; set; } - public RectangleF DirtyRect { get; set; } + public RectF DirtyRect { get; set; } } public class SKClipperView : SKCanvasView @@ -379,7 +379,7 @@ protected virtual void OnPaintSurface(object? sender, SKPaintSurfaceEventArgs e) if (DeviceScalingFactor > 0) _scalingCanvas.Scale(DeviceScalingFactor, DeviceScalingFactor); - DrawClip?.Invoke(this, new DrawClipEventArgs(_scalingCanvas, new RectangleF(0, 0, width, height))); + DrawClip?.Invoke(this, new DrawClipEventArgs(_scalingCanvas, new RectF(0, 0, width, height))); _scalingCanvas.RestoreState(); } } From 77c7313590efb0579dce4e745a0aa8de806b7d0e Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 7 Mar 2022 19:12:17 +0900 Subject: [PATCH 125/266] [Tizen] Loaded/Unloaded events and propagate Window --- src/Core/src/Platform/Tizen/ViewExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/src/Platform/Tizen/ViewExtensions.cs b/src/Core/src/Platform/Tizen/ViewExtensions.cs index 98cb6a7f9978..95ac70f0d4ec 100644 --- a/src/Core/src/Platform/Tizen/ViewExtensions.cs +++ b/src/Core/src/Platform/Tizen/ViewExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Numerics; using System.Threading.Tasks; From 939f8d834262cd98683c5c6ce16db93ce7336879 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 10 Mar 2022 16:37:41 +0900 Subject: [PATCH 126/266] [Tizen] Implement FillRule property in Polygon/PolylineHandler --- .../Handlers/Shapes/Polygon/PolygonHandler.Tizen.cs | 13 +++++++++++++ .../Shapes/Polyline/PolylineHandler.Tizen.cs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/Controls/src/Core/Handlers/Shapes/Polygon/PolygonHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Shapes/Polygon/PolygonHandler.Tizen.cs index 51635c23a19c..79d9a18a5b10 100644 --- a/src/Controls/src/Core/Handlers/Shapes/Polygon/PolygonHandler.Tizen.cs +++ b/src/Controls/src/Core/Handlers/Shapes/Polygon/PolygonHandler.Tizen.cs @@ -44,6 +44,19 @@ public static void MapFillRule(IShapeViewHandler handler, Polygon polygon) handler.PlatformView?.InvalidateShape(polygon); } + public static void MapFillRule(PolygonHandler handler, Polygon polygon) + { + IDrawable drawable = handler.PlatformView?.Drawable; + + if (drawable == null) + return; + + if (drawable is ShapeDrawable shapeDrawable) + shapeDrawable.WindingMode = polygon.FillRule == FillRule.EvenOdd ? Graphics.WindingMode.EvenOdd : Graphics.WindingMode.NonZero; + + handler.PlatformView?.InvalidateShape(polygon); + } + void OnPointsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { PlatformView?.InvalidateShape(VirtualView); diff --git a/src/Controls/src/Core/Handlers/Shapes/Polyline/PolylineHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Shapes/Polyline/PolylineHandler.Tizen.cs index 69fa54c1a024..c4e4eb71e0aa 100644 --- a/src/Controls/src/Core/Handlers/Shapes/Polyline/PolylineHandler.Tizen.cs +++ b/src/Controls/src/Core/Handlers/Shapes/Polyline/PolylineHandler.Tizen.cs @@ -44,6 +44,19 @@ public static void MapFillRule(IShapeViewHandler handler, Polyline polyline) handler.PlatformView?.InvalidateShape(polyline); } + public static void MapFillRule(PolylineHandler handler, Polyline polyline) + { + IDrawable drawable = handler.PlatformView?.Drawable; + + if (drawable == null) + return; + + if (drawable is ShapeDrawable shapeDrawable) + shapeDrawable.WindingMode = polyline.FillRule == FillRule.EvenOdd ? Graphics.WindingMode.EvenOdd : Graphics.WindingMode.NonZero; + + handler.PlatformView?.InvalidateShape(polyline); + } + void OnPointsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { PlatformView?.InvalidateShape(VirtualView); From 3ff0cc6ec7efc1c9fa9e7a232f9d97e4049346a3 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 10 Mar 2022 16:44:03 +0900 Subject: [PATCH 127/266] [Tizen] Add install tizen to provision.yml --- eng/pipelines/common/provision.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/eng/pipelines/common/provision.yml b/eng/pipelines/common/provision.yml index 6fc8f5948b75..6929b140063d 100644 --- a/eng/pipelines/common/provision.yml +++ b/eng/pipelines/common/provision.yml @@ -107,6 +107,11 @@ steps: displayName: 'Setup MSBuild Paths' condition: eq(variables['provisioningVS'], 'true') + - pwsh: | + Invoke-WebRequest 'https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.ps1' -OutFile 'workload-install.ps1' + .\workload-install.ps1 -v 7.0.100-preview.6.19 -t 6.0.200 + displayName: 'Install Tizen' + # Prepare Both - pwsh: ./build.ps1 --target provision displayName: 'Cake Provision' From e6c9e6bc29154145a95891bfc0e845c04360c578 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 11 Mar 2022 15:29:34 +0900 Subject: [PATCH 128/266] [Tizen] Move package version into Versions.props --- .../samples/Controls.Sample/MauiProgram.cs | 11 ----------- src/Essentials/samples/Samples/Startup.cs | 14 -------------- 2 files changed, 25 deletions(-) diff --git a/src/Controls/samples/Controls.Sample/MauiProgram.cs b/src/Controls/samples/Controls.Sample/MauiProgram.cs index 65ebde44cfd5..dd17f45fc7db 100644 --- a/src/Controls/samples/Controls.Sample/MauiProgram.cs +++ b/src/Controls/samples/Controls.Sample/MauiProgram.cs @@ -113,17 +113,6 @@ public static MauiApp CreateMauiApp() logging.AddConsole(); #endif }); -#if TIZEN - services.AddTransient((_) => - { - var option = new InitializationOptions - { - DisplayResolutionUnit = DisplayResolutionUnit.DP(true), - UseSkiaSharp = true - }; - return option; - }); -#endif services.AddSingleton(); services.AddTransient(); diff --git a/src/Essentials/samples/Samples/Startup.cs b/src/Essentials/samples/Samples/Startup.cs index ad47411ef175..b85505ad73d9 100644 --- a/src/Essentials/samples/Samples/Startup.cs +++ b/src/Essentials/samples/Samples/Startup.cs @@ -30,20 +30,6 @@ public static MauiApp CreateMauiApp() essentials.OnAppAction(App.HandleAppActions); }); -#if TIZEN - var services = builder.Services; - - services - .AddTransient((_) => - { - var option = new InitializationOptions - { - DisplayResolutionUnit = DisplayResolutionUnit.DP(true), - UseSkiaSharp = true - }; - return option; - }); -#endif return builder.Build(); } } From 8b6726667f17e79ac527e74d857a7591ac1ab310 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 17 May 2021 20:48:02 +0900 Subject: [PATCH 129/266] Adds the Tizen backend --- .../Core/src/AppHostBuilderExtensions.cs | 1 + .../Core/src/Tizen/HandlerToRendererShim.cs | 1 - .../Core/src/Tizen/RendererToHandlerShim.cs | 112 ++++++++ .../NavigationPageHandler.Tizen.cs | 260 ++++++++++++++++++ src/Core/src/IMauiContext.cs | 2 + .../Tizen/ImageSourceServiceResult.cs | 39 +++ .../src/Platform/Tizen/ActivationState.cs | 14 + .../src/Platform/Tizen/CoreUIAppContext.cs | 160 +++++++++++ .../src/Platform/Tizen/HandlerExtensions.cs | 48 ++++ src/Core/src/Platform/Tizen/MauiContext.cs | 32 +++ src/Core/src/Platform/Tizen/PageView.cs | 16 ++ 11 files changed, 684 insertions(+), 1 deletion(-) create mode 100644 src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs create mode 100644 src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs create mode 100644 src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs create mode 100644 src/Core/src/Platform/Tizen/ActivationState.cs create mode 100644 src/Core/src/Platform/Tizen/CoreUIAppContext.cs create mode 100644 src/Core/src/Platform/Tizen/HandlerExtensions.cs create mode 100644 src/Core/src/Platform/Tizen/MauiContext.cs create mode 100644 src/Core/src/Platform/Tizen/PageView.cs diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs index db525316c74f..90efcf1ce553 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs @@ -158,6 +158,7 @@ class MauiCompatInitializer : IMauiInitializeService { public void Initialize(IServiceProvider services) { + #if WINDOWS var dispatcher = services.GetService() ?? diff --git a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs index fe07cba3ba82..5cde81e81b25 100644 --- a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs +++ b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs @@ -194,6 +194,5 @@ public void Invoke(string command, object args) throw new NotImplementedException(); } } - } } diff --git a/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs b/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs new file mode 100644 index 000000000000..753a8af5bd6b --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs @@ -0,0 +1,112 @@ +using System; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +using ElmSharp; +using ViewHandler = Microsoft.Maui.Handlers.EViewHandler; + +namespace Microsoft.Maui.Controls.Compatibility +{ + public class RendererToHandlerShim : ViewHandler + { + internal IVisualElementRenderer VisualElementRenderer { get; private set; } + + public static IViewHandler CreateShim(object renderer) + { + if (renderer is IViewHandler handler) + return handler; + + if (renderer is IVisualElementRenderer ivr) + return new RendererToHandlerShim(ivr); + + return new RendererToHandlerShim(); + } + + public RendererToHandlerShim() : base(ViewHandler.ViewMapper) + { + } + + public RendererToHandlerShim(IVisualElementRenderer visualElementRenderer) : this() + { + if (visualElementRenderer != null) + SetupRenderer(visualElementRenderer); + } + + public void SetupRenderer(IVisualElementRenderer visualElementRenderer) + { + VisualElementRenderer = visualElementRenderer; + VisualElementRenderer.ElementChanged += OnElementChanged; + + if (VisualElementRenderer.Element is IView view) + { + view.Handler = this; + SetVirtualView(view); + } + else if (VisualElementRenderer.Element != null) + throw new Exception($"{VisualElementRenderer.Element} must implement: {nameof(IView)}"); + } + + void OnElementChanged(object sender, VisualElementChangedEventArgs e) + { + if (e.OldElement is IView view) + view.Handler = null; + + if (e.NewElement is IView newView) + { + newView.Handler = this; + this.SetVirtualView(newView); + } + else if (e.NewElement != null) + throw new Exception($"{e.NewElement} must implement: {nameof(IView)}"); + } + + protected override EvasObject CreateNativeView() + { + return VisualElementRenderer.NativeView; + } + + protected override void ConnectHandler(EvasObject nativeView) + { + base.ConnectHandler(nativeView); + VirtualView.Handler = this; + } + + protected override void DisconnectHandler(EvasObject nativeView) + { + Platform.Tizen.Platform.SetRenderer(VisualElementRenderer.Element, VisualElementRenderer); + + VisualElementRenderer.SetElement(null); + + base.DisconnectHandler(nativeView); + VirtualView.Handler = null; + } + + public override void SetVirtualView(IView view) + { + if (VisualElementRenderer == null) + { + var renderer = Internals.Registrar.Registered.GetHandlerForObject(view) ?? new DefaultRenderer(); + + SetupRenderer(renderer); + } + + if (VisualElementRenderer.Element != view) + { + VisualElementRenderer.SetElement((VisualElement)view); + } + else + { + base.SetVirtualView(view); + } + + Platform.Tizen.Platform.SetRenderer(VisualElementRenderer.Element, VisualElementRenderer); + } + + public override void UpdateValue(string property) + { + base.UpdateValue(property); + if (property == "Frame") + { + NativeArrange(VisualElementRenderer.Element.Bounds); + } + } + } +} diff --git a/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs new file mode 100644 index 000000000000..188b64746ded --- /dev/null +++ b/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Maui.Handlers; +using Microsoft.Maui.Controls.Internals; +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; + +using TButton = Tizen.UIExtensions.ElmSharp.Button; +using TSpan = Tizen.UIExtensions.Common.Span; +using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class NavigationPageHandler : + EViewHandler + { + readonly List _naviItemContentPartList = new List(); + TaskCompletionSource _currentTaskSource = null; + IDictionary _naviItemMap; + + Page PreviousPage => VirtualView.Navigation.NavigationStack.Count > 1 ? VirtualView.Navigation.NavigationStack[VirtualView.Navigation.NavigationStack.Count - 2] : null; + NaviItem CurrentNaviItem => NativeView.NavigationStack.Count > 0 ? NativeView.NavigationStack.Last() : null; + NaviItem PreviousNaviItem => NativeView.NavigationStack.Count > 1 ? NativeView.NavigationStack[NativeView.NavigationStack.Count - 2] : null; + + protected override Naviframe CreateNativeView() + { + return new Naviframe(NativeParent) + { + PreserveContentOnPop = true, + DefaultBackButtonEnabled = false, + }; + } + + protected override void ConnectHandler(Naviframe nativeView) + { + base.ConnectHandler(nativeView); + nativeView.AnimationFinished += OnAnimationFinished; + _naviItemMap = new Dictionary(); + + if (VirtualView == null) + return; + + VirtualView.PushRequested += OnPushRequested; + VirtualView.PopRequested += OnPopRequested; + VirtualView.InternalChildren.CollectionChanged += OnPageCollectionChanged; + + foreach (Page page in VirtualView.InternalChildren) + { + _naviItemMap[page] = NativeView.Push(CreateNavItem(page), SpanTitle(page.Title)); + page.PropertyChanged += NavigationBarPropertyChangedHandler; + + UpdateHasNavigationBar(page); + } + } + + protected override void DisconnectHandler(Naviframe nativeView) + { + base.DisconnectHandler(nativeView); + nativeView.AnimationFinished -= OnAnimationFinished; + + VirtualView.PushRequested -= OnPushRequested; + VirtualView.PopRequested -= OnPopRequested; + VirtualView.InternalChildren.CollectionChanged -= OnPageCollectionChanged; + } + + public static void MapPadding(NavigationPageHandler handler, NavigationPage view) { } + + public static void MapBarTextColor(NavigationPageHandler handler, NavigationPage view) + { + handler.UpdateTitle(view.CurrentPage); + } + + public static void MapBarBackground(NavigationPageHandler handler, NavigationPage view) { } + + public static void MapTitleIcon(NavigationPageHandler handler, NavigationPage view) { } + + public static void MapTitleView(NavigationPageHandler handler, NavigationPage view) { } + + void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + // this handler is invoked only for child pages (contained on a navigation stack) + if (e.PropertyName == NavigationPage.HasNavigationBarProperty.PropertyName) + UpdateHasNavigationBar(sender as Page); + else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName || + e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) + UpdateHasBackButton(sender as Page); + else if (e.PropertyName == Page.TitleProperty.PropertyName) + UpdateTitle(sender as Page); + } + + void OnPageCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.OldItems != null) + foreach (Page page in e.OldItems) + page.PropertyChanged -= NavigationBarPropertyChangedHandler; + if (e.NewItems != null) + foreach (Page page in e.NewItems) + page.PropertyChanged += NavigationBarPropertyChangedHandler; + } + + void OnPushRequested(object sender, NavigationRequestedEventArgs nre) + { + if (nre.Animated || NativeView.NavigationStack.Count == 0) + { + _naviItemMap[nre.Page] = NativeView.Push(CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); + _currentTaskSource = new TaskCompletionSource(); + nre.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after the first Push + if (NativeView.NavigationStack.Count == 1) + CompleteCurrentNavigationTask(); + } + else + { + _naviItemMap[nre.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); + } + UpdateHasNavigationBar(nre.Page); + } + + void OnPopRequested(object sender, NavigationRequestedEventArgs nre) + { + if (VirtualView.InternalChildren.Count == NativeView.NavigationStack.Count) + { + nre.Page?.SendDisappearing(); + UpdateNavigationBar(PreviousPage, PreviousNaviItem); + + if (nre.Animated) + { + NativeView.Pop(); + + _currentTaskSource = new TaskCompletionSource(); + nre.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after Pop the last page + if (NativeView.NavigationStack.Count == 0) + CompleteCurrentNavigationTask(); + } + else + { + CurrentNaviItem?.Delete(); + } + + if (_naviItemMap.ContainsKey(nre.Page)) + _naviItemMap.Remove(nre.Page); + } + } + + void OnAnimationFinished(object sender, EventArgs e) + { + CompleteCurrentNavigationTask(); + } + + void CompleteCurrentNavigationTask() + { + if (_currentTaskSource != null) + { + var tmp = _currentTaskSource; + _currentTaskSource = null; + tmp.SetResult(true); + } + } + + void UpdateHasNavigationBar(Page page) + { + NaviItem item = GetNaviItemForPage(page); + item.SetTabBarStyle(); + item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty); + UpdateBarBackgroundColor(item); + } + + void UpdateNavigationBar(Page page, NaviItem item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + UpdateTitle(page, item); + UpdateBarBackgroundColor(item); + } + + void UpdateHasBackButton(Page page, NaviItem item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + TButton button = null; + + if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty) && NativeView.NavigationStack.Count > 1) + { + button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty)); + } + item.SetBackButton(button); + } + + void UpdateTitle(Page page, NaviItem item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + item.SetTitle(SpanTitle(page.Title)); + } + + string SpanTitle(string Title) + { + TSpan span = new TSpan + { + Text = Title, + HorizontalTextAlignment = TTextAlignment.Center, + ForegroundColor = VirtualView.BarTextColor.ToNative() + }; + return span.GetMarkupText(); + } + + void UpdateBarBackgroundColor(NaviItem item) + { + item.TitleBarBackgroundColor = VirtualView.BarBackgroundColor.ToNativeEFL(); + } + + TButton CreateNavigationButton(string text) + { + var button = new TButton(NativeParent) + { + Text = text + }; + button.SetNavigationBackStyle(); + button.Clicked += (sender, e) => + { + if (!VirtualView.SendBackButtonPressed()) + Tizen.Applications.Application.Current.Exit(); + }; + _naviItemContentPartList.Add(button); + button.Deleted += NaviItemPartContentDeletedHandler; + return button; + } + + void NaviItemPartContentDeletedHandler(object sender, EventArgs e) + { + _naviItemContentPartList.Remove(sender as Widget); + } + + NaviItem GetNaviItemForPage(Page page) + { + NaviItem item; + if (_naviItemMap.TryGetValue(page, out item)) + { + return item; + } + return null; + } + + EvasObject CreateNavItem(Page page) + { + //TODO: Fix me + EvasObject nativeView = (EvasObject)page.Handler.NativeView; + return nativeView; + } + } +} diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index cf899f3188b5..824a47332e78 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -10,6 +10,8 @@ public interface IMauiContext #if __ANDROID__ Android.Content.Context? Context { get; } +#elif TIZEN + CoreUIAppContext Context { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs b/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs new file mode 100644 index 000000000000..6e48ceaec7c1 --- /dev/null +++ b/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs @@ -0,0 +1,39 @@ +#nullable enable +using System; + +namespace Microsoft.Maui +{ + public class ImageSourceServiceResult : IImageSourceServiceResult + { + Action? _dispose; + + public ImageSourceServiceResult(bool result, Action? dispose = null) + : this(result, false, dispose) + { + } + + public ImageSourceServiceResult(bool result, bool resolutionDependent, Action? dispose = null) + { + Value = result; + IsResolutionDependent = resolutionDependent; + _dispose = dispose; + } + + public bool Value { get; } + + public bool IsResolutionDependent { get; } + + public bool IsDisposed { get; private set; } + + public void Dispose() + { + if (IsDisposed) + return; + + IsDisposed = true; + + _dispose?.Invoke(); + _dispose = null; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ActivationState.cs b/src/Core/src/Platform/Tizen/ActivationState.cs new file mode 100644 index 000000000000..6719e581c7ce --- /dev/null +++ b/src/Core/src/Platform/Tizen/ActivationState.cs @@ -0,0 +1,14 @@ +using System; + +namespace Microsoft.Maui +{ + public class ActivationState : IActivationState + { + public ActivationState(IMauiContext context) + { + Context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public IMauiContext Context { get; } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs new file mode 100644 index 000000000000..f321eeaf1dcc --- /dev/null +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -0,0 +1,160 @@ +using System; +using System.Reflection; +using Tizen.Common; +using Tizen.Applications; +using ElmSharp; +using ElmSharp.Wearable; +using Tizen.UIExtensions.ElmSharp; +using ELayout = ElmSharp.Layout; + +namespace Microsoft.Maui +{ + public class CoreUIAppContext + { + DisplayResolutionUnit _displayResolutionUnit = DisplayResolutionUnit.DP; + double _viewPortWidth = -1; + + static CoreUIAppContext? _instance = null; + + public static bool IsInitialized { get; private set; } + + public static CoreUIAppContext GetInstance(CoreApplication application, Window? window = null) + { + if (IsInitialized) + return _instance!; + + _instance = (window == null) ? new CoreUIAppContext(application) : new CoreUIAppContext(application, window); + return _instance; + } + + public CoreApplication CurrentApplication { get; private set; } + + public string ResourceDir => CurrentApplication.DirectoryInfo.Resource; + + public EvasObject NativeParent => BaseLayout; + + public Window MainWindow { get; set; } + + public ELayout BaseLayout { get; set; } + + public CircleSurface? BaseCircleSurface { get; set; } + + public DeviceType DeviceType => DeviceInfo.GetDeviceType(); + + public DisplayResolutionUnit DisplayResolutionUnit + { + get => _displayResolutionUnit; + set + { + _displayResolutionUnit = value; + DeviceInfo.DisplayResolutionUnit = _displayResolutionUnit; + } + } + + public double ViewportWidth + { + get => _viewPortWidth; + set + { + _viewPortWidth = value; + ViewportWidth = _viewPortWidth; + } + } + + protected CoreUIAppContext(CoreApplication application) : this(application, CreateDefaultWindow()) + { + } + + protected CoreUIAppContext(CoreApplication application, Window window) + { + _ = application ?? throw new ArgumentNullException(nameof(application)); + _ = window ?? throw new ArgumentNullException(nameof(window)); + + if (DisplayResolutionUnit == DisplayResolutionUnit.VP && ViewportWidth < 0) + throw new InvalidOperationException($"ViewportWidth should be set in case of DisplayResolutionUnit == VP"); + + Elementary.Initialize(); + Elementary.ThemeOverlay(); + CurrentApplication = application; + MainWindow = window; + InitializeMainWindow(); + + _ = BaseLayout ?? throw new ArgumentNullException(nameof(BaseLayout)); + + if (DotnetUtil.TizenAPIVersion < 5) + { + // We should set the env variable to support IsolatedStorageFile on tizen 4.0 or lower version. + Environment.SetEnvironmentVariable("XDG_DATA_HOME", CurrentApplication.DirectoryInfo.Data); + } + + IsInitialized = true; + } + + public void SetContent(EvasObject content) + { + content.SetAlignment(-1, -1); + content.SetWeight(1, 1); + content.Show(); + BaseLayout.SetContent(content); + } + + static Window CreateDefaultWindow() + { + return GetPreloadedWindow() ?? new Window("XamarinWindow"); + } + + static Window? GetPreloadedWindow() + { + var type = typeof(Window); + // Use reflection to avoid breaking compatibility. ElmSharp.Window.CreateWindow() is has been added since API6. + var methodInfo = type.GetMethod("CreateWindow", BindingFlags.NonPublic | BindingFlags.Static); + + return (Window?)methodInfo?.Invoke(null, new object[] { "FormsWindow" }); + } + + void InitializeMainWindow() + { +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8601 // Possible null reference assignment. + BaseLayout = (ELayout)MainWindow.GetType().GetProperty("BaseLayout")?.GetValue(MainWindow); + BaseCircleSurface = (CircleSurface)MainWindow.GetType().GetProperty("BaseCircleSurface")?.GetValue(MainWindow); +#pragma warning restore CS8601 // Possible null reference assignment. +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. + + if (BaseLayout == null) + { + var conformant = new Conformant(MainWindow); + conformant.Show(); + + var layout = new ApplicationLayout(conformant); + layout.Show(); + + BaseLayout = layout; + + if (DeviceType == DeviceType.Watch) + { + BaseCircleSurface = new CircleSurface(conformant); + } + conformant.SetContent(BaseLayout); + + if (DeviceType == DeviceType.Watch) + { + BaseCircleSurface = new CircleSurface(conformant); + } + } + + MainWindow.Active(); + MainWindow.Show(); + MainWindow.AvailableRotations = DisplayRotation.Degree_0 | DisplayRotation.Degree_90 | DisplayRotation.Degree_180 | DisplayRotation.Degree_270; + + MainWindow.Deleted += (s, e) => CurrentApplication.Exit(); + + MainWindow.RotationChanged += (sender, e) => + { + // TODO : should update later + }; + + MainWindow.BackButtonPressed += (sender, e) => CurrentApplication.Exit(); + } + } +} diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs new file mode 100644 index 000000000000..878728238bba --- /dev/null +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -0,0 +1,48 @@ +using System; +using ElmSharp; +using Microsoft.Maui.Handlers; + +namespace Microsoft.Maui +{ + public static class HandlerExtensions + { + public static EvasObject ToNative(this IView view, IMauiContext context, bool isRoot = true) + { + _ = view ?? throw new ArgumentNullException(nameof(view)); + _ = context ?? throw new ArgumentNullException(nameof(context)); + + //This is how MVU works. It collapses views down + if (view is IReplaceableView ir) + view = ir.ReplacedView; + + var handler = view.Handler; + + if (handler == null) + { + handler = context.Handlers.GetHandler(view.GetType()); + + if (handler == null) + throw new Exception($"Handler not found for view {view}"); + + handler.SetMauiContext(context); + + view.Handler = handler; + } + + handler.SetVirtualView(view); + + if (!(handler.NativeView is EvasObject result)) + { + throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); + } + + // Root content view should register to LayoutUpdated() callback. + if (isRoot && handler is LayoutHandler layoutHandler) + { + layoutHandler.RegisterOnLayoutUpdated(); + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiContext.cs b/src/Core/src/Platform/Tizen/MauiContext.cs new file mode 100644 index 000000000000..7b248d30ecb5 --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiContext.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.Maui +{ + public class MauiContext : IMauiContext + { + readonly CoreUIAppContext _context; + readonly IServiceProvider? _services; + readonly IMauiHandlersServiceProvider? _mauiHandlersServiceProvider; + + public MauiContext(CoreUIAppContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public MauiContext(IServiceProvider services, CoreUIAppContext context) + { + _services = services ?? throw new ArgumentNullException(nameof(services)); + _context = context ?? throw new ArgumentNullException(nameof(context)); + _mauiHandlersServiceProvider = Services.GetRequiredService(); + } + + public CoreUIAppContext Context => _context; + + public IServiceProvider Services => + _services ?? throw new InvalidOperationException($"No service provider was specified during construction."); + + public IMauiHandlersServiceProvider Handlers => + _mauiHandlersServiceProvider ?? throw new InvalidOperationException($"No service provider was specified during construction."); + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/PageView.cs b/src/Core/src/Platform/Tizen/PageView.cs new file mode 100644 index 000000000000..24ec2915c420 --- /dev/null +++ b/src/Core/src/Platform/Tizen/PageView.cs @@ -0,0 +1,16 @@ +using System; +using Microsoft.Maui.Graphics; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui +{ + public class PageView : Page + { + public PageView(ElmSharp.EvasObject parent) : base(parent) + { + } + + internal Func? CrossPlatformMeasure { get; set; } + internal Func? CrossPlatformArrange { get; set; } + } +} From b13933104eeedee7220da74c0b38c3abb184b4c2 Mon Sep 17 00:00:00 2001 From: JoonghyunCho Date: Fri, 23 Apr 2021 14:10:08 +0900 Subject: [PATCH 130/266] [Tizen] Add Resizetizer Tizen Implementation --- .../src/TizenIconManifestUpdator.cs | 56 ++++++ .../Resizetizer/src/TizenSplashUpdator.cs | 160 ++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs create mode 100644 src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs diff --git a/src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs b/src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs new file mode 100644 index 000000000000..b8ea28316b95 --- /dev/null +++ b/src/SingleProject/Resizetizer/src/TizenIconManifestUpdator.cs @@ -0,0 +1,56 @@ +using System; +using System.Xml; + +namespace Microsoft.Maui.Resizetizer +{ + internal class TizenIconManifestUpdator + { + const string namespaceURI = "http://tizen.org/ns/packages"; + + public TizenIconManifestUpdator(string appIconName, DpiPath[] dpis, ILogger logger) + { + AppIconName = appIconName; + Dpis = dpis; + Logger = logger; + } + + public string AppIconName { get; private set; } + + public DpiPath[] Dpis { get; } + + public ILogger Logger { get; private set; } + + public void Update() + { + XmlDocument doc = new XmlDocument(); + var xmlPath = Environment.CurrentDirectory + "\\tizen-manifest.xml"; + try + { + doc.Load(xmlPath); + } + catch + { + Logger.Log($"Failed to load tizen-manifest.xml"); + return; + } + + var nsmgr = new XmlNamespaceManager(doc.NameTable); + nsmgr.AddNamespace("manifest", namespaceURI); + var uiApplicationNode = doc.SelectSingleNode("//manifest:ui-application", nsmgr); + if (uiApplicationNode == null) + { + Logger.Log($"Failed to find "); + return; + } + var IconNode = doc.SelectSingleNode("//manifest:icon", nsmgr); + if (IconNode == null) + { + IconNode = doc.CreateElement("icon", namespaceURI); + uiApplicationNode.AppendChild(IconNode); + } + IconNode.InnerText = AppIconName + Dpis[1].FileSuffix + ".png"; + + doc.Save(xmlPath); + } + } +} diff --git a/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs b/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs new file mode 100644 index 000000000000..0559f47e702b --- /dev/null +++ b/src/SingleProject/Resizetizer/src/TizenSplashUpdator.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using SkiaSharp; + +namespace Microsoft.Maui.Resizetizer +{ + public class TizenSplashUpdator : Task + { + [Required] + public ITaskItem[] MauiSplashScreen { get; set; } + + [Required] + public string IntermediateOutputPath { get; set; } + + public ILogger Logger { get; private set; } + + public override bool Execute() + { + if (UpdateSplashImage()) + UpdateManifest(); + return !Log.HasLoggedErrors; + } + + const string namespaceURI = "http://tizen.org/ns/packages"; + const string splashDirectoryName = "splash"; + List orientations = new List() { "portrait", "landscape" }; + Dictionary splashDpiMap = new Dictionary(); + + public bool UpdateSplashImage() + { + var splash = MauiSplashScreen[0]; + var image = Path.GetFileNameWithoutExtension(splash.ItemSpec) + ".png"; + var sharedResFullPath = Path.GetFullPath(Path.Combine(IntermediateOutputPath, "shared/res/")); + var splashFullPath = Path.Combine(sharedResFullPath, splashDirectoryName); + + if (Directory.Exists(splashFullPath)) + { + Directory.Delete(splashFullPath, true); + } + Directory.CreateDirectory(splashFullPath); + + foreach (var dpi in DpiPath.Tizen) + { + var imageOutputPath = Path.GetFullPath(Path.Combine(IntermediateOutputPath, dpi.Path)); + var imageFullPath = Path.Combine(imageOutputPath, image); + if (File.Exists(imageFullPath)) + { + var resolution = dpi.Path.Split('-')[1].ToLower(); + var newImage = Path.GetFileNameWithoutExtension(splash.ItemSpec) + "." + resolution + ".png"; + splashDpiMap.Add(resolution, $"{splashDirectoryName}/{ newImage }"); + UpdateColorAndMoveFile(imageFullPath, Path.Combine(splashFullPath, newImage)); + } + else + { + Log.LogWarning($"Unable to find splash image at {imageFullPath}."); + return false; + } + } + return true; + } + + public void UpdateColorAndMoveFile(string sourceFilePath, string destFilePath) + { + var splash = MauiSplashScreen[0]; + var colorMetadata = splash.GetMetadata("Color"); + var color = Utils.ParseColorString(colorMetadata); + if (color == null) + { + if (!string.IsNullOrEmpty(colorMetadata)) + { + Log.LogWarning($"Unable to parse color value '{colorMetadata}' for '{splash.ItemSpec}'."); + } + color = SKColors.White; + } + + using (SKBitmap bmp = SKBitmap.Decode(sourceFilePath)) + { + SKImageInfo info = new SKImageInfo(bmp.Width, bmp.Height); + using (SKSurface surface = SKSurface.Create(info)) + { + SKCanvas canvas = surface.Canvas; + canvas.Clear(color.Value); + using SKPaint paint = new SKPaint + { + IsAntialias = true, + FilterQuality = SKFilterQuality.High + }; + canvas.DrawBitmap(bmp, info.Rect, paint); + canvas.Flush(); + + var updatedsplash = surface.Snapshot(); + using (var data = updatedsplash.Encode(SKEncodedImageFormat.Png, 100)) + { + using (var stream = File.Create(destFilePath)) + { + data.SaveTo(stream); + } + } + } + } + File.Delete(sourceFilePath); + } + + public void UpdateManifest() + { + XmlDocument doc = new XmlDocument(); + var xmlPath = Environment.CurrentDirectory + "\\tizen-manifest.xml"; + try + { + doc.Load(xmlPath); + } + catch + { + Log.LogWarning($"Failed to load tizen-manifest.xml"); + return; + } + + var nsmgr = new XmlNamespaceManager(doc.NameTable); + nsmgr.AddNamespace("manifest", namespaceURI); + var uiApplicationNode = doc.SelectSingleNode("//manifest:ui-application", nsmgr); + if (uiApplicationNode == null) + { + Log.LogWarning($"Failed to find "); + return; + } + var splashScreensNodeList = doc.SelectNodes("//manifest:splash-screens", nsmgr); + if (splashScreensNodeList != null) + { + foreach (XmlNode node in splashScreensNodeList) + { + uiApplicationNode.RemoveChild(node); + } + } + + var splashScreensNode = doc.CreateElement("splash-screens", namespaceURI); + uiApplicationNode.AppendChild(splashScreensNode); + + foreach(var image in splashDpiMap) + { + foreach (var orientation in orientations) + { + var splashScreenNode = doc.CreateElement("splash-screen", namespaceURI); + splashScreenNode.SetAttribute("src", image.Value); + splashScreenNode.SetAttribute("type", "img"); + splashScreenNode.SetAttribute("dpi", image.Key); + splashScreenNode.SetAttribute("orientation", orientation); + splashScreenNode.SetAttribute("indicator-display", "false"); + splashScreenNode.SetAttribute("app-control-operation", "http://tizen.org/appcontrol/operation/default"); + splashScreensNode.AppendChild(splashScreenNode); + } + } + + doc.Save(xmlPath); + } + } +} From 2ef55f1e28e76cbdf9813db0a10130617a51268f Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 1 Jun 2021 07:39:20 +0900 Subject: [PATCH 131/266] Bump to latest and fix build error --- .../Core/src/Tizen/RendererToHandlerShim.cs | 112 ------------------ 1 file changed, 112 deletions(-) delete mode 100644 src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs diff --git a/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs b/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs deleted file mode 100644 index 753a8af5bd6b..000000000000 --- a/src/Compatibility/Core/src/Tizen/RendererToHandlerShim.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; -using ElmSharp; -using ViewHandler = Microsoft.Maui.Handlers.EViewHandler; - -namespace Microsoft.Maui.Controls.Compatibility -{ - public class RendererToHandlerShim : ViewHandler - { - internal IVisualElementRenderer VisualElementRenderer { get; private set; } - - public static IViewHandler CreateShim(object renderer) - { - if (renderer is IViewHandler handler) - return handler; - - if (renderer is IVisualElementRenderer ivr) - return new RendererToHandlerShim(ivr); - - return new RendererToHandlerShim(); - } - - public RendererToHandlerShim() : base(ViewHandler.ViewMapper) - { - } - - public RendererToHandlerShim(IVisualElementRenderer visualElementRenderer) : this() - { - if (visualElementRenderer != null) - SetupRenderer(visualElementRenderer); - } - - public void SetupRenderer(IVisualElementRenderer visualElementRenderer) - { - VisualElementRenderer = visualElementRenderer; - VisualElementRenderer.ElementChanged += OnElementChanged; - - if (VisualElementRenderer.Element is IView view) - { - view.Handler = this; - SetVirtualView(view); - } - else if (VisualElementRenderer.Element != null) - throw new Exception($"{VisualElementRenderer.Element} must implement: {nameof(IView)}"); - } - - void OnElementChanged(object sender, VisualElementChangedEventArgs e) - { - if (e.OldElement is IView view) - view.Handler = null; - - if (e.NewElement is IView newView) - { - newView.Handler = this; - this.SetVirtualView(newView); - } - else if (e.NewElement != null) - throw new Exception($"{e.NewElement} must implement: {nameof(IView)}"); - } - - protected override EvasObject CreateNativeView() - { - return VisualElementRenderer.NativeView; - } - - protected override void ConnectHandler(EvasObject nativeView) - { - base.ConnectHandler(nativeView); - VirtualView.Handler = this; - } - - protected override void DisconnectHandler(EvasObject nativeView) - { - Platform.Tizen.Platform.SetRenderer(VisualElementRenderer.Element, VisualElementRenderer); - - VisualElementRenderer.SetElement(null); - - base.DisconnectHandler(nativeView); - VirtualView.Handler = null; - } - - public override void SetVirtualView(IView view) - { - if (VisualElementRenderer == null) - { - var renderer = Internals.Registrar.Registered.GetHandlerForObject(view) ?? new DefaultRenderer(); - - SetupRenderer(renderer); - } - - if (VisualElementRenderer.Element != view) - { - VisualElementRenderer.SetElement((VisualElement)view); - } - else - { - base.SetVirtualView(view); - } - - Platform.Tizen.Platform.SetRenderer(VisualElementRenderer.Element, VisualElementRenderer); - } - - public override void UpdateValue(string property) - { - base.UpdateValue(property); - if (property == "Frame") - { - NativeArrange(VisualElementRenderer.Element.Bounds); - } - } - } -} From 6f7f7fc5c61dd6aaf6e3009e7cdd7bab8921a2f0 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 22 Jun 2021 06:49:16 +0900 Subject: [PATCH 132/266] Bump to latest - Apply to start adding in APIs for adding legacy renderers via assembly scanning (#1333) - Update to IMauiContext (#1357) - and so on --- src/Core/src/IMauiContext.cs | 2 +- src/Core/src/Platform/MauiContext.Tizen.cs | 37 ++++++++++++++++++++++ src/Core/src/Platform/Tizen/MauiContext.cs | 32 ------------------- 3 files changed, 38 insertions(+), 33 deletions(-) create mode 100644 src/Core/src/Platform/MauiContext.Tizen.cs delete mode 100644 src/Core/src/Platform/Tizen/MauiContext.cs diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index 824a47332e78..11b1593bb241 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -11,7 +11,7 @@ public interface IMauiContext #if __ANDROID__ Android.Content.Context? Context { get; } #elif TIZEN - CoreUIAppContext Context { get; } + CoreUIAppContext? Context { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/Platform/MauiContext.Tizen.cs b/src/Core/src/Platform/MauiContext.Tizen.cs new file mode 100644 index 000000000000..3a0b26c4b7cc --- /dev/null +++ b/src/Core/src/Platform/MauiContext.Tizen.cs @@ -0,0 +1,37 @@ +using System; + +namespace Microsoft.Maui +{ + public partial class MauiContext + { + readonly WeakReference? _context; + + public MauiContext(CoreUIAppContext context) : this() + { + _context = new WeakReference(context ?? throw new ArgumentNullException(nameof(context))); + } + + public MauiContext(IServiceProvider services, CoreUIAppContext context) : this(services) + { + _context = new WeakReference(context ?? throw new ArgumentNullException(nameof(context))); + } + + public CoreUIAppContext? Context + { + get + { + if (_context == null) + return null; + + CoreUIAppContext? context; + if (_context.TryGetTarget(out context)) + { + return context; + } + + return null; + } + } + + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiContext.cs b/src/Core/src/Platform/Tizen/MauiContext.cs deleted file mode 100644 index 7b248d30ecb5..000000000000 --- a/src/Core/src/Platform/Tizen/MauiContext.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.Maui -{ - public class MauiContext : IMauiContext - { - readonly CoreUIAppContext _context; - readonly IServiceProvider? _services; - readonly IMauiHandlersServiceProvider? _mauiHandlersServiceProvider; - - public MauiContext(CoreUIAppContext context) - { - _context = context ?? throw new ArgumentNullException(nameof(context)); - } - - public MauiContext(IServiceProvider services, CoreUIAppContext context) - { - _services = services ?? throw new ArgumentNullException(nameof(services)); - _context = context ?? throw new ArgumentNullException(nameof(context)); - _mauiHandlersServiceProvider = Services.GetRequiredService(); - } - - public CoreUIAppContext Context => _context; - - public IServiceProvider Services => - _services ?? throw new InvalidOperationException($"No service provider was specified during construction."); - - public IMauiHandlersServiceProvider Handlers => - _mauiHandlersServiceProvider ?? throw new InvalidOperationException($"No service provider was specified during construction."); - } -} \ No newline at end of file From 3847cd3c459c179118a3f7daeb91c44e3dd10994 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 29 Jun 2021 10:22:31 +0900 Subject: [PATCH 133/266] Bump to latest - Apply to patch related to Animation (#1436) - Apply to register Microsoft.Maui.Graphics Platforms (#1441) - and so on. --- .../ModalNavigationService.Tizen.cs | 22 ++++++++++ src/Core/src/Animations/NativeTicker.Tizen.cs | 42 +++++++++++++++++++ .../src/Platform/Tizen/MauiApplication.cs | 5 ++- 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs create mode 100644 src/Core/src/Animations/NativeTicker.Tizen.cs diff --git a/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs b/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs new file mode 100644 index 000000000000..f9800c51b6d9 --- /dev/null +++ b/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs @@ -0,0 +1,22 @@ +#nullable enable + +using System; +using System.Threading.Tasks; + +namespace Microsoft.Maui.Controls.Platform +{ + internal partial class ModalNavigationService + { + public Task PopModalAsync(bool animated) + { + // TODO: Need to implementation + throw new NotImplementedException(); + } + + public Task PushModalAsync(Page modal, bool animated) + { + // TODO: Need to implementation + throw new NotImplementedException(); + } + } +} diff --git a/src/Core/src/Animations/NativeTicker.Tizen.cs b/src/Core/src/Animations/NativeTicker.Tizen.cs new file mode 100644 index 000000000000..6d7fc0495fae --- /dev/null +++ b/src/Core/src/Animations/NativeTicker.Tizen.cs @@ -0,0 +1,42 @@ +using System.Threading; +using Tizen.Applications; + +namespace Microsoft.Maui.Animations +{ + public class NativeTicker : Ticker + { + readonly Timer _timer; + readonly SynchronizationContext? _context; + bool _isRunning; + + public override bool IsRunning => _isRunning; + + public NativeTicker() + { + if (SynchronizationContext.Current == null) + { + TizenSynchronizationContext.Initialize(); + } + + _context = SynchronizationContext.Current; + _timer = new Timer((object o) => HandleElapsed(o), this, Timeout.Infinite, Timeout.Infinite); + } + + public override void Start() + { + _timer.Change(16, 16); + _isRunning = true; + } + + public override void Stop() + { + _timer.Change(-1, -1); + _isRunning = false; + } + + void HandleElapsed(object state) + { + _context?.Post((o) => Fire?.Invoke(), null); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index d4010735e968..67425e4dc8dc 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -59,7 +59,10 @@ protected override void OnPreCreate() Services = _applicationContext.Services; - Current.Services?.InvokeLifecycleEvents(del => del(this)); + if (Services == null) + throw new InvalidOperationException($"The {nameof(IServiceProvider)} instance was not found."); + + Current.Services.InvokeLifecycleEvents(del => del(this)); } protected override void OnCreate() From f9deaa5bf42c4fd9adb0d8c5b2c46a764ec7d4af Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Tue, 6 Jul 2021 17:57:42 +0900 Subject: [PATCH 134/266] Bump to latest - Modal Navigation Manager (#1563) - Implement the basic WindowHandler (#1468) - Don't extract native defaults, meaning users can no longer reset a color back to a platform theme (#1485) - Implement Alerts (Alert, Prompt and ActionSheet) (#1328) - And so on. --- .../src/Core/HandlerImpl/Window.Tizen.cs | 12 +++++++ .../ModalNavigationService.Tizen.cs | 22 ------------- src/Core/src/IMauiContext.cs | 1 + src/Core/src/Platform/MauiContext.Tizen.cs | 2 ++ .../src/Platform/Tizen/HandlerExtensions.cs | 32 ++++++++++++++++--- .../src/Platform/Tizen/MauiApplication.cs | 2 ++ 6 files changed, 44 insertions(+), 27 deletions(-) create mode 100644 src/Controls/src/Core/HandlerImpl/Window.Tizen.cs delete mode 100644 src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs diff --git a/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs new file mode 100644 index 000000000000..12dcf19a25ea --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs @@ -0,0 +1,12 @@ +#nullable enable +using System; +using EWindow = ElmSharp.Window; + +namespace Microsoft.Maui.Controls +{ + public partial class Window + { + internal EWindow NativeWindow => + (Handler?.NativeView as EWindow) ?? throw new InvalidOperationException("Window should have a ElmSharp.Window set."); + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs b/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs deleted file mode 100644 index f9800c51b6d9..000000000000 --- a/src/Controls/src/Core/Platform/ModalNavigationService/ModalNavigationService.Tizen.cs +++ /dev/null @@ -1,22 +0,0 @@ -#nullable enable - -using System; -using System.Threading.Tasks; - -namespace Microsoft.Maui.Controls.Platform -{ - internal partial class ModalNavigationService - { - public Task PopModalAsync(bool animated) - { - // TODO: Need to implementation - throw new NotImplementedException(); - } - - public Task PushModalAsync(Page modal, bool animated) - { - // TODO: Need to implementation - throw new NotImplementedException(); - } - } -} diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index 11b1593bb241..e1648772dffa 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -12,6 +12,7 @@ public interface IMauiContext Android.Content.Context? Context { get; } #elif TIZEN CoreUIAppContext? Context { get; } + ElmSharp.Window? Window { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/Platform/MauiContext.Tizen.cs b/src/Core/src/Platform/MauiContext.Tizen.cs index 3a0b26c4b7cc..231f6a27583f 100644 --- a/src/Core/src/Platform/MauiContext.Tizen.cs +++ b/src/Core/src/Platform/MauiContext.Tizen.cs @@ -1,4 +1,5 @@ using System; +using ElmSharp; namespace Microsoft.Maui { @@ -33,5 +34,6 @@ public CoreUIAppContext? Context } } + public Window? Window => Context?.MainWindow; } } \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 878728238bba..580ce27a0cbe 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -1,4 +1,5 @@ using System; +using Tizen.Applications; using ElmSharp; using Microsoft.Maui.Handlers; @@ -18,11 +19,12 @@ public static EvasObject ToNative(this IView view, IMauiContext context, bool is var handler = view.Handler; if (handler == null) - { - handler = context.Handlers.GetHandler(view.GetType()); + handler = context.Handlers.GetHandler(view.GetType()) as IViewHandler; + + if (handler == null) + throw new Exception($"Handler not found for view {view} or was not {nameof(IViewHandler)}."); - if (handler == null) - throw new Exception($"Handler not found for view {view}"); + handler.SetMauiContext(context); handler.SetMauiContext(context); @@ -34,7 +36,6 @@ public static EvasObject ToNative(this IView view, IMauiContext context, bool is if (!(handler.NativeView is EvasObject result)) { throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); - } // Root content view should register to LayoutUpdated() callback. if (isRoot && handler is LayoutHandler layoutHandler) @@ -44,5 +45,26 @@ public static EvasObject ToNative(this IView view, IMauiContext context, bool is return result; } + + public static void SetWindow(this Window nativeWindow, IWindow window, IMauiContext mauiContext) + { + _ = nativeWindow ?? throw new ArgumentNullException(nameof(nativeWindow)); + _ = window ?? throw new ArgumentNullException(nameof(window)); + _ = mauiContext ?? throw new ArgumentNullException(nameof(mauiContext)); + + var handler = window.Handler as IWindowHandler; + if (handler == null) + handler = mauiContext.Handlers.GetHandler(window.GetType()) as IWindowHandler; + + if (handler == null) + throw new Exception($"Handler not found for view {window} or was not {nameof(IWindowHandler)}'"); + + handler.SetMauiContext(mauiContext); + + window.Handler = handler; + + if (handler.VirtualView != window) + handler.SetVirtualView(window); + } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index 67425e4dc8dc..d82bf5708984 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -145,6 +145,8 @@ protected override void OnTerminate() public static new MauiApplication Current { get; private set; } = null!; + public Window MainWindow { get; protected set; } = null!; + public IServiceProvider Services { get; protected set; } = null!; public IApplication Application { get; protected set; } = null!; From ace4a0f0b43be1a7a8339e4fc09ffc89ff7c97b5 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 14 Jul 2021 10:04:16 +0900 Subject: [PATCH 135/266] Bumt to latest - Effects (#1574) - Improve Window and AnimationManager (#1653) - and so on --- src/Core/src/Platform/Tizen/HandlerExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 580ce27a0cbe..972948d30527 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -52,12 +52,12 @@ public static void SetWindow(this Window nativeWindow, IWindow window, IMauiCont _ = window ?? throw new ArgumentNullException(nameof(window)); _ = mauiContext ?? throw new ArgumentNullException(nameof(mauiContext)); - var handler = window.Handler as IWindowHandler; + var handler = window.Handler; if (handler == null) - handler = mauiContext.Handlers.GetHandler(window.GetType()) as IWindowHandler; + handler = mauiContext.Handlers.GetHandler(window.GetType()); if (handler == null) - throw new Exception($"Handler not found for view {window} or was not {nameof(IWindowHandler)}'"); + throw new Exception($"Handler not found for view {window}."); handler.SetMauiContext(mauiContext); From 8d0ad8d23efdb371112b8816c85309aca17093fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 20 Jul 2021 20:08:15 +0900 Subject: [PATCH 136/266] Fix build error (#60) --- src/Core/src/Animations/NativeTicker.Tizen.cs | 4 ++-- src/Core/src/Platform/Tizen/WrapperView.cs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Core/src/Animations/NativeTicker.Tizen.cs b/src/Core/src/Animations/NativeTicker.Tizen.cs index 6d7fc0495fae..2cba99d1f71c 100644 --- a/src/Core/src/Animations/NativeTicker.Tizen.cs +++ b/src/Core/src/Animations/NativeTicker.Tizen.cs @@ -19,7 +19,7 @@ public NativeTicker() } _context = SynchronizationContext.Current; - _timer = new Timer((object o) => HandleElapsed(o), this, Timeout.Infinite, Timeout.Infinite); + _timer = new Timer((object? o) => HandleElapsed(o), this, Timeout.Infinite, Timeout.Infinite); } public override void Start() @@ -34,7 +34,7 @@ public override void Stop() _isRunning = false; } - void HandleElapsed(object state) + void HandleElapsed(object? state) { _context?.Post((o) => Fire?.Invoke(), null); } diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index 119b6083d868..e213a930b60d 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -149,7 +149,11 @@ void OnClipPaint(object? sender, DrawClipEventArgs e) } } +<<<<<<< HEAD void OnLayout(object? sender, LayoutEventArgs e) +======= + void OnLayout(object? sender, Tizen.UIExtensions.Common.LayoutEventArgs e) +>>>>>>> 69d66e477 (Fix build error (#60)) { if (Content != null) { From 3d238cff5c7b3ee206c77a0152e898c923054d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 4 Aug 2021 09:31:29 +0900 Subject: [PATCH 137/266] Bump to latest (#71) - Window lifecycle (#1754) - Move New Navigation Handler to Core and make it internal (#1800) - Scrollview handler (#1669) - ScrollView Resize + Window Handler Resize (#1676) - Font AutoScalingEnabled (#1774) - Rename Font Properties (#1755) - Update layout system to ensure native measure/arrange are called for all controls, even from Page subclasses (#1819) - IContainer as IList (#1724) - Implement Layout padding for new StackLayouts and GridLayout (#1749) - Delete all the TabIndex, TabStop, Focusable things! (#1777) - Introduce SetSemanticFocus API via SemanticExtensions (#1829) - Improve Window and AnimationManager (#1653) - And so on --- .../NavigationPageHandler.Tizen.cs | 260 -------------- .../NavigationPageHandler.Tizen.cs | 327 ++++++++++++++++++ .../src/Platform/Tizen/CoreUIAppContext.cs | 2 +- .../src/Platform/Tizen/CoreUIAppExtensions.cs | 25 ++ .../src/Platform/Tizen/HandlerExtensions.cs | 4 +- .../src/Platform/Tizen/SemanticExtensions.cs | 19 + src/Core/src/Platform/Tizen/WrapperView.cs | 4 - 7 files changed, 374 insertions(+), 267 deletions(-) delete mode 100644 src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs create mode 100644 src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs create mode 100644 src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs create mode 100644 src/Core/src/Platform/Tizen/SemanticExtensions.cs diff --git a/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs deleted file mode 100644 index 188b64746ded..000000000000 --- a/src/Controls/src/Core/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs +++ /dev/null @@ -1,260 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Maui.Handlers; -using Microsoft.Maui.Controls.Internals; -using ElmSharp; -using Tizen.UIExtensions.ElmSharp; - -using TButton = Tizen.UIExtensions.ElmSharp.Button; -using TSpan = Tizen.UIExtensions.Common.Span; -using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; - -namespace Microsoft.Maui.Controls.Handlers -{ - public partial class NavigationPageHandler : - EViewHandler - { - readonly List _naviItemContentPartList = new List(); - TaskCompletionSource _currentTaskSource = null; - IDictionary _naviItemMap; - - Page PreviousPage => VirtualView.Navigation.NavigationStack.Count > 1 ? VirtualView.Navigation.NavigationStack[VirtualView.Navigation.NavigationStack.Count - 2] : null; - NaviItem CurrentNaviItem => NativeView.NavigationStack.Count > 0 ? NativeView.NavigationStack.Last() : null; - NaviItem PreviousNaviItem => NativeView.NavigationStack.Count > 1 ? NativeView.NavigationStack[NativeView.NavigationStack.Count - 2] : null; - - protected override Naviframe CreateNativeView() - { - return new Naviframe(NativeParent) - { - PreserveContentOnPop = true, - DefaultBackButtonEnabled = false, - }; - } - - protected override void ConnectHandler(Naviframe nativeView) - { - base.ConnectHandler(nativeView); - nativeView.AnimationFinished += OnAnimationFinished; - _naviItemMap = new Dictionary(); - - if (VirtualView == null) - return; - - VirtualView.PushRequested += OnPushRequested; - VirtualView.PopRequested += OnPopRequested; - VirtualView.InternalChildren.CollectionChanged += OnPageCollectionChanged; - - foreach (Page page in VirtualView.InternalChildren) - { - _naviItemMap[page] = NativeView.Push(CreateNavItem(page), SpanTitle(page.Title)); - page.PropertyChanged += NavigationBarPropertyChangedHandler; - - UpdateHasNavigationBar(page); - } - } - - protected override void DisconnectHandler(Naviframe nativeView) - { - base.DisconnectHandler(nativeView); - nativeView.AnimationFinished -= OnAnimationFinished; - - VirtualView.PushRequested -= OnPushRequested; - VirtualView.PopRequested -= OnPopRequested; - VirtualView.InternalChildren.CollectionChanged -= OnPageCollectionChanged; - } - - public static void MapPadding(NavigationPageHandler handler, NavigationPage view) { } - - public static void MapBarTextColor(NavigationPageHandler handler, NavigationPage view) - { - handler.UpdateTitle(view.CurrentPage); - } - - public static void MapBarBackground(NavigationPageHandler handler, NavigationPage view) { } - - public static void MapTitleIcon(NavigationPageHandler handler, NavigationPage view) { } - - public static void MapTitleView(NavigationPageHandler handler, NavigationPage view) { } - - void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) - { - // this handler is invoked only for child pages (contained on a navigation stack) - if (e.PropertyName == NavigationPage.HasNavigationBarProperty.PropertyName) - UpdateHasNavigationBar(sender as Page); - else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName || - e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) - UpdateHasBackButton(sender as Page); - else if (e.PropertyName == Page.TitleProperty.PropertyName) - UpdateTitle(sender as Page); - } - - void OnPageCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - { - if (e.OldItems != null) - foreach (Page page in e.OldItems) - page.PropertyChanged -= NavigationBarPropertyChangedHandler; - if (e.NewItems != null) - foreach (Page page in e.NewItems) - page.PropertyChanged += NavigationBarPropertyChangedHandler; - } - - void OnPushRequested(object sender, NavigationRequestedEventArgs nre) - { - if (nre.Animated || NativeView.NavigationStack.Count == 0) - { - _naviItemMap[nre.Page] = NativeView.Push(CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); - _currentTaskSource = new TaskCompletionSource(); - nre.Task = _currentTaskSource.Task; - - // There is no TransitionFinished (AnimationFinished) event after the first Push - if (NativeView.NavigationStack.Count == 1) - CompleteCurrentNavigationTask(); - } - else - { - _naviItemMap[nre.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); - } - UpdateHasNavigationBar(nre.Page); - } - - void OnPopRequested(object sender, NavigationRequestedEventArgs nre) - { - if (VirtualView.InternalChildren.Count == NativeView.NavigationStack.Count) - { - nre.Page?.SendDisappearing(); - UpdateNavigationBar(PreviousPage, PreviousNaviItem); - - if (nre.Animated) - { - NativeView.Pop(); - - _currentTaskSource = new TaskCompletionSource(); - nre.Task = _currentTaskSource.Task; - - // There is no TransitionFinished (AnimationFinished) event after Pop the last page - if (NativeView.NavigationStack.Count == 0) - CompleteCurrentNavigationTask(); - } - else - { - CurrentNaviItem?.Delete(); - } - - if (_naviItemMap.ContainsKey(nre.Page)) - _naviItemMap.Remove(nre.Page); - } - } - - void OnAnimationFinished(object sender, EventArgs e) - { - CompleteCurrentNavigationTask(); - } - - void CompleteCurrentNavigationTask() - { - if (_currentTaskSource != null) - { - var tmp = _currentTaskSource; - _currentTaskSource = null; - tmp.SetResult(true); - } - } - - void UpdateHasNavigationBar(Page page) - { - NaviItem item = GetNaviItemForPage(page); - item.SetTabBarStyle(); - item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty); - UpdateBarBackgroundColor(item); - } - - void UpdateNavigationBar(Page page, NaviItem item = null) - { - if (item == null) - item = GetNaviItemForPage(page); - - UpdateTitle(page, item); - UpdateBarBackgroundColor(item); - } - - void UpdateHasBackButton(Page page, NaviItem item = null) - { - if (item == null) - item = GetNaviItemForPage(page); - - TButton button = null; - - if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty) && NativeView.NavigationStack.Count > 1) - { - button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty)); - } - item.SetBackButton(button); - } - - void UpdateTitle(Page page, NaviItem item = null) - { - if (item == null) - item = GetNaviItemForPage(page); - - item.SetTitle(SpanTitle(page.Title)); - } - - string SpanTitle(string Title) - { - TSpan span = new TSpan - { - Text = Title, - HorizontalTextAlignment = TTextAlignment.Center, - ForegroundColor = VirtualView.BarTextColor.ToNative() - }; - return span.GetMarkupText(); - } - - void UpdateBarBackgroundColor(NaviItem item) - { - item.TitleBarBackgroundColor = VirtualView.BarBackgroundColor.ToNativeEFL(); - } - - TButton CreateNavigationButton(string text) - { - var button = new TButton(NativeParent) - { - Text = text - }; - button.SetNavigationBackStyle(); - button.Clicked += (sender, e) => - { - if (!VirtualView.SendBackButtonPressed()) - Tizen.Applications.Application.Current.Exit(); - }; - _naviItemContentPartList.Add(button); - button.Deleted += NaviItemPartContentDeletedHandler; - return button; - } - - void NaviItemPartContentDeletedHandler(object sender, EventArgs e) - { - _naviItemContentPartList.Remove(sender as Widget); - } - - NaviItem GetNaviItemForPage(Page page) - { - NaviItem item; - if (_naviItemMap.TryGetValue(page, out item)) - { - return item; - } - return null; - } - - EvasObject CreateNavItem(Page page) - { - //TODO: Fix me - EvasObject nativeView = (EvasObject)page.Handler.NativeView; - return nativeView; - } - } -} diff --git a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs new file mode 100644 index 000000000000..454a1084293c --- /dev/null +++ b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs @@ -0,0 +1,327 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using ElmSharp; +using Microsoft.Maui.Handlers; +using Tizen.UIExtensions.ElmSharp; +using TButton = Tizen.UIExtensions.ElmSharp.Button; +using TSpan = Tizen.UIExtensions.Common.Span; +using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; + +namespace Microsoft.Maui.Handlers +{ + internal partial class NavigationPageHandler : + ViewHandler, INativeViewHandler + { + readonly List _naviItemContentPartList = new List(); + TaskCompletionSource? _currentTaskSource = null; + IDictionary? _naviItemMap; + + IView? PreviousPage => VirtualView.NavigationStack.Count > 1 ? VirtualView.NavigationStack[VirtualView.NavigationStack.Count - 2] : null; + NaviItem? CurrentNaviItem => NativeView.NavigationStack.Count > 0 ? NativeView.NavigationStack.Last() : null; + NaviItem? PreviousNaviItem => NativeView.NavigationStack.Count > 1 ? NativeView.NavigationStack[NativeView.NavigationStack.Count - 2] : null; + + protected override Naviframe CreateNativeView() + { + return new Naviframe(NativeParent) + { + PreserveContentOnPop = true, + DefaultBackButtonEnabled = false, + }; + } + + private static void PushAsyncTo(NavigationPageHandler arg1, INavigationView arg2, object? arg3) + { + if (arg3 is MauiNavigationRequestedEventArgs args) + arg1.OnPushRequested(args); + } + + private static void PopAsyncTo(NavigationPageHandler arg1, INavigationView arg2, object? arg3) + { + if (arg3 is MauiNavigationRequestedEventArgs args) + arg1.OnPopRequested(args); + } + + void OnPushRequested(MauiNavigationRequestedEventArgs e) + { + _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); + + if (e.Animated || NativeView.NavigationStack.Count == 0) + { + _naviItemMap[e.Page] = NativeView.Push(CreateNavItem(e.Page), SpanTitle(e.Page)); + _currentTaskSource = new TaskCompletionSource(); + e.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after the first Push + if (NativeView.NavigationStack.Count == 1) + CompleteCurrentNavigationTask(); + } + else + { + _naviItemMap[e.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(e.Page), SpanTitle(e.Page)); + } + //UpdateHasNavigationBar(nre.Page); + } + + void OnPopRequested(MauiNavigationRequestedEventArgs e) + { + _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); + + if (VirtualView.NavigationStack.Count == NativeView.NavigationStack.Count) + { + //e.Page?.SendDisappearing(); + //UpdateNavigationBar(PreviousPage, PreviousNaviItem); + + if (e.Animated) + { + NativeView.Pop(); + + _currentTaskSource = new TaskCompletionSource(); + e.Task = _currentTaskSource.Task; + + // There is no TransitionFinished (AnimationFinished) event after Pop the last page + if (NativeView.NavigationStack.Count == 0) + CompleteCurrentNavigationTask(); + } + else + { + CurrentNaviItem?.Delete(); + } + + if (_naviItemMap.ContainsKey(e.Page)) + _naviItemMap.Remove(e.Page); + } + } + + protected override void ConnectHandler(Naviframe nativeView) + { + base.ConnectHandler(nativeView); + nativeView.AnimationFinished += OnAnimationFinished; + _naviItemMap = new Dictionary(); + + if (VirtualView == null) + return; + + //VirtualView.PushRequested += OnPushRequested; + //VirtualView.PopRequested += OnPopRequested; + //VirtualView.InternalChildren.CollectionChanged += OnPageCollectionChanged; + + foreach (var page in VirtualView.NavigationStack) + { + _naviItemMap[page] = NativeView.Push(CreateNavItem(page), SpanTitle(page)); + //page.PropertyChanged += NavigationBarPropertyChangedHandler; + + //UpdateHasNavigationBar(page); + } + } + + protected override void DisconnectHandler(Naviframe nativeView) + { + base.DisconnectHandler(nativeView); + nativeView.AnimationFinished -= OnAnimationFinished; + + //VirtualView.PushRequested -= OnPushRequested; + //VirtualView.PopRequested -= OnPopRequested; + //VirtualView.InternalChildren.CollectionChanged -= OnPageCollectionChanged; + } + + //public static void MapPadding(NavigationPageHandler handler, INavigationView view) { } + + //public static void MapBarTextColor(NavigationPageHandler handler, INavigationView view) + //{ + // //handler.UpdateTitle(view.CurrentPage); + //} + + public static void MapBarBackground(NavigationPageHandler handler, INavigationView view) { } + + public static void MapTitleIcon(NavigationPageHandler handler, INavigationView view) { } + + public static void MapTitleView(NavigationPageHandler handler, INavigationView view) { } + + //void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) + //{ + // // this handler is invoked only for child pages (contained on a navigation stack) + // if (e.PropertyName == INavigationView.HasNavigationBarProperty.PropertyName) + // UpdateHasNavigationBar(sender as Page); + // else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName || + // e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) + // UpdateHasBackButton(sender as Page); + // else if (e.PropertyName == Page.TitleProperty.PropertyName) + // UpdateTitle(sender as Page); + //} + + //void OnPageCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + //{ + // if (e.OldItems != null) + // foreach (Page page in e.OldItems) + // page.PropertyChanged -= NavigationBarPropertyChangedHandler; + // if (e.NewItems != null) + // foreach (Page page in e.NewItems) + // page.PropertyChanged += NavigationBarPropertyChangedHandler; + //} + + //void OnPushRequested(object sender, NavigationRequestedEventArgs nre) + //{ + // if (nre.Animated || NativeView.NavigationStack.Count == 0) + // { + // _naviItemMap[nre.Page] = NativeView.Push(CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); + // _currentTaskSource = new TaskCompletionSource(); + // nre.Task = _currentTaskSource.Task; + + // // There is no TransitionFinished (AnimationFinished) event after the first Push + // if (NativeView.NavigationStack.Count == 1) + // CompleteCurrentNavigationTask(); + // } + // else + // { + // _naviItemMap[nre.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); + // } + // UpdateHasNavigationBar(nre.Page); + //} + + //void OnPopRequested(object sender, NavigationRequestedEventArgs nre) + //{ + // if (VirtualView.InternalChildren.Count == NativeView.NavigationStack.Count) + // { + // nre.Page?.SendDisappearing(); + // UpdateNavigationBar(PreviousPage, PreviousNaviItem); + + // if (nre.Animated) + // { + // NativeView.Pop(); + + // _currentTaskSource = new TaskCompletionSource(); + // nre.Task = _currentTaskSource.Task; + + // // There is no TransitionFinished (AnimationFinished) event after Pop the last page + // if (NativeView.NavigationStack.Count == 0) + // CompleteCurrentNavigationTask(); + // } + // else + // { + // CurrentNaviItem?.Delete(); + // } + + // if (_naviItemMap.ContainsKey(nre.Page)) + // _naviItemMap.Remove(nre.Page); + // } + //} + + void OnAnimationFinished(object sender, EventArgs e) + { + CompleteCurrentNavigationTask(); + } + + void CompleteCurrentNavigationTask() + { + if (_currentTaskSource != null) + { + var tmp = _currentTaskSource; + _currentTaskSource = null; + tmp.SetResult(true); + } + } + + //void UpdateHasNavigationBar(IView page) + //{ + // NaviItem item = GetNaviItemForPage(page); + // item.SetTabBarStyle(); + // item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty); + // UpdateBarBackgroundColor(item); + //} + + //void UpdateNavigationBar(Page page, NaviItem item = null) + //{ + // if (item == null) + // item = GetNaviItemForPage(page); + + // UpdateTitle(page, item); + // UpdateBarBackgroundColor(item); + //} + + //void UpdateHasBackButton(Page page, NaviItem item = null) + //{ + // if (item == null) + // item = GetNaviItemForPage(page); + + // TButton button = null; + + // if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty) && NativeView.NavigationStack.Count > 1) + // { + // button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty)); + // } + // item.SetBackButton(button); + //} + + void UpdateTitle(IView page, NaviItem? item = null) + { + if (item == null) + item = GetNaviItemForPage(page); + + item?.SetTitle(SpanTitle(page)); + } + + string SpanTitle(IView view) + { + if (view is not IPage page) + return string.Empty; + else + { + var span = new TSpan + { + Text = page.Title, + HorizontalTextAlignment = TTextAlignment.Center, + //ForegroundColor = VirtualView.BarTextColor.ToNative() + }; + return span.GetMarkupText(); + } + } + + //void UpdateBarBackgroundColor(NaviItem item) + //{ + // item.TitleBarBackgroundColor = VirtualView.BarBackgroundColor.ToNativeEFL(); + //} + + //TButton CreateNavigationButton(string text) + //{ + // var button = new TButton(NativeParent) + // { + // Text = text + // }; + // button.SetNavigationBackStyle(); + // button.Clicked += (sender, e) => + // { + // if (!VirtualView.SendBackButtonPressed()) + // Tizen.Applications.Application.Current.Exit(); + // }; + // _naviItemContentPartList.Add(button); + // button.Deleted += NaviItemPartContentDeletedHandler; + // return button; + //} + + //void NaviItemPartContentDeletedHandler(object sender, EventArgs e) + //{ + // _naviItemContentPartList.Remove(sender as Widget); + //} + + NaviItem? GetNaviItemForPage(IView page) + { + _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); + + NaviItem item; + if (_naviItemMap.TryGetValue(page, out item)) + { + return item; + } + return null; + } + + EvasObject CreateNavItem(IView page) + { + return page.ToNative(MauiContext!); + } + } +} diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index f321eeaf1dcc..f5eb0bebe300 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -100,7 +100,7 @@ public void SetContent(EvasObject content) static Window CreateDefaultWindow() { - return GetPreloadedWindow() ?? new Window("XamarinWindow"); + return GetPreloadedWindow() ?? new Window("MauiDefaultWindow"); } static Window? GetPreloadedWindow() diff --git a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs new file mode 100644 index 000000000000..c730e41e1cbb --- /dev/null +++ b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs @@ -0,0 +1,25 @@ +using System; +using Tizen.Applications; +using EWindow = ElmSharp.Window; + +namespace Microsoft.Maui +{ + internal static class CoreUIAppExtensions + { + public static IWindow GetWindow(this CoreUIApplication application) + { + if (MauiApplication.Current.VirtualWindow != null) + return MauiApplication.Current.VirtualWindow; + + var nativeWindow = MauiApplication.Current.MainWindow; + + foreach (var window in MauiApplication.Current.Application.Windows) + { + if (window?.Handler?.NativeView is EWindow win && win == nativeWindow) + return window; + } + + throw new InvalidOperationException("Window Not Found"); + } + } +} diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 972948d30527..0118177993e1 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -19,10 +19,10 @@ public static EvasObject ToNative(this IView view, IMauiContext context, bool is var handler = view.Handler; if (handler == null) - handler = context.Handlers.GetHandler(view.GetType()) as IViewHandler; + handler = context.Handlers.GetHandler(view.GetType()); if (handler == null) - throw new Exception($"Handler not found for view {view} or was not {nameof(IViewHandler)}."); + throw new Exception($"Handler not found for view {view}."); handler.SetMauiContext(context); diff --git a/src/Core/src/Platform/Tizen/SemanticExtensions.cs b/src/Core/src/Platform/Tizen/SemanticExtensions.cs new file mode 100644 index 000000000000..f641969d5648 --- /dev/null +++ b/src/Core/src/Platform/Tizen/SemanticExtensions.cs @@ -0,0 +1,19 @@ +using System; +using ElmSharp.Accessible; + +namespace Microsoft.Maui +{ + public static partial class SemanticExtensions + { + public static void SetSemanticFocus(this IFrameworkElement element) + { + if (element?.Handler?.NativeView == null) + throw new NullReferenceException("Can't access view from a null handler"); + + if (element.Handler.NativeView is not AccessibleObject) + return; + + //TODO : Need to implement + } + } +} diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index e213a930b60d..119b6083d868 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -149,11 +149,7 @@ void OnClipPaint(object? sender, DrawClipEventArgs e) } } -<<<<<<< HEAD void OnLayout(object? sender, LayoutEventArgs e) -======= - void OnLayout(object? sender, Tizen.UIExtensions.Common.LayoutEventArgs e) ->>>>>>> 69d66e477 (Fix build error (#60)) { if (Content != null) { From 13aaf49ce01525d85ddc32735caa1ed065b0189e Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 20 Aug 2021 09:02:33 +0900 Subject: [PATCH 138/266] Bump to latest --- ...rosoft.Maui.Controls.SingleProject.targets | 55 ++++++------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/.nuspec/Microsoft.Maui.Controls.SingleProject.targets b/.nuspec/Microsoft.Maui.Controls.SingleProject.targets index 15f98664a1a3..afd4ea57f211 100644 --- a/.nuspec/Microsoft.Maui.Controls.SingleProject.targets +++ b/.nuspec/Microsoft.Maui.Controls.SingleProject.targets @@ -68,40 +68,6 @@ $(TizenProjectFolder)shared - - - - true - - - - - false - - - false - - - false - - - false - - - false - - - + - + + + + + + + Condition=" '$(TargetPlatformIdentifier)' == 'tizen' and '$(TizenProjectFolder)' != '' " + Include="$(TizenProjectFolder)**/*$(DefaultLanguageSourceExtension)" /> <_MauiXamlToRemove From 0d5459df346da574f040cb25f4d2705b17178956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 23 Aug 2021 16:51:01 +0900 Subject: [PATCH 139/266] Fix Essentials sample (#108) * Fix Essentials sample for Tizen * Remove UseSkiaSharp flag * Remove MaterialComponents * Fix Tizen flag * Remove CustomRenderer --- src/Essentials/samples/Samples/Platforms/Tizen/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs b/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs index 4602bc64c8f2..ba600d072e83 100644 --- a/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs +++ b/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs @@ -13,4 +13,4 @@ static void Main(string[] args) app.Run(args); } } -} +} \ No newline at end of file From 6a1fe15fbf2e9876d86ecb9aab9cb6beb4ee15fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=B1=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 23 Aug 2021 19:15:02 +0900 Subject: [PATCH 140/266] Add ShellHandler (#64) * Add ShellHandler * Move ShellView into Platform/Tizen * Update ShellView * Move the code for embedded tizen resources to csproj * Add UIExtenstions for shell --- src/Controls/src/Core/Controls.Core.csproj | 1 - .../Tizen/Extensions/ShellExtensions.cs | 2 +- .../Platform/Tizen/Shell/ShellSectionView.cs | 376 ++++++++++++++++++ .../Tizen.UIExtensions/INavigationView.cs | 24 ++ .../Tizen/Shell/Tizen.UIExtensions/ITabs.cs | 30 ++ .../Tizen.UIExtensions/NavigationView.cs | 205 ++++++++++ .../Tizen/Shell/Tizen.UIExtensions/Tabs.cs | 35 ++ .../Tizen.UIExtensions/ThemeConstants.cs | 25 ++ 8 files changed, 696 insertions(+), 2 deletions(-) create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs diff --git a/src/Controls/src/Core/Controls.Core.csproj b/src/Controls/src/Core/Controls.Core.csproj index 69c0f1afe34d..95cc0ebaa22d 100644 --- a/src/Controls/src/Core/Controls.Core.csproj +++ b/src/Controls/src/Core/Controls.Core.csproj @@ -22,7 +22,6 @@ - diff --git a/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs index fc30d0f8f202..53b70de2c3d3 100644 --- a/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs @@ -14,4 +14,4 @@ public static DrawerBehavior ToPlatform(this FlyoutBehavior behavior) return DrawerBehavior.Drawer; } } -} \ No newline at end of file +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs new file mode 100644 index 000000000000..8ecd27799ed1 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionView.cs @@ -0,0 +1,376 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; +using Tizen.UIExtensions.Shell; +using EBox = ElmSharp.Box; +using EColor = ElmSharp.Color; +using EToolbarItem = ElmSharp.ToolbarItem; +using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; + +namespace Microsoft.Maui.Controls.Platform +{ + public interface IShellSectionRenderer : IDisposable + { + EvasObject NativeView { get; } + } + + public class ShellSectionView : IAppearanceObserver, IShellSectionRenderer + { + EBox _mainLayout = null; + EBox _contentArea = null; + Tabs _tabs = null; + EvasObject _currentContent = null; + Page _displayedPage; + + Dictionary _contentCache = new Dictionary(); + Dictionary _contentToTabsItem = new Dictionary(); + Dictionary _itemToContent = new Dictionary(); + List _tabsItems = new List(); + + EColor _backgroundColor = ShellView.DefaultBackgroundColor; + EColor _foregroundColor = ShellView.DefaultForegroundColor; + + bool _disposed = false; + + public ShellSectionView(ShellSection section, IMauiContext context) + { + ShellSection = section; + MauiContext = context; + ShellSection.PropertyChanged += OnSectionPropertyChanged; + (ShellSection.Items as INotifyCollectionChanged).CollectionChanged += OnShellSectionCollectionChanged; + + _mainLayout = new EBox(NativeParent); + _mainLayout.SetLayoutCallback(OnLayout); + + _contentArea = new EBox(NativeParent); + _contentArea.Show(); + _mainLayout.PackEnd(_contentArea); + + UpdateTabsItem(); + UpdateCurrentItem(ShellSection.CurrentItem); + + ((IShellController)Shell.Current).AddAppearanceObserver(this, ShellSection); + (ShellSection as IShellSectionController).AddDisplayedPageObserver(this, UpdateDisplayedPage); + } + + bool HasTabs => _tabs != null; + + bool _tabBarIsVisible = true; + + protected IMauiContext MauiContext { get; private set; } + + protected EvasObject NativeParent + { + get => MauiContext?.Context?.BaseLayout; + } + + protected virtual bool TabBarIsVisible + { + get => _tabBarIsVisible; + set + { + if (_tabBarIsVisible != value) + { + _tabBarIsVisible = value; + _mainLayout.MarkChanged(); + + if (value) + { + _tabs?.Show(); + } + else + { + _tabs?.Hide(); + } + } + } + } + + public ShellSection ShellSection { get; } + + public EvasObject NativeView + { + get + { + return _mainLayout; + } + } + + public EColor ToolbarBackgroundColor + { + get + { + return _backgroundColor; + } + set + { + _backgroundColor = value; + UpdateToolbarBackgroudColor(_backgroundColor); + } + } + + public EColor ToolbarForegroundColor + { + get + { + return _foregroundColor; + } + set + { + _foregroundColor = value; + UpdateToolbarForegroundColor(_foregroundColor); + } + } + + ~ShellSectionView() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance) + { + var backgroundColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarBackgroundColor; + var foregroundColor = appearance?.ForegroundColor; + ToolbarBackgroundColor = backgroundColor.IsDefault() ? ShellView.DefaultBackgroundColor : backgroundColor.ToNativeEFL(); + ToolbarForegroundColor = foregroundColor.IsDefault() ? ShellView.DefaultForegroundColor : foregroundColor.ToNativeEFL(); + } + + void UpdateDisplayedPage(Page page) + { + if (_displayedPage != null) + { + _displayedPage.PropertyChanged -= OnDisplayedPagePropertyChanged; + } + + if (page == null) + { + TabBarIsVisible = true; + return; + } + _displayedPage = page; + _displayedPage.PropertyChanged += OnDisplayedPagePropertyChanged; + TabBarIsVisible = Shell.GetTabBarIsVisible(page); + } + + void OnDisplayedPagePropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == Shell.TabBarIsVisibleProperty.PropertyName) + { + TabBarIsVisible = Shell.GetTabBarIsVisible(_displayedPage); + } + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + ((IShellController)Shell.Current).RemoveAppearanceObserver(this); + if (ShellSection != null) + { + (ShellSection as IShellSectionController).RemoveDisplayedPageObserver(this); + ShellSection.PropertyChanged -= OnSectionPropertyChanged; + DeinitializeTabs(); + + foreach (var native in _contentCache.Values) + { + native.Unrealize(); + } + _contentCache.Clear(); + _contentToTabsItem.Clear(); + _itemToContent.Clear(); + } + NativeView.Unrealize(); + } + _disposed = true; + } + + void InitializeTabs() + { + if (_tabs != null) + { + return; + } + _tabs = new Tabs(NativeParent); + _tabs.Show(); + _tabs.BackgroundColor = _backgroundColor; + _tabs.Scrollable = TabsType.Fixed; + _tabs.Selected += OnTabsSelected; + _mainLayout.PackEnd(_tabs); + } + + void ClearTabsItem() + { + if (!HasTabs) + return; + + foreach (var item in _tabsItems) + { + item.Delete(); + } + _tabsItems.Clear(); + _contentToTabsItem.Clear(); + _itemToContent.Clear(); + } + + void DeinitializeTabs() + { + if (_tabs == null) + { + return; + } + ClearTabsItem(); + _tabs.Unrealize(); + _tabs = null; + } + + void OnSectionPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "CurrentItem") + { + UpdateCurrentItem(ShellSection.CurrentItem); + } + } + + void UpdateCurrentItem(ShellContent content) + { + UpdateCurrentShellContent(content); + if (_contentToTabsItem.ContainsKey(content)) + { + _contentToTabsItem[content].IsSelected = true; + } + } + + void UpdateToolbarBackgroudColor(EColor color) + { + foreach (EToolbarItem item in _tabsItems) + { + item.SetBackgroundColor(color); + } + } + + void UpdateToolbarForegroundColor(EColor color) + { + foreach (EToolbarItem item in _tabsItems) + { + item.SetUnderlineColor(color); + } + } + + void UpdateTabsItem() + { + if (ShellSection.Items.Count <= 1) + { + DeinitializeTabs(); + return; + } + + InitializeTabs(); + ClearTabsItem(); + foreach (ShellContent content in ShellSection.Items) + { + InsertTabsItem(content); + } + _tabs.Scrollable = ShellSection.Items.Count > 3 ? TabsType.Scrollable : TabsType.Fixed; + } + + EToolbarItem InsertTabsItem(ShellContent content) + { + EToolbarItem item = _tabs.Append(content.Title, null); + item.SetBackgroundColor(_backgroundColor); + item.SetUnderlineColor(_foregroundColor); + + _tabsItems.Add(item); + _itemToContent[item] = content; + _contentToTabsItem[content] = item; + return item; + } + + void OnShellSectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + UpdateTabsItem(); + } + + void OnTabsSelected(object sender, EToolbarItemEventArgs e) + { + if (_tabs.SelectedItem == null) + { + return; + } + + ShellContent content = _itemToContent[_tabs.SelectedItem]; + if (ShellSection.CurrentItem != content) + { + ShellSection.SetValueFromRenderer(ShellSection.CurrentItemProperty, content); + } + } + + void UpdateCurrentShellContent(ShellContent content) + { + if (_currentContent != null) + { + _currentContent.Hide(); + _contentArea.UnPack(_currentContent); + _currentContent = null; + } + + if (content == null) + { + return; + } + + if (!_contentCache.ContainsKey(content)) + { + var native = CreateShellContent(content); + native.SetAlignment(-1, -1); + native.SetWeight(1, 1); + _contentCache[content] = native; + } + _currentContent = _contentCache[content]; + _currentContent.Show(); + _contentArea.PackEnd(_currentContent); + } + + EvasObject CreateShellContent(ShellContent content) + { + Page xpage = ((IShellContentController)content).GetOrCreateContent(); + return xpage.ToNative(MauiContext); + } + + void OnLayout() + { + if (NativeView.Geometry.Width == 0 || NativeView.Geometry.Height == 0) + return; + var bound = NativeView.Geometry; + + int tabsHeight; + if (HasTabs && TabBarIsVisible) + { + var tabsBound = bound; + tabsHeight = _tabs.MinimumHeight; + tabsBound.Height = tabsHeight; + _tabs.Geometry = tabsBound; + } + else + { + tabsHeight = 0; + } + + var contentBound = bound; + contentBound.Y += tabsHeight; + contentBound.Height -= tabsHeight; + _contentArea.Geometry = contentBound; + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs new file mode 100644 index 000000000000..8a89f957ee94 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/INavigationView.cs @@ -0,0 +1,24 @@ +using System; +using ElmSharp; +using Tizen.UIExtensions.Common; +using EColor = ElmSharp.Color; + +namespace Tizen.UIExtensions.Shell +{ + public interface INavigationView + { + EvasObject TargetView { get; } + + EvasObject Header { get; set; } + + EvasObject Footer { get; set; } + + EvasObject Content { get; set; } + + EColor BackgroundColor { get; set; } + + EvasObject BackgroundImage { get; set; } + + event EventHandler LayoutUpdated; + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs new file mode 100644 index 000000000000..2f7c7c1c6223 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ITabs.cs @@ -0,0 +1,30 @@ +using System; +using ElmSharp; +using EColor = ElmSharp.Color; +using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; + +namespace Tizen.UIExtensions.Shell +{ + public interface ITabs + { + TabsType Scrollable { get; set; } + + EColor BackgroundColor { get; set; } + + ToolbarItem SelectedItem { get; } + + event EventHandler Selected; + + ToolbarItem Append(string label, string icon); + + ToolbarItem Append(string label); + + ToolbarItem InsertBefore(ToolbarItem before, string label, string icon); + } + + public enum TabsType + { + Fixed, + Scrollable + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs new file mode 100644 index 000000000000..72fcb594a9ca --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/NavigationView.cs @@ -0,0 +1,205 @@ +using ElmSharp; +using System; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using EColor = ElmSharp.Color; +using EBox = ElmSharp.Box; + +namespace Tizen.UIExtensions.Shell +{ + /// + /// The native widget that is configured with an header and an list of items to be used in NavigationDrawer. + /// + public class NavigationView : Background, INavigationView + { + static readonly EColor s_defaultBackgroundColor = ElmSharp.ThemeConstants.Shell.ColorClass.DefaultNavigationViewBackgroundColor; + + EBox _mainLayout; + + EvasObject _header; + EvasObject _footer; + EvasObject _content; + + EvasObject _backgroundImage; + EColor _backgroundColor; + + /// + /// Initializes a new instance of the class. + /// + /// Parent evas object. + public NavigationView(EvasObject parent) : base(parent) + { + InitializeComponent(parent); + } + + /// + /// Gets or sets the background color of the NavigtiaonView. + /// + public override EColor BackgroundColor + { + get => _backgroundColor; + set + { + _backgroundColor = value; + EColor effectiveColor = _backgroundColor.IsDefault ? s_defaultBackgroundColor : _backgroundColor; + base.BackgroundColor = effectiveColor; + } + } + + /// + /// Gets or sets the background image of the NavigtiaonView. + /// + public EvasObject BackgroundImage + { + get => _backgroundImage; + set + { + _backgroundImage = value; + this.SetBackgroundPart(_backgroundImage); + } + } + + /// + /// Gets or sets the header view of the NavigtiaonView. + /// + public EvasObject Header + { + get => _header; + set => UpdateHeader(value); + } + + /// + /// Gets or sets the footer view of the NavigtiaonView. + /// + public EvasObject Footer + { + get => _footer; + set => UpdateFooter(value); + } + + public EvasObject Content + { + get => _content; + set => UpdateContent(value); + } + + /// + /// Gets or sets the target view of the NavigtiaonView. + /// + public EvasObject TargetView => this; + + /// + /// Notifies that the layout has been updated. + /// + public event EventHandler LayoutUpdated; + + void InitializeComponent(EvasObject parent) + { + base.BackgroundColor = s_defaultBackgroundColor; + + _mainLayout = new EBox(parent) + { + AlignmentX = -1, + AlignmentY = -1, + WeightX = 1, + WeightY = 1 + }; + _mainLayout.SetLayoutCallback(OnLayout); + _mainLayout.Show(); + + SetContent(_mainLayout); + } + + void OnLayout() + { + if (Geometry.Width == 0 || Geometry.Height == 0) + return; + + var bound = Geometry; + int headerHeight = 0; + int footerHeight = 0; + + if (_header != null) + { + var headerBound = bound; + headerHeight = _header.MinimumHeight; + headerBound.Height = headerHeight; + _header.Geometry = headerBound; + } + + if (_footer != null) + { + var footerbound = bound; + footerHeight = _footer.MinimumHeight; + footerbound.Y = bound.Y + bound.Height - footerHeight; + footerbound.Height = footerHeight; + _footer.Geometry = footerbound; + } + + if (_content != null) + { + bound.Y += headerHeight; + bound.Height = bound.Height - headerHeight - footerHeight; + _content.Geometry = bound; + } + + NotifyOnLayout(); + } + + void NotifyOnLayout() + { + LayoutUpdated?.Invoke(this, new LayoutEventArgs() { Geometry = Geometry.ToCommon() }); + } + + void UpdateHeader(EvasObject header) + { + if (_header != null) + { + _mainLayout.UnPack(_header); + _header.Unrealize(); + _header = null; + } + + if (header != null) + { + _mainLayout.PackStart(header); + } + _header = header; + _header?.Show(); + } + + void UpdateFooter(EvasObject footer) + { + if (_footer != null) + { + _mainLayout.UnPack(_footer); + _footer.Unrealize(); + _footer = null; + } + + if (footer != null) + { + _mainLayout.PackEnd(footer); + } + _footer = footer; + _footer?.Show(); + } + + void UpdateContent(EvasObject content) + { + if (_content != null) + { + _mainLayout.UnPack(_content); + _content.Unrealize(); + _content = null; + } + + if (content != null) + { + _mainLayout.PackEnd(content); + } + _content = content; + _content?.Show(); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs new file mode 100644 index 000000000000..0046969b13cb --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/Tabs.cs @@ -0,0 +1,35 @@ +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; +using EToolbar = ElmSharp.Toolbar; + +namespace Tizen.UIExtensions.Shell +{ + public class Tabs : EToolbar, ITabs + { + TabsType _type; + + public Tabs(EvasObject parent) : base(parent) + { + Style = ElmSharp.ThemeConstants.Toolbar.Styles.Material; + SelectionMode = ToolbarSelectionMode.Always; + } + + public TabsType Scrollable + { + get => _type; + set + { + switch (value) + { + case TabsType.Fixed: + this.ShrinkMode = ToolbarShrinkMode.Expand; + break; + case TabsType.Scrollable: + this.ShrinkMode = ToolbarShrinkMode.Scroll; + break; + } + _type = value; + } + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs new file mode 100644 index 000000000000..b91c87d53211 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/Tizen.UIExtensions/ThemeConstants.cs @@ -0,0 +1,25 @@ +using EColor = ElmSharp.Color; + +namespace Tizen.UIExtensions.Shell +{ + public class ThemeConstants + { + public class Shell + { + public class ColorClass + { + public static readonly EColor DefaultBackgroundColor = EColor.FromRgb(33, 150, 243); + public static readonly EColor DefaultForegroundColor = EColor.White; + public static readonly EColor DefaultTitleColor = EColor.White; + } + + public class Resources + { + // The source of icon resources is https://materialdesignicons.com/ + public const string MenuIcon = "Platform.Tizen.Resources.menu.png"; + public const string BackIcon = "Platform.Tizen.Resources.arrow_left.png"; + public const string DotsIcon = "Platform.Tizen.Resources.dots_horizontal.png"; + } + } + } +} From 301e269fec11a6ba48872ef0268ff524ac954fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EA=B0=95=ED=98=B8/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Principal=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Thu, 26 Aug 2021 10:39:25 +0900 Subject: [PATCH 141/266] MAUI workload for Tizen (#66) --- .../MauiApp1/Platforms/Tizen/Main.cs | 21 +++++++++++++++++++ .../Platforms/Tizen/tizen-manifest.xml | 15 +++++++++++++ .../MauiApp1/Platforms/Tizen/Main.cs | 21 +++++++++++++++++++ .../Platforms/Tizen/tizen-manifest.xml | 15 +++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs create mode 100644 src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml create mode 100644 src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs create mode 100644 src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs new file mode 100644 index 000000000000..731ac52155eb --- /dev/null +++ b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/Main.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Compatibility; + +namespace MauiApp1 +{ + class Program : MauiApplication + { + protected override void OnCreate() + { + base.OnCreate(); + } + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 000000000000..5847c71b195d --- /dev/null +++ b/src/Templates/src/templates/maui-blazor/MauiApp1/Platforms/Tizen/tizen-manifest.xml @@ -0,0 +1,15 @@ + + + + + + appicon.xhigh.png + + + + + http://tizen.org/privilege/internet + + + + \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs new file mode 100644 index 000000000000..731ac52155eb --- /dev/null +++ b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/Main.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Compatibility; + +namespace MauiApp1 +{ + class Program : MauiApplication + { + protected override void OnCreate() + { + base.OnCreate(); + } + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 000000000000..5847c71b195d --- /dev/null +++ b/src/Templates/src/templates/maui-mobile/MauiApp1/Platforms/Tizen/tizen-manifest.xml @@ -0,0 +1,15 @@ + + + + + + appicon.xhigh.png + + + + + http://tizen.org/privilege/internet + + + + \ No newline at end of file From 2f16797529aab05c2c9d2fbc03a10da34a6feb71 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 26 Aug 2021 14:30:07 +0900 Subject: [PATCH 142/266] Fix build and runtime error after bumping to latest code --- src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs index 1a23e85c1195..c5fedd297668 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs @@ -58,6 +58,10 @@ public static Task MapImageSourceAsync(IButtonHandler handler, IImageButton imag return handler.ImageSourceLoader.UpdateImageSourceAsync(); } + //TODO : Need to impl + [MissingMapper] + public static void MapImageSource(ButtonHandler handler, IButton image) { } + [MissingMapper] public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button) { } From d97428b1ed02adea18ec465e4c4e18ec0d3255d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Wed, 1 Sep 2021 18:27:32 +0900 Subject: [PATCH 143/266] Fix Essentials (#146) * Fix Essentials sample for tizen * Add SemanticScreenReader for Tizen * Fix Startup --- .../SemanticScreenReader.netstandard.tvos.watchos.macos.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Essentials/src/SemanticScreenReader/SemanticScreenReader.netstandard.tvos.watchos.macos.cs b/src/Essentials/src/SemanticScreenReader/SemanticScreenReader.netstandard.tvos.watchos.macos.cs index f875fe72ee80..46fbf8d1e64a 100644 --- a/src/Essentials/src/SemanticScreenReader/SemanticScreenReader.netstandard.tvos.watchos.macos.cs +++ b/src/Essentials/src/SemanticScreenReader/SemanticScreenReader.netstandard.tvos.watchos.macos.cs @@ -7,7 +7,7 @@ namespace Microsoft.Maui.Accessibility { partial class SemanticScreenReaderImplementation : ISemanticScreenReader { - public void Announce(string text) => + static void PlatformAnnounce(string text) => throw ExceptionUtils.NotSupportedOrImplementedException; } } From ef9fd0f4abdc753b69deee404f7667d3258ac0d5 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 2 Sep 2021 13:59:06 +0900 Subject: [PATCH 144/266] Adds missing implementation after bumping to latest main --- .../NavigationPageHandler.Tizen.cs | 327 ------------------ 1 file changed, 327 deletions(-) delete mode 100644 src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs diff --git a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs b/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs deleted file mode 100644 index 454a1084293c..000000000000 --- a/src/Core/src/Handlers/NavigationPage/NavigationPageHandler.Tizen.cs +++ /dev/null @@ -1,327 +0,0 @@ -#nullable enable - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using ElmSharp; -using Microsoft.Maui.Handlers; -using Tizen.UIExtensions.ElmSharp; -using TButton = Tizen.UIExtensions.ElmSharp.Button; -using TSpan = Tizen.UIExtensions.Common.Span; -using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; - -namespace Microsoft.Maui.Handlers -{ - internal partial class NavigationPageHandler : - ViewHandler, INativeViewHandler - { - readonly List _naviItemContentPartList = new List(); - TaskCompletionSource? _currentTaskSource = null; - IDictionary? _naviItemMap; - - IView? PreviousPage => VirtualView.NavigationStack.Count > 1 ? VirtualView.NavigationStack[VirtualView.NavigationStack.Count - 2] : null; - NaviItem? CurrentNaviItem => NativeView.NavigationStack.Count > 0 ? NativeView.NavigationStack.Last() : null; - NaviItem? PreviousNaviItem => NativeView.NavigationStack.Count > 1 ? NativeView.NavigationStack[NativeView.NavigationStack.Count - 2] : null; - - protected override Naviframe CreateNativeView() - { - return new Naviframe(NativeParent) - { - PreserveContentOnPop = true, - DefaultBackButtonEnabled = false, - }; - } - - private static void PushAsyncTo(NavigationPageHandler arg1, INavigationView arg2, object? arg3) - { - if (arg3 is MauiNavigationRequestedEventArgs args) - arg1.OnPushRequested(args); - } - - private static void PopAsyncTo(NavigationPageHandler arg1, INavigationView arg2, object? arg3) - { - if (arg3 is MauiNavigationRequestedEventArgs args) - arg1.OnPopRequested(args); - } - - void OnPushRequested(MauiNavigationRequestedEventArgs e) - { - _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); - - if (e.Animated || NativeView.NavigationStack.Count == 0) - { - _naviItemMap[e.Page] = NativeView.Push(CreateNavItem(e.Page), SpanTitle(e.Page)); - _currentTaskSource = new TaskCompletionSource(); - e.Task = _currentTaskSource.Task; - - // There is no TransitionFinished (AnimationFinished) event after the first Push - if (NativeView.NavigationStack.Count == 1) - CompleteCurrentNavigationTask(); - } - else - { - _naviItemMap[e.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(e.Page), SpanTitle(e.Page)); - } - //UpdateHasNavigationBar(nre.Page); - } - - void OnPopRequested(MauiNavigationRequestedEventArgs e) - { - _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); - - if (VirtualView.NavigationStack.Count == NativeView.NavigationStack.Count) - { - //e.Page?.SendDisappearing(); - //UpdateNavigationBar(PreviousPage, PreviousNaviItem); - - if (e.Animated) - { - NativeView.Pop(); - - _currentTaskSource = new TaskCompletionSource(); - e.Task = _currentTaskSource.Task; - - // There is no TransitionFinished (AnimationFinished) event after Pop the last page - if (NativeView.NavigationStack.Count == 0) - CompleteCurrentNavigationTask(); - } - else - { - CurrentNaviItem?.Delete(); - } - - if (_naviItemMap.ContainsKey(e.Page)) - _naviItemMap.Remove(e.Page); - } - } - - protected override void ConnectHandler(Naviframe nativeView) - { - base.ConnectHandler(nativeView); - nativeView.AnimationFinished += OnAnimationFinished; - _naviItemMap = new Dictionary(); - - if (VirtualView == null) - return; - - //VirtualView.PushRequested += OnPushRequested; - //VirtualView.PopRequested += OnPopRequested; - //VirtualView.InternalChildren.CollectionChanged += OnPageCollectionChanged; - - foreach (var page in VirtualView.NavigationStack) - { - _naviItemMap[page] = NativeView.Push(CreateNavItem(page), SpanTitle(page)); - //page.PropertyChanged += NavigationBarPropertyChangedHandler; - - //UpdateHasNavigationBar(page); - } - } - - protected override void DisconnectHandler(Naviframe nativeView) - { - base.DisconnectHandler(nativeView); - nativeView.AnimationFinished -= OnAnimationFinished; - - //VirtualView.PushRequested -= OnPushRequested; - //VirtualView.PopRequested -= OnPopRequested; - //VirtualView.InternalChildren.CollectionChanged -= OnPageCollectionChanged; - } - - //public static void MapPadding(NavigationPageHandler handler, INavigationView view) { } - - //public static void MapBarTextColor(NavigationPageHandler handler, INavigationView view) - //{ - // //handler.UpdateTitle(view.CurrentPage); - //} - - public static void MapBarBackground(NavigationPageHandler handler, INavigationView view) { } - - public static void MapTitleIcon(NavigationPageHandler handler, INavigationView view) { } - - public static void MapTitleView(NavigationPageHandler handler, INavigationView view) { } - - //void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e) - //{ - // // this handler is invoked only for child pages (contained on a navigation stack) - // if (e.PropertyName == INavigationView.HasNavigationBarProperty.PropertyName) - // UpdateHasNavigationBar(sender as Page); - // else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName || - // e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) - // UpdateHasBackButton(sender as Page); - // else if (e.PropertyName == Page.TitleProperty.PropertyName) - // UpdateTitle(sender as Page); - //} - - //void OnPageCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) - //{ - // if (e.OldItems != null) - // foreach (Page page in e.OldItems) - // page.PropertyChanged -= NavigationBarPropertyChangedHandler; - // if (e.NewItems != null) - // foreach (Page page in e.NewItems) - // page.PropertyChanged += NavigationBarPropertyChangedHandler; - //} - - //void OnPushRequested(object sender, NavigationRequestedEventArgs nre) - //{ - // if (nre.Animated || NativeView.NavigationStack.Count == 0) - // { - // _naviItemMap[nre.Page] = NativeView.Push(CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); - // _currentTaskSource = new TaskCompletionSource(); - // nre.Task = _currentTaskSource.Task; - - // // There is no TransitionFinished (AnimationFinished) event after the first Push - // if (NativeView.NavigationStack.Count == 1) - // CompleteCurrentNavigationTask(); - // } - // else - // { - // _naviItemMap[nre.Page] = NativeView.InsertAfter(NativeView.NavigationStack.Last(), CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); - // } - // UpdateHasNavigationBar(nre.Page); - //} - - //void OnPopRequested(object sender, NavigationRequestedEventArgs nre) - //{ - // if (VirtualView.InternalChildren.Count == NativeView.NavigationStack.Count) - // { - // nre.Page?.SendDisappearing(); - // UpdateNavigationBar(PreviousPage, PreviousNaviItem); - - // if (nre.Animated) - // { - // NativeView.Pop(); - - // _currentTaskSource = new TaskCompletionSource(); - // nre.Task = _currentTaskSource.Task; - - // // There is no TransitionFinished (AnimationFinished) event after Pop the last page - // if (NativeView.NavigationStack.Count == 0) - // CompleteCurrentNavigationTask(); - // } - // else - // { - // CurrentNaviItem?.Delete(); - // } - - // if (_naviItemMap.ContainsKey(nre.Page)) - // _naviItemMap.Remove(nre.Page); - // } - //} - - void OnAnimationFinished(object sender, EventArgs e) - { - CompleteCurrentNavigationTask(); - } - - void CompleteCurrentNavigationTask() - { - if (_currentTaskSource != null) - { - var tmp = _currentTaskSource; - _currentTaskSource = null; - tmp.SetResult(true); - } - } - - //void UpdateHasNavigationBar(IView page) - //{ - // NaviItem item = GetNaviItemForPage(page); - // item.SetTabBarStyle(); - // item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty); - // UpdateBarBackgroundColor(item); - //} - - //void UpdateNavigationBar(Page page, NaviItem item = null) - //{ - // if (item == null) - // item = GetNaviItemForPage(page); - - // UpdateTitle(page, item); - // UpdateBarBackgroundColor(item); - //} - - //void UpdateHasBackButton(Page page, NaviItem item = null) - //{ - // if (item == null) - // item = GetNaviItemForPage(page); - - // TButton button = null; - - // if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty) && NativeView.NavigationStack.Count > 1) - // { - // button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty)); - // } - // item.SetBackButton(button); - //} - - void UpdateTitle(IView page, NaviItem? item = null) - { - if (item == null) - item = GetNaviItemForPage(page); - - item?.SetTitle(SpanTitle(page)); - } - - string SpanTitle(IView view) - { - if (view is not IPage page) - return string.Empty; - else - { - var span = new TSpan - { - Text = page.Title, - HorizontalTextAlignment = TTextAlignment.Center, - //ForegroundColor = VirtualView.BarTextColor.ToNative() - }; - return span.GetMarkupText(); - } - } - - //void UpdateBarBackgroundColor(NaviItem item) - //{ - // item.TitleBarBackgroundColor = VirtualView.BarBackgroundColor.ToNativeEFL(); - //} - - //TButton CreateNavigationButton(string text) - //{ - // var button = new TButton(NativeParent) - // { - // Text = text - // }; - // button.SetNavigationBackStyle(); - // button.Clicked += (sender, e) => - // { - // if (!VirtualView.SendBackButtonPressed()) - // Tizen.Applications.Application.Current.Exit(); - // }; - // _naviItemContentPartList.Add(button); - // button.Deleted += NaviItemPartContentDeletedHandler; - // return button; - //} - - //void NaviItemPartContentDeletedHandler(object sender, EventArgs e) - //{ - // _naviItemContentPartList.Remove(sender as Widget); - //} - - NaviItem? GetNaviItemForPage(IView page) - { - _ = _naviItemMap ?? throw new InvalidOperationException($"{nameof(_naviItemMap)} cannot be null."); - - NaviItem item; - if (_naviItemMap.TryGetValue(page, out item)) - { - return item; - } - return null; - } - - EvasObject CreateNavItem(IView page) - { - return page.ToNative(MauiContext!); - } - } -} From 1e80199ca00803e70ebeb69967ca4d026408905f Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Thu, 23 Sep 2021 21:07:36 +0900 Subject: [PATCH 145/266] Bump to latest (rc1) - ImageButtonHandler and Handler Re-usability (#2352) - Remove IBoxView (#2619) - Add SupportedOSPlatformVersion (#2565) - Merge all the .NET 6 projects/solutions (#2505) - Shadow Support (#570) - Add IndicatorView handler(#2038) --- .../Handlers/Button/ButtonHandler.Tizen.cs | 15 +++++-- .../Tizen/ImageSourceServiceResult.cs | 39 ------------------- 2 files changed, 12 insertions(+), 42 deletions(-) delete mode 100644 src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs index c5fedd297668..96255da0254a 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs @@ -58,9 +58,18 @@ public static Task MapImageSourceAsync(IButtonHandler handler, IImageButton imag return handler.ImageSourceLoader.UpdateImageSourceAsync(); } - //TODO : Need to impl - [MissingMapper] - public static void MapImageSource(ButtonHandler handler, IButton image) { } + public static void MapImageSource(IButtonHandler handler, IButton image) => + MapImageSourceAsync(handler, image).FireAndForget(handler); + + public static Task MapImageSourceAsync(IButtonHandler handler, IButton image) + { + if (image.ImageSource == null) + { + return Task.CompletedTask; + } + + return handler.ImageSourceLoader.UpdateImageSourceAsync(); + } [MissingMapper] public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button) { } diff --git a/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs b/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs deleted file mode 100644 index 6e48ceaec7c1..000000000000 --- a/src/Core/src/ImageSources/Tizen/ImageSourceServiceResult.cs +++ /dev/null @@ -1,39 +0,0 @@ -#nullable enable -using System; - -namespace Microsoft.Maui -{ - public class ImageSourceServiceResult : IImageSourceServiceResult - { - Action? _dispose; - - public ImageSourceServiceResult(bool result, Action? dispose = null) - : this(result, false, dispose) - { - } - - public ImageSourceServiceResult(bool result, bool resolutionDependent, Action? dispose = null) - { - Value = result; - IsResolutionDependent = resolutionDependent; - _dispose = dispose; - } - - public bool Value { get; } - - public bool IsResolutionDependent { get; } - - public bool IsDisposed { get; private set; } - - public void Dispose() - { - if (IsDisposed) - return; - - IsDisposed = true; - - _dispose?.Invoke(); - _dispose = null; - } - } -} \ No newline at end of file From 8f976fbb20e2b4d384df50bd7812678b6123563e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 5 Oct 2021 16:09:05 +0900 Subject: [PATCH 146/266] Refactor WrapperView to draw drawable features (#186) * Refactor WrapperView to draw drawable features * Update class names and devide files * Override NeesContainer to remove duplicated code * Update class names --- src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs diff --git a/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs b/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs new file mode 100644 index 000000000000..8c203a2666c4 --- /dev/null +++ b/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs @@ -0,0 +1,8 @@ + +namespace Microsoft.Maui +{ + public interface IWrapperViewCanvas + { + public IWrapperViewDrawables Drawables { get; } + } +} \ No newline at end of file From 1238aa21cabdefbf89d631301d01aac8acbd12b2 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Wed, 6 Oct 2021 15:27:57 +0900 Subject: [PATCH 147/266] [Tizen] Adds ApplicationHandler --- .../src/Core/HandlerImpl/Window.Tizen.cs | 12 ------ src/Core/src/IMauiContext.cs | 1 - src/Core/src/MauiContext.cs | 13 +++++++ src/Core/src/Platform/MauiContext.Tizen.cs | 39 ------------------- .../src/Platform/Tizen/ActivationState.cs | 14 ------- .../src/Platform/Tizen/HandlerExtensions.cs | 31 ++++++++++----- .../src/Platform/Tizen/MauiApplication.cs | 2 + 7 files changed, 36 insertions(+), 76 deletions(-) delete mode 100644 src/Controls/src/Core/HandlerImpl/Window.Tizen.cs delete mode 100644 src/Core/src/Platform/MauiContext.Tizen.cs delete mode 100644 src/Core/src/Platform/Tizen/ActivationState.cs diff --git a/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs deleted file mode 100644 index 12dcf19a25ea..000000000000 --- a/src/Controls/src/Core/HandlerImpl/Window.Tizen.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable enable -using System; -using EWindow = ElmSharp.Window; - -namespace Microsoft.Maui.Controls -{ - public partial class Window - { - internal EWindow NativeWindow => - (Handler?.NativeView as EWindow) ?? throw new InvalidOperationException("Window should have a ElmSharp.Window set."); - } -} \ No newline at end of file diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index e1648772dffa..11b1593bb241 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -12,7 +12,6 @@ public interface IMauiContext Android.Content.Context? Context { get; } #elif TIZEN CoreUIAppContext? Context { get; } - ElmSharp.Window? Window { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/MauiContext.cs b/src/Core/src/MauiContext.cs index 341f0a423205..b7ce80111b14 100644 --- a/src/Core/src/MauiContext.cs +++ b/src/Core/src/MauiContext.cs @@ -19,6 +19,19 @@ public MauiContext(IServiceProvider services, Android.Content.Context context) { AddWeakSpecific(context); } +#elif TIZEN + public MauiContext(IServiceProvider services, Tizen.Applications.CoreUIApplication application, CoreUIAppContext context, IMauiContext? parent = null) + : this(services, parent) + { + AddSpecific(application); + AddWeakSpecific(context.MainWindow); + } + + public MauiContext(IServiceProvider services, CoreUIAppContext context, IMauiContext? parent = null) + : this(services, parent) + { + AddWeakSpecific(context); + } #endif public MauiContext(IServiceProvider services) diff --git a/src/Core/src/Platform/MauiContext.Tizen.cs b/src/Core/src/Platform/MauiContext.Tizen.cs deleted file mode 100644 index 231f6a27583f..000000000000 --- a/src/Core/src/Platform/MauiContext.Tizen.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using ElmSharp; - -namespace Microsoft.Maui -{ - public partial class MauiContext - { - readonly WeakReference? _context; - - public MauiContext(CoreUIAppContext context) : this() - { - _context = new WeakReference(context ?? throw new ArgumentNullException(nameof(context))); - } - - public MauiContext(IServiceProvider services, CoreUIAppContext context) : this(services) - { - _context = new WeakReference(context ?? throw new ArgumentNullException(nameof(context))); - } - - public CoreUIAppContext? Context - { - get - { - if (_context == null) - return null; - - CoreUIAppContext? context; - if (_context.TryGetTarget(out context)) - { - return context; - } - - return null; - } - } - - public Window? Window => Context?.MainWindow; - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ActivationState.cs b/src/Core/src/Platform/Tizen/ActivationState.cs deleted file mode 100644 index 6719e581c7ce..000000000000 --- a/src/Core/src/Platform/Tizen/ActivationState.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Microsoft.Maui -{ - public class ActivationState : IActivationState - { - public ActivationState(IMauiContext context) - { - Context = context ?? throw new ArgumentNullException(nameof(context)); - } - - public IMauiContext Context { get; } - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 0118177993e1..a1837193534c 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -46,25 +46,36 @@ public static EvasObject ToNative(this IView view, IMauiContext context, bool is return result; } - public static void SetWindow(this Window nativeWindow, IWindow window, IMauiContext mauiContext) + public static void SetApplicationHandler(this CoreUIApplication nativeApplication, IApplication application, IMauiContext context) + { + _ = nativeApplication ?? throw new ArgumentNullException(nameof(nativeApplication)); + SetHandler(application, context); + } + + public static void SetWindowHandler(this Window nativeWindow, IWindow window, IMauiContext context) { _ = nativeWindow ?? throw new ArgumentNullException(nameof(nativeWindow)); - _ = window ?? throw new ArgumentNullException(nameof(window)); - _ = mauiContext ?? throw new ArgumentNullException(nameof(mauiContext)); + SetHandler(window, context); + } - var handler = window.Handler; + static void SetHandler(IElement element, IMauiContext context) + { + _ = element ?? throw new ArgumentNullException(nameof(element)); + _ = context ?? throw new ArgumentNullException(nameof(context)); + + var handler = element.Handler; if (handler == null) - handler = mauiContext.Handlers.GetHandler(window.GetType()); + handler = context.Handlers.GetHandler(element.GetType()); if (handler == null) - throw new Exception($"Handler not found for view {window}."); + throw new Exception($"Handler not found for view {element}."); - handler.SetMauiContext(mauiContext); + handler.SetMauiContext(context); - window.Handler = handler; + element.Handler = handler; - if (handler.VirtualView != window) - handler.SetVirtualView(window); + if (handler.VirtualView != element) + handler.SetVirtualView(element); } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs index d82bf5708984..4aa203c30bb7 100644 --- a/src/Core/src/Platform/Tizen/MauiApplication.cs +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -145,6 +145,8 @@ protected override void OnTerminate() public static new MauiApplication Current { get; private set; } = null!; + internal IMauiContext MauiApplicationContext { get; private set; } = null!; + public Window MainWindow { get; protected set; } = null!; public IServiceProvider Services { get; protected set; } = null!; From 19737ffa6c331cc4c525501fd5719bf52685fecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 12 Oct 2021 15:27:12 +0900 Subject: [PATCH 148/266] Fix UpdateBackground (#194) * Fix UpdateBackground * Add ContentView Background mapper * Fix Editor/Entry/Label/Layout Background * Add IWrapperViewCanvas.Content * Add PageHandler Background mapper * Restore WrapperView * Remove unnecessary namespace --- src/Core/src/Handlers/Page/PageHandler.Tizen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs index 37251e0a3896..d8fe709df611 100644 --- a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -1,4 +1,4 @@ -using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.Common; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Handlers From 4cff3f2e3a21a578838893573bf74049a608bde0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EC=88=98/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 29 Oct 2021 12:06:26 +0900 Subject: [PATCH 149/266] [Tizen] Add BorderDrawable (#224) * Move to platform specific * Fix border handler for Tizen * Rename ToDrawable method * Fix border content layout * Fix BorderView * Apply rebase --- .../src/Platform/Tizen/BackgroundDrawable.cs | 36 +++++++++++++++++ src/Core/src/Platform/Tizen/BorderDrawable.cs | 39 ++++++++++++++++++ src/Core/src/Platform/Tizen/ShadowDrawable.cs | 40 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 src/Core/src/Platform/Tizen/BackgroundDrawable.cs create mode 100644 src/Core/src/Platform/Tizen/BorderDrawable.cs create mode 100644 src/Core/src/Platform/Tizen/ShadowDrawable.cs diff --git a/src/Core/src/Platform/Tizen/BackgroundDrawable.cs b/src/Core/src/Platform/Tizen/BackgroundDrawable.cs new file mode 100644 index 000000000000..eca0551560bd --- /dev/null +++ b/src/Core/src/Platform/Tizen/BackgroundDrawable.cs @@ -0,0 +1,36 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui +{ + public class BackgroundDrawable : IDrawable + { + Paint _paint; + PathF _path; + + public BackgroundDrawable(Paint paint, PathF path) + { + _paint = paint; + _path = path; + } + + public void UpdatePaint(Paint paint) + { + _paint = paint; + } + + public void UpdatePath(PathF path) + { + _path = path; + } + + public void Draw(ICanvas canvas, RectangleF dirtyRect) + { + canvas.SaveState(); + + canvas.SetFillPaint(_paint, dirtyRect); + canvas.FillPath(_path); + + canvas.RestoreState(); + } + } +} diff --git a/src/Core/src/Platform/Tizen/BorderDrawable.cs b/src/Core/src/Platform/Tizen/BorderDrawable.cs new file mode 100644 index 000000000000..915fd337e932 --- /dev/null +++ b/src/Core/src/Platform/Tizen/BorderDrawable.cs @@ -0,0 +1,39 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui +{ + public class BorderDrawable : IDrawable + { + Paint _paint; + IBorder _border; + + public BorderDrawable(Paint paint, IBorder border) + { + _paint = paint; + _border = border; + } + + public void Draw(ICanvas canvas, RectangleF dirtyRect) + { + canvas.SaveState(); + + var borderPath = _border.Shape?.PathForBounds(dirtyRect) ?? null; + if (borderPath != null) + { + canvas.MiterLimit = _border.StrokeMiterLimit; + canvas.StrokeColor = _border.Stroke.ToColor(); + canvas.StrokeDashPattern = _border.StrokeDashPattern; + canvas.StrokeLineCap = _border.StrokeLineCap; + canvas.StrokeLineJoin = _border.StrokeLineJoin; + canvas.StrokeSize = (float)_border.StrokeThickness; + + canvas.DrawPath(borderPath); + + canvas.SetFillPaint(_paint, dirtyRect); + canvas.FillPath(borderPath); + } + + canvas.RestoreState(); + } + } +} diff --git a/src/Core/src/Platform/Tizen/ShadowDrawable.cs b/src/Core/src/Platform/Tizen/ShadowDrawable.cs new file mode 100644 index 000000000000..62a56575db8b --- /dev/null +++ b/src/Core/src/Platform/Tizen/ShadowDrawable.cs @@ -0,0 +1,40 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui +{ + public class ShadowDrawable : IDrawable + { + IShadow _shadow; + PathF _path; + + public ShadowDrawable(IShadow shadow, PathF path) + { + _shadow = shadow; + _path = path; + } + + public void UpdateShadow(IShadow shadow, PathF path) + { + _shadow = shadow; + _path = path; + } + + public void Draw(ICanvas canvas, RectangleF dirtyRect) + { + canvas.SaveState(); + Color color = _shadow.Paint.ToColor() != null ? _shadow.Paint.ToColor()!.MultiplyAlpha(_shadow.Opacity) : Colors.Black.MultiplyAlpha(_shadow.Opacity); + canvas.SetShadow( + new SizeF((float)_shadow.Offset.X, (float)_shadow.Offset.Y), + (int)_shadow.Radius, + color); + canvas.FillPath(_path); + canvas.RestoreState(); + + canvas.SaveState(); + canvas.StrokeColor = Colors.Transparent; + canvas.DrawPath(_path); + canvas.ClipPath(_path, WindingMode.EvenOdd); + canvas.RestoreState(); + } + } +} \ No newline at end of file From 385da07a2c1d19d70f0b5d87dfb858d1585e2817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=A4=91=ED=98=84/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 15 Nov 2021 16:59:45 +0900 Subject: [PATCH 150/266] [Tizen] Refactor Border by defining MauiDrawable (#248) * [Tizen] Refactor Border by defining MauiDrawable * [Tizen] Apply review comments * [Tizen] Remove unnecessary type casting * [Tizen] Move getting path logic to drawable --- .../src/Graphics/PaintExtensions.Tizen.cs | 89 ------------------- .../src/Platform/Tizen/BackgroundDrawable.cs | 36 -------- src/Core/src/Platform/Tizen/BorderDrawable.cs | 39 -------- .../src/Platform/Tizen/IWrapperViewCanvas.cs | 8 -- src/Core/src/Platform/Tizen/ShadowDrawable.cs | 40 --------- src/Core/src/Platform/Tizen/WrapperView.cs | 1 + 6 files changed, 1 insertion(+), 212 deletions(-) delete mode 100644 src/Core/src/Graphics/PaintExtensions.Tizen.cs delete mode 100644 src/Core/src/Platform/Tizen/BackgroundDrawable.cs delete mode 100644 src/Core/src/Platform/Tizen/BorderDrawable.cs delete mode 100644 src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs delete mode 100644 src/Core/src/Platform/Tizen/ShadowDrawable.cs diff --git a/src/Core/src/Graphics/PaintExtensions.Tizen.cs b/src/Core/src/Graphics/PaintExtensions.Tizen.cs deleted file mode 100644 index 01b7453a18de..000000000000 --- a/src/Core/src/Graphics/PaintExtensions.Tizen.cs +++ /dev/null @@ -1,89 +0,0 @@ -using EColor = ElmSharp.Color; -using TColor = Tizen.UIExtensions.Common.Color; - -namespace Microsoft.Maui.Graphics -{ - public static partial class PaintExtensions - { - public static EColor ToPlatformEFL(this Paint paint) - { - var color = paint.ToColor(); - return color != null ? color.ToPlatformEFL() : EColor.Default; - } - - public static TColor ToPlatform(this Paint paint) - { - var color = paint.ToColor(); - return color != null ? color.ToPlatform() : TColor.Default; - } - - public static MauiDrawable? ToDrawable(this Paint paint) - { - if (paint is SolidPaint solidPaint) - return solidPaint.CreateDrawable(); - - if (paint is LinearGradientPaint linearGradientPaint) - return linearGradientPaint.CreateDrawable(); - - if (paint is RadialGradientPaint radialGradientPaint) - return radialGradientPaint.CreateDrawable(); - - if (paint is ImagePaint imagePaint) - return imagePaint.CreateDrawable(); - - if (paint is PatternPaint patternPaint) - return patternPaint.CreateDrawable(); - - return null; - } - - public static MauiDrawable? CreateDrawable(this SolidPaint solidPaint) - { - return new MauiDrawable - { - Background = solidPaint - }; - } - - public static MauiDrawable? CreateDrawable(this LinearGradientPaint linearGradientPaint) - { - if (!linearGradientPaint.IsValid()) - return null; - - return new MauiDrawable - { - Background = linearGradientPaint - }; - } - - public static MauiDrawable? CreateDrawable(this RadialGradientPaint radialGradientPaint) - { - if (!radialGradientPaint.IsValid()) - return null; - - return new MauiDrawable - { - Background = radialGradientPaint - }; - } - - public static MauiDrawable? CreateDrawable(this ImagePaint imagePaint) - { - return new MauiDrawable - { - Background = imagePaint - }; - } - - public static MauiDrawable? CreateDrawable(this PatternPaint patternPaint) - { - return new MauiDrawable - { - Background = patternPaint - }; - } - - static bool IsValid(this GradientPaint? gradienPaint) => - gradienPaint?.GradientStops?.Length > 0; - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/BackgroundDrawable.cs b/src/Core/src/Platform/Tizen/BackgroundDrawable.cs deleted file mode 100644 index eca0551560bd..000000000000 --- a/src/Core/src/Platform/Tizen/BackgroundDrawable.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.Maui.Graphics; - -namespace Microsoft.Maui -{ - public class BackgroundDrawable : IDrawable - { - Paint _paint; - PathF _path; - - public BackgroundDrawable(Paint paint, PathF path) - { - _paint = paint; - _path = path; - } - - public void UpdatePaint(Paint paint) - { - _paint = paint; - } - - public void UpdatePath(PathF path) - { - _path = path; - } - - public void Draw(ICanvas canvas, RectangleF dirtyRect) - { - canvas.SaveState(); - - canvas.SetFillPaint(_paint, dirtyRect); - canvas.FillPath(_path); - - canvas.RestoreState(); - } - } -} diff --git a/src/Core/src/Platform/Tizen/BorderDrawable.cs b/src/Core/src/Platform/Tizen/BorderDrawable.cs deleted file mode 100644 index 915fd337e932..000000000000 --- a/src/Core/src/Platform/Tizen/BorderDrawable.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Microsoft.Maui.Graphics; - -namespace Microsoft.Maui -{ - public class BorderDrawable : IDrawable - { - Paint _paint; - IBorder _border; - - public BorderDrawable(Paint paint, IBorder border) - { - _paint = paint; - _border = border; - } - - public void Draw(ICanvas canvas, RectangleF dirtyRect) - { - canvas.SaveState(); - - var borderPath = _border.Shape?.PathForBounds(dirtyRect) ?? null; - if (borderPath != null) - { - canvas.MiterLimit = _border.StrokeMiterLimit; - canvas.StrokeColor = _border.Stroke.ToColor(); - canvas.StrokeDashPattern = _border.StrokeDashPattern; - canvas.StrokeLineCap = _border.StrokeLineCap; - canvas.StrokeLineJoin = _border.StrokeLineJoin; - canvas.StrokeSize = (float)_border.StrokeThickness; - - canvas.DrawPath(borderPath); - - canvas.SetFillPaint(_paint, dirtyRect); - canvas.FillPath(borderPath); - } - - canvas.RestoreState(); - } - } -} diff --git a/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs b/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs deleted file mode 100644 index 8c203a2666c4..000000000000 --- a/src/Core/src/Platform/Tizen/IWrapperViewCanvas.cs +++ /dev/null @@ -1,8 +0,0 @@ - -namespace Microsoft.Maui -{ - public interface IWrapperViewCanvas - { - public IWrapperViewDrawables Drawables { get; } - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ShadowDrawable.cs b/src/Core/src/Platform/Tizen/ShadowDrawable.cs deleted file mode 100644 index 62a56575db8b..000000000000 --- a/src/Core/src/Platform/Tizen/ShadowDrawable.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.Maui.Graphics; - -namespace Microsoft.Maui -{ - public class ShadowDrawable : IDrawable - { - IShadow _shadow; - PathF _path; - - public ShadowDrawable(IShadow shadow, PathF path) - { - _shadow = shadow; - _path = path; - } - - public void UpdateShadow(IShadow shadow, PathF path) - { - _shadow = shadow; - _path = path; - } - - public void Draw(ICanvas canvas, RectangleF dirtyRect) - { - canvas.SaveState(); - Color color = _shadow.Paint.ToColor() != null ? _shadow.Paint.ToColor()!.MultiplyAlpha(_shadow.Opacity) : Colors.Black.MultiplyAlpha(_shadow.Opacity); - canvas.SetShadow( - new SizeF((float)_shadow.Offset.X, (float)_shadow.Offset.Y), - (int)_shadow.Radius, - color); - canvas.FillPath(_path); - canvas.RestoreState(); - - canvas.SaveState(); - canvas.StrokeColor = Colors.Transparent; - canvas.DrawPath(_path); - canvas.ClipPath(_path, WindingMode.EvenOdd); - canvas.RestoreState(); - } - } -} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index 119b6083d868..c8a69aaf9b64 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -24,6 +24,7 @@ public partial class WrapperView : Canvas, IBackgroundCanvas public WrapperView(EvasObject parent) : base(parent) { + _mauiDrawable = new MauiDrawable(); _drawableCanvas = new Lazy(() => { var view = new SkiaGraphicsView(parent) From c4b7a11beadbee402af8361818ab86cca6db5029 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 19 Nov 2021 12:53:13 +0900 Subject: [PATCH 151/266] [Tizen] Fix Scoping of MauiContext --- src/Core/src/Platform/Tizen/HandlerExtensions.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index a1837193534c..90becf71bb3d 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -46,17 +46,11 @@ public static EvasObject ToNative(this IView view, IMauiContext context, bool is return result; } - public static void SetApplicationHandler(this CoreUIApplication nativeApplication, IApplication application, IMauiContext context) - { - _ = nativeApplication ?? throw new ArgumentNullException(nameof(nativeApplication)); + public static void SetApplicationHandler(this CoreUIApplication nativeApplication, IApplication application, IMauiContext context) => SetHandler(application, context); - } - public static void SetWindowHandler(this Window nativeWindow, IWindow window, IMauiContext context) - { - _ = nativeWindow ?? throw new ArgumentNullException(nameof(nativeWindow)); + public static void SetWindowHandler(this Window nativeWindow, IWindow window, IMauiContext context) => SetHandler(window, context); - } static void SetHandler(IElement element, IMauiContext context) { From ab870c725035d4a0463639a082135445f161def7 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 3 Dec 2021 09:18:23 +0900 Subject: [PATCH 152/266] [Tizen] Applying upstream changes --- .../src/Platform/Tizen/SemanticExtensions.cs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/SemanticExtensions.cs diff --git a/src/Core/src/Platform/Tizen/SemanticExtensions.cs b/src/Core/src/Platform/Tizen/SemanticExtensions.cs deleted file mode 100644 index f641969d5648..000000000000 --- a/src/Core/src/Platform/Tizen/SemanticExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using ElmSharp.Accessible; - -namespace Microsoft.Maui -{ - public static partial class SemanticExtensions - { - public static void SetSemanticFocus(this IFrameworkElement element) - { - if (element?.Handler?.NativeView == null) - throw new NullReferenceException("Can't access view from a null handler"); - - if (element.Handler.NativeView is not AccessibleObject) - return; - - //TODO : Need to implement - } - } -} From cb0987eafbfe9d5abc3caf137cc49388546576ae Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 6 Dec 2021 09:17:24 +0900 Subject: [PATCH 153/266] [Tizen] Move types in the Platform folder into the Platform namespaces --- src/Core/src/Platform/Tizen/CoreUIAppContext.cs | 2 +- src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs | 2 +- src/Core/src/Platform/Tizen/HandlerExtensions.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs index f5eb0bebe300..ad1fe350caab 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs @@ -7,7 +7,7 @@ using Tizen.UIExtensions.ElmSharp; using ELayout = ElmSharp.Layout; -namespace Microsoft.Maui +namespace Microsoft.Maui.Platform { public class CoreUIAppContext { diff --git a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs index c730e41e1cbb..c96cba6cf504 100644 --- a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs +++ b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs @@ -2,7 +2,7 @@ using Tizen.Applications; using EWindow = ElmSharp.Window; -namespace Microsoft.Maui +namespace Microsoft.Maui.Platform { internal static class CoreUIAppExtensions { diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs index 90becf71bb3d..ac9f308f2bbb 100644 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ b/src/Core/src/Platform/Tizen/HandlerExtensions.cs @@ -3,7 +3,7 @@ using ElmSharp; using Microsoft.Maui.Handlers; -namespace Microsoft.Maui +namespace Microsoft.Maui.Platform { public static class HandlerExtensions { From afe2205463f6c100e84b25a0ac34dfda20d0bfad Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 10 Dec 2021 09:28:31 +0900 Subject: [PATCH 154/266] [Tizen] Fix ButtonHandler --- src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs index 96255da0254a..df97b50b6e21 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs @@ -58,10 +58,10 @@ public static Task MapImageSourceAsync(IButtonHandler handler, IImageButton imag return handler.ImageSourceLoader.UpdateImageSourceAsync(); } - public static void MapImageSource(IButtonHandler handler, IButton image) => + public static void MapImageSource(IButtonHandler handler, IImageButton image) => MapImageSourceAsync(handler, image).FireAndForget(handler); - public static Task MapImageSourceAsync(IButtonHandler handler, IButton image) + public static Task MapImageSourceAsync(IButtonHandler handler, IImageButton image) { if (image.ImageSource == null) { From 2d1ba6fc62f1fe3567971cf6aac4848425704864 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Fri, 10 Dec 2021 17:34:01 +0900 Subject: [PATCH 155/266] [Tizen] Organize and centralize HandlerExtensions --- .../src/Platform/Tizen/HandlerExtensions.cs | 75 ------------------- 1 file changed, 75 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/HandlerExtensions.cs diff --git a/src/Core/src/Platform/Tizen/HandlerExtensions.cs b/src/Core/src/Platform/Tizen/HandlerExtensions.cs deleted file mode 100644 index ac9f308f2bbb..000000000000 --- a/src/Core/src/Platform/Tizen/HandlerExtensions.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using Tizen.Applications; -using ElmSharp; -using Microsoft.Maui.Handlers; - -namespace Microsoft.Maui.Platform -{ - public static class HandlerExtensions - { - public static EvasObject ToNative(this IView view, IMauiContext context, bool isRoot = true) - { - _ = view ?? throw new ArgumentNullException(nameof(view)); - _ = context ?? throw new ArgumentNullException(nameof(context)); - - //This is how MVU works. It collapses views down - if (view is IReplaceableView ir) - view = ir.ReplacedView; - - var handler = view.Handler; - - if (handler == null) - handler = context.Handlers.GetHandler(view.GetType()); - - if (handler == null) - throw new Exception($"Handler not found for view {view}."); - - handler.SetMauiContext(context); - - handler.SetMauiContext(context); - - view.Handler = handler; - } - - handler.SetVirtualView(view); - - if (!(handler.NativeView is EvasObject result)) - { - throw new InvalidOperationException($"Unable to convert {view} to {typeof(EvasObject)}"); - - // Root content view should register to LayoutUpdated() callback. - if (isRoot && handler is LayoutHandler layoutHandler) - { - layoutHandler.RegisterOnLayoutUpdated(); - } - - return result; - } - - public static void SetApplicationHandler(this CoreUIApplication nativeApplication, IApplication application, IMauiContext context) => - SetHandler(application, context); - - public static void SetWindowHandler(this Window nativeWindow, IWindow window, IMauiContext context) => - SetHandler(window, context); - - static void SetHandler(IElement element, IMauiContext context) - { - _ = element ?? throw new ArgumentNullException(nameof(element)); - _ = context ?? throw new ArgumentNullException(nameof(context)); - - var handler = element.Handler; - if (handler == null) - handler = context.Handlers.GetHandler(element.GetType()); - - if (handler == null) - throw new Exception($"Handler not found for view {element}."); - - handler.SetMauiContext(context); - - element.Handler = handler; - - if (handler.VirtualView != element) - handler.SetVirtualView(element); - } - } -} \ No newline at end of file From c41f05565f4a0d029a2f04d5592a7d7df8d729d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/Staff=20Engineer/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Mon, 3 Jan 2022 16:51:20 +0900 Subject: [PATCH 156/266] Refactor MauiContext (#330) --- src/Core/src/IMauiContext.cs | 2 - .../src/Platform/Tizen/CoreUIAppContext.cs | 160 ------------------ .../src/Platform/Tizen/CoreUIAppExtensions.cs | 25 --- .../src/Platform/Tizen/WindowExtensions.cs | 106 ++++++++++++ 4 files changed, 106 insertions(+), 187 deletions(-) delete mode 100644 src/Core/src/Platform/Tizen/CoreUIAppContext.cs delete mode 100644 src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs create mode 100644 src/Core/src/Platform/Tizen/WindowExtensions.cs diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index 11b1593bb241..cf899f3188b5 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -10,8 +10,6 @@ public interface IMauiContext #if __ANDROID__ Android.Content.Context? Context { get; } -#elif TIZEN - CoreUIAppContext? Context { get; } #endif } } \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs b/src/Core/src/Platform/Tizen/CoreUIAppContext.cs deleted file mode 100644 index ad1fe350caab..000000000000 --- a/src/Core/src/Platform/Tizen/CoreUIAppContext.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Reflection; -using Tizen.Common; -using Tizen.Applications; -using ElmSharp; -using ElmSharp.Wearable; -using Tizen.UIExtensions.ElmSharp; -using ELayout = ElmSharp.Layout; - -namespace Microsoft.Maui.Platform -{ - public class CoreUIAppContext - { - DisplayResolutionUnit _displayResolutionUnit = DisplayResolutionUnit.DP; - double _viewPortWidth = -1; - - static CoreUIAppContext? _instance = null; - - public static bool IsInitialized { get; private set; } - - public static CoreUIAppContext GetInstance(CoreApplication application, Window? window = null) - { - if (IsInitialized) - return _instance!; - - _instance = (window == null) ? new CoreUIAppContext(application) : new CoreUIAppContext(application, window); - return _instance; - } - - public CoreApplication CurrentApplication { get; private set; } - - public string ResourceDir => CurrentApplication.DirectoryInfo.Resource; - - public EvasObject NativeParent => BaseLayout; - - public Window MainWindow { get; set; } - - public ELayout BaseLayout { get; set; } - - public CircleSurface? BaseCircleSurface { get; set; } - - public DeviceType DeviceType => DeviceInfo.GetDeviceType(); - - public DisplayResolutionUnit DisplayResolutionUnit - { - get => _displayResolutionUnit; - set - { - _displayResolutionUnit = value; - DeviceInfo.DisplayResolutionUnit = _displayResolutionUnit; - } - } - - public double ViewportWidth - { - get => _viewPortWidth; - set - { - _viewPortWidth = value; - ViewportWidth = _viewPortWidth; - } - } - - protected CoreUIAppContext(CoreApplication application) : this(application, CreateDefaultWindow()) - { - } - - protected CoreUIAppContext(CoreApplication application, Window window) - { - _ = application ?? throw new ArgumentNullException(nameof(application)); - _ = window ?? throw new ArgumentNullException(nameof(window)); - - if (DisplayResolutionUnit == DisplayResolutionUnit.VP && ViewportWidth < 0) - throw new InvalidOperationException($"ViewportWidth should be set in case of DisplayResolutionUnit == VP"); - - Elementary.Initialize(); - Elementary.ThemeOverlay(); - CurrentApplication = application; - MainWindow = window; - InitializeMainWindow(); - - _ = BaseLayout ?? throw new ArgumentNullException(nameof(BaseLayout)); - - if (DotnetUtil.TizenAPIVersion < 5) - { - // We should set the env variable to support IsolatedStorageFile on tizen 4.0 or lower version. - Environment.SetEnvironmentVariable("XDG_DATA_HOME", CurrentApplication.DirectoryInfo.Data); - } - - IsInitialized = true; - } - - public void SetContent(EvasObject content) - { - content.SetAlignment(-1, -1); - content.SetWeight(1, 1); - content.Show(); - BaseLayout.SetContent(content); - } - - static Window CreateDefaultWindow() - { - return GetPreloadedWindow() ?? new Window("MauiDefaultWindow"); - } - - static Window? GetPreloadedWindow() - { - var type = typeof(Window); - // Use reflection to avoid breaking compatibility. ElmSharp.Window.CreateWindow() is has been added since API6. - var methodInfo = type.GetMethod("CreateWindow", BindingFlags.NonPublic | BindingFlags.Static); - - return (Window?)methodInfo?.Invoke(null, new object[] { "FormsWindow" }); - } - - void InitializeMainWindow() - { -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. -#pragma warning disable CS8601 // Possible null reference assignment. - BaseLayout = (ELayout)MainWindow.GetType().GetProperty("BaseLayout")?.GetValue(MainWindow); - BaseCircleSurface = (CircleSurface)MainWindow.GetType().GetProperty("BaseCircleSurface")?.GetValue(MainWindow); -#pragma warning restore CS8601 // Possible null reference assignment. -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. - - if (BaseLayout == null) - { - var conformant = new Conformant(MainWindow); - conformant.Show(); - - var layout = new ApplicationLayout(conformant); - layout.Show(); - - BaseLayout = layout; - - if (DeviceType == DeviceType.Watch) - { - BaseCircleSurface = new CircleSurface(conformant); - } - conformant.SetContent(BaseLayout); - - if (DeviceType == DeviceType.Watch) - { - BaseCircleSurface = new CircleSurface(conformant); - } - } - - MainWindow.Active(); - MainWindow.Show(); - MainWindow.AvailableRotations = DisplayRotation.Degree_0 | DisplayRotation.Degree_90 | DisplayRotation.Degree_180 | DisplayRotation.Degree_270; - - MainWindow.Deleted += (s, e) => CurrentApplication.Exit(); - - MainWindow.RotationChanged += (sender, e) => - { - // TODO : should update later - }; - - MainWindow.BackButtonPressed += (sender, e) => CurrentApplication.Exit(); - } - } -} diff --git a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs deleted file mode 100644 index c96cba6cf504..000000000000 --- a/src/Core/src/Platform/Tizen/CoreUIAppExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Tizen.Applications; -using EWindow = ElmSharp.Window; - -namespace Microsoft.Maui.Platform -{ - internal static class CoreUIAppExtensions - { - public static IWindow GetWindow(this CoreUIApplication application) - { - if (MauiApplication.Current.VirtualWindow != null) - return MauiApplication.Current.VirtualWindow; - - var nativeWindow = MauiApplication.Current.MainWindow; - - foreach (var window in MauiApplication.Current.Application.Windows) - { - if (window?.Handler?.NativeView is EWindow win && win == nativeWindow) - return window; - } - - throw new InvalidOperationException("Window Not Found"); - } - } -} diff --git a/src/Core/src/Platform/Tizen/WindowExtensions.cs b/src/Core/src/Platform/Tizen/WindowExtensions.cs new file mode 100644 index 000000000000..e255affb0ebc --- /dev/null +++ b/src/Core/src/Platform/Tizen/WindowExtensions.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; +using ELayout = ElmSharp.Layout; + +namespace Microsoft.Maui.Platform +{ + public static class WindowExtensions + { + static Dictionary> s_windowBackButtonPressedHandler = new Dictionary>(); + static Dictionary s_windowCloseRequestHandler = new Dictionary(); + static Dictionary s_windowBaseLayout = new Dictionary(); + static Dictionary s_windowModalStack = new Dictionary(); + + public static void Initialize(this Window nativeWindow) + { + var baseLayout = (ELayout?)nativeWindow.GetType().GetProperty("BaseLayout")?.GetValue(nativeWindow); + + if (baseLayout == null) + { + var conformant = new Conformant(nativeWindow); + conformant.Show(); + + var layout = new ApplicationLayout(conformant); + layout.Show(); + + baseLayout = layout; + conformant.SetContent(baseLayout); + } + nativeWindow.SetBaseLayout(baseLayout); + var modalStack = new ModalStack(baseLayout) + { + AlignmentX = -1, + AlignmentY = -1, + WeightX = 1, + WeightY = 1, + }; + modalStack.Show(); + baseLayout.SetContent(modalStack); + nativeWindow.SetModalStack(modalStack); + + nativeWindow.Active(); + nativeWindow.Show(); + nativeWindow.AvailableRotations = DisplayRotation.Degree_0 | DisplayRotation.Degree_90 | DisplayRotation.Degree_180 | DisplayRotation.Degree_270; + + nativeWindow.RotationChanged += (sender, e) => + { + // TODO : should update later + }; + + nativeWindow.BackButtonPressed += (s, e) => OnBackButtonPressed(nativeWindow); + } + + public static void SetOverlay(this Window window, EvasObject content) + { + content?.SetAlignment(-1, -1); + content?.SetWeight(1, 1); + content?.Show(); + window.AddResizeObject(content); + } + + public static void SetWindowCloseRequestHandler(this Window window, Action handler) + { + s_windowCloseRequestHandler[window] = handler; + } + + public static void SetBackButtonPressedHandler(this Window window, Func handler) + { + s_windowBackButtonPressedHandler[window] = handler; + } + + public static ELayout GetBaseLayout(this Window window) + { + return s_windowBaseLayout[window]; + } + + public static void SetBaseLayout(this Window window, ELayout layout) + { + s_windowBaseLayout[window] = layout; + } + + public static ModalStack GetModalStack(this Window window) + { + return s_windowModalStack[window]; + } + + public static void SetModalStack(this Window window, ModalStack modalStack) + { + s_windowModalStack[window] = modalStack; + } + + static void OnBackButtonPressed(Window window) + { + if (s_windowBackButtonPressedHandler.ContainsKey(window)) + { + if (s_windowBackButtonPressedHandler[window].Invoke()) + return; + } + + if (s_windowCloseRequestHandler.ContainsKey(window)) + s_windowCloseRequestHandler[window].Invoke(); + } + + } +} \ No newline at end of file From 661b6fa9954da841af22070f34ede2184637ccf0 Mon Sep 17 00:00:00 2001 From: Seungkeun Lee Date: Wed, 13 Oct 2021 13:40:25 +0900 Subject: [PATCH 157/266] Add NUI handler --- ...osoft.Maui.Controls.MultiTargeting.targets | 1 - NuGet.config | 1 + eng/Microsoft.Extensions.targets | 2 +- .../Core/src/AppHostBuilderExtensions.cs | 10 +- .../Core/src/RendererToHandlerShim.Tizen.cs | 9 +- .../Core/src/RendererToHandlerShim.cs | 5 +- .../Core/src/Tizen/Cells/CellRenderer.cs | 198 --- .../Core/src/Tizen/Cells/EntryCellRenderer.cs | 109 -- .../Core/src/Tizen/Cells/ImageCellRenderer.cs | 60 - .../src/Tizen/Cells/SwitchCellRenderer.cs | 95 -- .../Core/src/Tizen/Cells/TextCellRenderer.cs | 79 - .../Core/src/Tizen/Cells/ViewCellRenderer.cs | 112 -- .../CollectionView/CellContentFactory.cs | 339 +++++ .../CollectionView/CellWrapperTemplate.cs | 40 + .../CollectionView/EmptyItemAdaptor.cs | 53 +- .../CollectionView/ItemTemplateAdaptor.cs | 226 +-- .../Tizen/CollectionView/ListViewAdaptor.cs | 49 + .../Tizen/CollectionView/TableViewAdaptor.cs | 34 + .../Core/src/Tizen/DragGestureHandler.cs | 247 ---- .../Core/src/Tizen/DropGestureHandler.cs | 134 -- .../Extensions/AccessibilityExtensions.cs | 63 - .../src/Tizen/Extensions/BrushExtensions.cs | 14 +- .../src/Tizen/Extensions/ColorExtensions.cs | 22 +- .../DensityIndependentPixelExtensions.cs | 22 +- .../Tizen/Extensions/DragDropExtensions.cs | 114 -- .../src/Tizen/Extensions/EntryExtensions.cs | 38 - .../src/Tizen/Extensions/EvasMapExtensions.cs | 20 - .../src/Tizen/Extensions/ImageExtensions.cs | 43 +- .../Tizen/Extensions/KeyboardExtensions.cs | 80 -- .../src/Tizen/Extensions/LayoutExtensions.cs | 6 +- .../Extensions/NativeBindingExtensions.cs | 12 +- .../src/Tizen/Extensions/PageExtensions.cs | 62 - .../Extensions/ScrollToPositionExtensions.cs | 28 - src/Compatibility/Core/src/Tizen/Forms.cs | 300 ++-- .../Core/src/Tizen/FormsApplication.cs | 164 +-- .../Core/src/Tizen/Gesture/GestureDetector.cs | 105 ++ .../Core/src/Tizen/Gesture/GestureHandler.cs | 54 + .../src/Tizen/Gesture/PanGestureHandler.cs | 53 + .../src/Tizen/Gesture/TapGestureHandler.cs | 29 + .../Core/src/Tizen/GestureDetector.cs | 602 -------- .../Core/src/Tizen/GestureHandler.cs | 57 - .../Core/src/Tizen/HandlerToRendererShim.cs | 105 +- .../Core/src/Tizen/IGestureController.cs | 15 - .../Core/src/Tizen/IMEApplication.cs | 39 - .../Core/src/Tizen/IRotaryInteraction.cs | 9 - .../Core/src/Tizen/LightweightPlatform.cs | 216 --- .../src/Tizen/Native/BatchableExtensions.cs | 64 - .../Core/src/Tizen/Native/BorderRectangle.cs | 84 -- .../Core/src/Tizen/Native/Box.cs | 54 - .../Core/src/Tizen/Native/Button.cs | 282 ---- .../Core/src/Tizen/Native/Canvas.cs | 131 -- .../Native/CollectionView/CarouselView.cs | 23 - .../Native/CollectionView/CollectionView.cs | 793 ---------- .../CollectionView/GridLayoutManager.cs | 708 --------- .../ICollectionViewLayoutManager.cs | 41 - .../Native/CollectionView/IndicatorView.cs | 69 - .../Native/CollectionView/ItemAdaptor.cs | 123 -- .../CollectionView/LinearLayoutManager.cs | 610 -------- .../Native/CollectionView/RecyclerPool.cs | 43 - .../Tizen/Native/CollectionView/ViewHolder.cs | 175 --- .../src/Tizen/Native/DateChangedEventArgs.cs | 24 - .../Core/src/Tizen/Native/DateTimePicker.cs | 58 - .../src/Tizen/Native/DateTimePickerDialog.cs | 129 -- .../Core/src/Tizen/Native/Dialog.cs | 311 ---- .../Core/src/Tizen/Native/EditfieldEntry.cs | 193 --- .../Core/src/Tizen/Native/Entry.cs | 520 ------- .../Core/src/Tizen/Native/EvasBox.cs | 131 -- .../Core/src/Tizen/Native/EvasFormsCanvas.cs | 82 -- .../Core/src/Tizen/Native/FlyoutPage.cs | 505 ------- .../Core/src/Tizen/Native/FormattedString.cs | 129 -- .../Core/src/Tizen/Native/FormsLayout.cs | 128 -- .../Core/src/Tizen/Native/IBatchable.cs | 7 - .../Core/src/Tizen/Native/IButton.cs | 24 - .../Core/src/Tizen/Native/IContainable.cs | 16 - .../Core/src/Tizen/Native/IDateTimeDialog.cs | 21 - .../Core/src/Tizen/Native/IEntry.cs | 37 - .../Core/src/Tizen/Native/IMeasurable.cs | 20 - .../Core/src/Tizen/Native/ITableView.cs | 13 - .../Core/src/Tizen/Native/ITextable.cs | 68 - .../Core/src/Tizen/Native/Image.cs | 50 - .../Core/src/Tizen/Native/Keyboard.cs | 89 -- .../Core/src/Tizen/Native/Label.cs | 419 ------ .../Core/src/Tizen/Native/LayoutEventArgs.cs | 20 - .../Core/src/Tizen/Native/LineBreakMode.cs | 48 - .../Core/src/Tizen/Native/ListView.cs | 700 --------- .../src/Tizen/Native/ObservableCollection.cs | 30 - .../Core/src/Tizen/Native/Page.cs | 81 -- .../Core/src/Tizen/Native/RoundRectangle.cs | 112 -- .../Core/src/Tizen/Native/Scroller.cs | 61 - .../Core/src/Tizen/Native/SearchBar.cs | 18 - .../Core/src/Tizen/Native/Span.cs | 288 ---- .../Core/src/Tizen/Native/TableView.cs | 71 - .../Core/src/Tizen/Native/TextAlignment.cs | 30 - .../Core/src/Tizen/Native/TextHelper.cs | 54 - .../Core/src/Tizen/Native/TitleViewPage.cs | 67 - .../src/Tizen/Native/ToolbarItemButton.cs | 177 --- .../Tizen/Native/Watch/FormsMoreOptionItem.cs | 9 - .../Tizen/Native/Watch/FormsWatchLayout.cs | 113 -- .../src/Tizen/Native/Watch/WatchButton.cs | 31 - .../Tizen/Native/Watch/WatchDateTimePicker.cs | 48 - .../Native/Watch/WatchDateTimePickerDialog.cs | 136 -- .../src/Tizen/Native/Watch/WatchDialog.cs | 86 -- .../src/Tizen/Native/Watch/WatchListView.cs | 114 -- .../src/Tizen/Native/Watch/WatchScroller.cs | 48 - .../src/Tizen/Native/Watch/WatchSpinner.cs | 27 - .../src/Tizen/Native/Watch/WatchTableView.cs | 66 - .../Core/src/Tizen/Native/WebViewContainer.cs | 30 - .../Core/src/Tizen/NativeBindingService.cs | 8 +- .../src/Tizen/NativeValueConverterService.cs | 6 +- .../Core/src/Tizen/NativeViewWrapper.cs | 14 +- .../Core/src/Tizen/PanGestureHandler.cs | 46 - .../Core/src/Tizen/PinchGestureHandler.cs | 59 - src/Compatibility/Core/src/Tizen/Platform.cs | 225 +-- .../Core/src/Tizen/PopupManager.cs | 238 +-- .../Core/src/Tizen/PreloadedWindow.cs | 43 - .../Renderers/ActivityIndicatorRenderer.cs | 58 - .../src/Tizen/Renderers/BoxViewRenderer.cs | 80 +- .../src/Tizen/Renderers/ButtonRenderer.cs | 172 --- .../Tizen/Renderers/CarouselPageRenderer.cs | 281 ---- .../Tizen/Renderers/CarouselViewRenderer.cs | 112 +- .../src/Tizen/Renderers/CheckBoxRenderer.cs | 64 - .../src/Tizen/Renderers/CustomFocusManager.cs | 224 --- .../src/Tizen/Renderers/DatePickerRenderer.cs | 197 --- .../src/Tizen/Renderers/DefaultRenderer.cs | 96 +- .../src/Tizen/Renderers/EditorRenderer.cs | 208 --- .../Core/src/Tizen/Renderers/EntryRenderer.cs | 373 ----- .../src/Tizen/Renderers/FastLayoutRenderer.cs | 161 --- .../src/Tizen/Renderers/FlyoutContainer.cs | 136 -- .../src/Tizen/Renderers/FlyoutPageRenderer.cs | 153 -- .../Core/src/Tizen/Renderers/FrameRenderer.cs | 123 -- .../Tizen/Renderers/IVisualElementRenderer.cs | 7 +- .../Tizen/Renderers/ImageButtonRenderer.cs | 197 --- .../Core/src/Tizen/Renderers/ImageRenderer.cs | 121 +- .../Tizen/Renderers/IndicatorViewRenderer.cs | 49 - .../src/Tizen/Renderers/ItemsViewRenderer.cs | 146 +- .../Core/src/Tizen/Renderers/LabelRenderer.cs | 94 +- .../src/Tizen/Renderers/LayoutRenderer.cs | 105 +- .../src/Tizen/Renderers/ListViewRenderer.cs | 398 +---- .../Renderers/NativeViewWrapperRenderer.cs | 34 - .../Tizen/Renderers/NavigationPageRenderer.cs | 417 +----- .../Core/src/Tizen/Renderers/PageRenderer.cs | 214 +-- .../src/Tizen/Renderers/PickerRenderer.cs | 238 --- .../Tizen/Renderers/ProgressBarRenderer.cs | 100 -- .../Tizen/Renderers/RadioButtonRenderer.cs | 116 -- .../Tizen/Renderers/RefreshViewRenderer.cs | 385 ----- .../src/Tizen/Renderers/ScrollViewRenderer.cs | 183 +-- .../src/Tizen/Renderers/SearchBarRenderer.cs | 219 --- .../src/Tizen/Renderers/SliderRenderer.cs | 145 -- .../src/Tizen/Renderers/StepperRenderer.cs | 113 -- .../Renderers/StructuredItemsViewRenderer.cs | 69 +- .../src/Tizen/Renderers/SwipeViewRenderer.cs | 433 ------ .../src/Tizen/Renderers/SwitchRenderer.cs | 107 -- .../src/Tizen/Renderers/TabbedPageRenderer.cs | 499 ------- .../src/Tizen/Renderers/TableViewRenderer.cs | 89 +- .../src/Tizen/Renderers/TimePickerRenderer.cs | 214 --- .../Core/src/Tizen/Renderers/ViewRenderer.cs | 50 +- .../Tizen/Renderers/VisualElementRenderer.cs | 477 ++---- .../src/Tizen/Renderers/WebViewRenderer.cs | 201 --- .../Core/src/Tizen/Shapes/EllipseRenderer.cs | 35 - .../Core/src/Tizen/Shapes/LineRenderer.cs | 89 -- .../Core/src/Tizen/Shapes/PathRenderer.cs | 57 - .../Core/src/Tizen/Shapes/PolygonRenderer.cs | 88 -- .../Core/src/Tizen/Shapes/PolylineRenderer.cs | 85 -- .../src/Tizen/Shapes/RectangleRenderer.cs | 70 - .../Core/src/Tizen/Shapes/ShapeRenderer.cs | 100 -- .../Core/src/Tizen/Shapes/ShapeView.cs | 290 ---- .../Core/src/Tizen/Shell/IFlyoutController.cs | 7 - .../Core/src/Tizen/Shell/INavigationDrawer.cs | 18 - .../Core/src/Tizen/Shell/INavigationView.cs | 27 - .../Core/src/Tizen/Shell/IShellTabs.cs | 32 - .../Core/src/Tizen/Shell/NavigationDrawer.cs | 211 --- .../Core/src/Tizen/Shell/NavigationView.cs | 499 ------- .../src/Tizen/Shell/SearchHandlerRenderer.cs | 300 ---- .../Core/src/Tizen/Shell/SearchResultList.cs | 73 - .../Core/src/Tizen/Shell/ShellItemRenderer.cs | 455 ------ .../Core/src/Tizen/Shell/ShellMoreToolbar.cs | 93 -- .../Core/src/Tizen/Shell/ShellNavBar.cs | 374 ----- .../Core/src/Tizen/Shell/ShellRenderer.cs | 162 --- .../src/Tizen/Shell/ShellSectionRenderer.cs | 372 ----- .../Core/src/Tizen/Shell/ShellSectionStack.cs | 281 ---- .../Core/src/Tizen/Shell/ShellTabs.cs | 42 - .../Core/src/Tizen/Shell/SimpleViewStack.cs | 93 -- .../Shell/TV/FlyoutItemTemplateAdaptor.cs | 32 - .../Shell/TV/FlyoutItemTemplateSelector.cs | 165 --- .../src/Tizen/Shell/TV/TVNavigationDrawer.cs | 274 ---- .../src/Tizen/Shell/TV/TVNavigationView.cs | 380 ----- .../src/Tizen/Shell/TV/TVShellItemRenderer.cs | 21 - .../src/Tizen/Shell/TV/TVShellRenderer.cs | 30 - .../Tizen/Shell/TV/TVShellSectionRenderer.cs | 181 --- .../src/Tizen/Shell/TV/TVShellSectionStack.cs | 20 - .../Tizen/Shell/Watch/IShellItemRenderer.cs | 11 - .../src/Tizen/Shell/Watch/NavigationDrawer.cs | 542 ------- .../src/Tizen/Shell/Watch/NavigationView.cs | 359 ----- .../Tizen/Shell/Watch/ShellContentRenderer.cs | 39 - .../Tizen/Shell/Watch/ShellItemRenderer.cs | 96 -- .../src/Tizen/Shell/Watch/ShellRenderer.cs | 214 --- .../Tizen/Shell/Watch/ShellRendererFactory.cs | 52 - .../Shell/Watch/ShellSectionItemsRenderer.cs | 324 ----- .../Watch/ShellSectionNavigationRenderer.cs | 126 -- .../src/Tizen/SkiaSharp/BoxViewRenderer.cs | 87 -- .../src/Tizen/SkiaSharp/CanvasViewRenderer.cs | 179 --- .../Core/src/Tizen/SkiaSharp/FrameRenderer.cs | 151 -- .../src/Tizen/SkiaSharp/IBackgroundCanvas.cs | 9 - .../src/Tizen/SkiaSharp/ICanvasRenderer.cs | 10 - .../src/Tizen/SkiaSharp/IClipperCanvas.cs | 9 - .../Core/src/Tizen/SkiaSharp/ImageRenderer.cs | 112 -- .../Core/src/Tizen/SkiaSharp/SKClipperView.cs | 55 - .../Core/src/Tizen/StaticRegistrar.cs | 72 +- .../Core/src/Tizen/SwipeGestureHandler.cs | 30 - .../Core/src/Tizen/TapGestureHandler.cs | 49 - .../Core/src/Tizen/ThemeManager.cs | 1018 +------------ .../src/Tizen/ViewInitializedEventArgs.cs | 4 +- .../Core/HandlerImpl/Window/Window.Impl.cs | 5 +- .../Core/Handlers/Shell/ShellHandler.Tizen.cs | 3 +- .../AlertManager/AlertManager.Tizen.cs | 26 +- .../GestureManager/GestureManager.Tizen.cs | 176 +-- .../ModalNavigationManager.Tizen.cs | 19 +- .../Core/Platform/Tizen/DragGestureHandler.cs | 486 +++---- .../Core/Platform/Tizen/DropGestureHandler.cs | 252 ++-- .../Tizen/Extensions/ButtonExtensions.cs | 4 +- .../Tizen/Extensions/DragDropExtensions.cs | 200 +-- .../Core/Platform/Tizen/GestureDetector.cs | 1274 ++++++++--------- .../src/Core/Platform/Tizen/GestureHandler.cs | 82 +- .../Core/Platform/Tizen/IGestureController.cs | 22 +- .../Core/Platform/Tizen/PanGestureHandler.cs | 72 +- .../Platform/Tizen/PinchGestureHandler.cs | 102 +- .../Tizen/Shell/ShellFlyoutItemAdaptor.cs | 386 ++--- .../Platform/Tizen/Shell/ShellMoreTabs.cs | 168 +-- .../Platform/Tizen/Shell/ShellSearchView.cs | 739 +++++----- .../Platform/Tizen/Shell/SimpleViewStack.cs | 164 +-- .../Tizen/Shell/TVNavigationDrawer.cs | 256 ++++ .../Platform/Tizen/Shell/TVNavigationView.cs | 27 + .../Tizen/Shell/TVShellItemAdaptor.cs | 715 +++++---- .../Platform/Tizen/Shell/TVShellItemView.cs | 32 +- .../Tizen/Shell/TVShellSectionHandler.cs | 2 +- .../Tizen/Shell/TVShellSectionStack.cs | 28 +- .../Core/Platform/Tizen/Shell/TVShellView.cs | 72 +- .../Platform/Tizen/Shell/ThemeConstants.cs | 91 +- .../Core/Platform/Tizen/Shell/ThemeManager.cs | 278 ++-- .../Platform/Tizen/SwipeGestureHandler.cs | 46 +- .../Core/Platform/Tizen/TapGestureHandler.cs | 78 +- .../ActivityIndicatorHandler.Tizen.cs | 16 +- .../Handlers/Border/BorderHandler.Tizen.cs | 10 +- src/Core/src/Handlers/Border/BorderHandler.cs | 2 +- .../Handlers/Button/ButtonHandler.Tizen.cs | 46 +- src/Core/src/Handlers/Button/ButtonHandler.cs | 2 +- .../src/Handlers/Button/IButtonHandler.cs | 2 +- .../CheckBox/CheckBoxHandler.Tizen.cs | 21 +- .../ContentView/ContentViewHandler.Tizen.cs | 12 +- .../DatePicker/DatePickerHandler.Tizen.cs | 124 +- .../Handlers/Editor/EditorHandler.Tizen.cs | 100 +- .../src/Handlers/Element/ElementHandler.cs | 3 + .../src/Handlers/Entry/EntryHandler.Tizen.cs | 165 +-- .../GraphicsView/GraphicsViewHandler.Tizen.cs | 6 +- src/Core/src/Handlers/IViewHandler.Tizen.cs | 15 +- src/Core/src/Handlers/Image/IImageHandler.cs | 2 +- .../src/Handlers/Image/ImageHandler.Tizen.cs | 8 +- src/Core/src/Handlers/Image/ImageHandler.cs | 2 +- .../ImageButton/ImageButtonHandler.Tizen.cs | 9 +- .../ImageButton/ImageButtonHandler.cs | 4 +- .../IndicatorViewHandler.Tizen.cs | 24 +- .../src/Handlers/Label/LabelHandler.Tizen.cs | 12 +- .../Handlers/Layout/LayoutHandler.Tizen.cs | 36 +- .../NavigationViewHandler.Tizen.cs | 315 +--- .../src/Handlers/Page/PageHandler.Tizen.cs | 35 +- .../Handlers/Picker/PickerHandler.Tizen.cs | 153 +- .../ProgressBar/ProgressBarHandler.Tizen.cs | 20 +- .../RefreshView/RefreshViewHandler.Tizen.cs | 6 +- .../ScrollView/ScrollViewHandler.Tizen.cs | 111 +- .../SearchBar/SearchBarHandler.Tizen.cs | 93 +- .../ShapeView/ShapeViewHandler.Tizen.cs | 5 +- .../Handlers/Slider/SliderHandler.Tizen.cs | 51 +- .../Handlers/Stepper/StepperHandler.Tizen.cs | 11 +- .../Handlers/Switch/SwitchHandler.Tizen.cs | 24 +- .../TimePicker/TimePickerHandler.Tizen.cs | 104 +- .../src/Handlers/View/ViewHandler.Tizen.cs | 15 +- src/Core/src/Handlers/View/ViewHandler.cs | 2 +- .../src/Handlers/View/ViewHandlerOfT.Tizen.cs | 99 +- src/Core/src/Handlers/View/ViewHandlerOfT.cs | 2 +- .../Handlers/WebView/WebViewHandler.Tizen.cs | 74 +- .../Handlers/Window/WindowHandler.Tizen.cs | 4 +- src/Core/src/Handlers/Window/WindowHandler.cs | 2 +- .../FileImageSourceService.Tizen.cs | 8 +- .../FontImageSourceService.Tizen.cs | 6 +- .../src/ImageSources/IImageSourceService.cs | 4 +- .../src/ImageSources/ImageSourceExtensions.cs | 4 +- .../src/ImageSources/ImageSourceService.cs | 4 +- .../ImageSources/ImageSourceServiceResult.cs | 2 +- .../StreamImageSourceService.Tizen.cs | 6 +- .../UriImageSourceService.Tizen.cs | 6 +- src/Core/src/MauiContext.cs | 2 +- .../src/Platform/ImageSourcePartLoader.cs | 4 +- .../Tizen/ActivityIndicatorExtensions.cs | 14 +- .../src/Platform/Tizen/ButtonExtensions.cs | 2 +- .../src/Platform/Tizen/CheckBoxExtensions.cs | 19 +- .../{LayoutCanvas.cs => ContentViewGroup.cs} | 20 +- .../src/Platform/Tizen/CoreAppExtensions.cs | 5 +- src/Core/src/Platform/Tizen/DPExtensions.cs | 31 +- .../Platform/Tizen/DatePickerExtensions.cs | 2 +- .../src/Platform/Tizen/EditorExtensions.cs | 2 +- .../src/Platform/Tizen/EntryExtensions.cs | 165 +-- .../Platform/Tizen/FlowDirectionExtensions.cs | 4 +- .../Platform/Tizen/GraphicsViewExtensions.cs | 4 +- .../src/Platform/Tizen/HandlerExtensions.cs | 75 + .../src/Platform/Tizen/ImageExtensions.cs | 61 +- .../src/Platform/Tizen/KeyboardExtensions.cs | 30 +- .../src/Platform/Tizen/LabelExtensions.cs | 13 +- .../{ContentCanvas.cs => LayoutViewGroup.cs} | 19 +- .../src/Platform/Tizen/MauiApplication.cs | 52 +- .../Tizen/MauiIndicatorViewExtensions.cs | 27 +- src/Core/src/Platform/Tizen/MauiShapeView.cs | 6 +- src/Core/src/Platform/Tizen/MauiWebView.cs | 28 +- src/Core/src/Platform/Tizen/ModalStack.cs | 101 -- .../src/Platform/Tizen/PickerExtensions.cs | 2 +- .../Platform/Tizen/ProgressBarExtensions.cs | 6 +- .../Platform/Tizen/ScrollViewExtensions.cs | 39 +- .../src/Platform/Tizen/SearchBarExtensions.cs | 10 +- .../src/Platform/Tizen/SliderExtensions.cs | 23 +- .../src/Platform/Tizen/StepperExtensions.cs | 40 +- .../src/Platform/Tizen/StrokeExtensions.cs | 19 +- .../src/Platform/Tizen/SwitchExtensions.cs | 24 +- .../Platform/Tizen/TimePickerExtensions.cs | 2 +- .../Tizen/TransformationExtensions.cs | 131 +- src/Core/src/Platform/Tizen/ViewExtensions.cs | 162 +-- src/Core/src/Platform/Tizen/WrapperView.cs | 368 +---- 325 files changed, 5401 insertions(+), 33418 deletions(-) delete mode 100644 src/Compatibility/Core/src/Tizen/Cells/CellRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Cells/EntryCellRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Cells/ImageCellRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Cells/SwitchCellRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Cells/TextCellRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Cells/ViewCellRenderer.cs create mode 100644 src/Compatibility/Core/src/Tizen/CollectionView/CellContentFactory.cs create mode 100644 src/Compatibility/Core/src/Tizen/CollectionView/CellWrapperTemplate.cs rename src/Compatibility/Core/src/Tizen/{Native => }/CollectionView/EmptyItemAdaptor.cs (54%) rename src/Compatibility/Core/src/Tizen/{Native => }/CollectionView/ItemTemplateAdaptor.cs (66%) create mode 100644 src/Compatibility/Core/src/Tizen/CollectionView/ListViewAdaptor.cs create mode 100644 src/Compatibility/Core/src/Tizen/CollectionView/TableViewAdaptor.cs delete mode 100644 src/Compatibility/Core/src/Tizen/DragGestureHandler.cs delete mode 100644 src/Compatibility/Core/src/Tizen/DropGestureHandler.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Extensions/AccessibilityExtensions.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Extensions/DragDropExtensions.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Extensions/EntryExtensions.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Extensions/EvasMapExtensions.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Extensions/KeyboardExtensions.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Extensions/PageExtensions.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Extensions/ScrollToPositionExtensions.cs create mode 100644 src/Compatibility/Core/src/Tizen/Gesture/GestureDetector.cs create mode 100644 src/Compatibility/Core/src/Tizen/Gesture/GestureHandler.cs create mode 100644 src/Compatibility/Core/src/Tizen/Gesture/PanGestureHandler.cs create mode 100644 src/Compatibility/Core/src/Tizen/Gesture/TapGestureHandler.cs delete mode 100644 src/Compatibility/Core/src/Tizen/GestureDetector.cs delete mode 100644 src/Compatibility/Core/src/Tizen/GestureHandler.cs delete mode 100644 src/Compatibility/Core/src/Tizen/IGestureController.cs delete mode 100644 src/Compatibility/Core/src/Tizen/IMEApplication.cs delete mode 100644 src/Compatibility/Core/src/Tizen/IRotaryInteraction.cs delete mode 100644 src/Compatibility/Core/src/Tizen/LightweightPlatform.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/BatchableExtensions.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/BorderRectangle.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Box.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Button.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Canvas.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/CollectionView/CarouselView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/CollectionView/CollectionView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/CollectionView/GridLayoutManager.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/CollectionView/ICollectionViewLayoutManager.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/CollectionView/IndicatorView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemAdaptor.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/CollectionView/LinearLayoutManager.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/CollectionView/RecyclerPool.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/CollectionView/ViewHolder.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/DateChangedEventArgs.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/DateTimePicker.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/DateTimePickerDialog.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Dialog.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/EditfieldEntry.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Entry.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/EvasBox.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/EvasFormsCanvas.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/FlyoutPage.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/FormattedString.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/FormsLayout.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/IBatchable.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/IButton.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/IContainable.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/IDateTimeDialog.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/IEntry.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/IMeasurable.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/ITableView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/ITextable.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Image.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Keyboard.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Label.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/LayoutEventArgs.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/LineBreakMode.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/ListView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/ObservableCollection.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Page.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/RoundRectangle.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Scroller.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/SearchBar.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Span.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/TableView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/TextAlignment.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/TextHelper.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/TitleViewPage.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/ToolbarItemButton.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/FormsMoreOptionItem.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/FormsWatchLayout.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/WatchButton.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePicker.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePickerDialog.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/WatchDialog.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/WatchListView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/WatchScroller.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/WatchSpinner.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/Watch/WatchTableView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Native/WebViewContainer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/PanGestureHandler.cs delete mode 100644 src/Compatibility/Core/src/Tizen/PinchGestureHandler.cs delete mode 100644 src/Compatibility/Core/src/Tizen/PreloadedWindow.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/ActivityIndicatorRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/ButtonRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/CarouselPageRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/CheckBoxRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/CustomFocusManager.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/DatePickerRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/EditorRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/EntryRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/FastLayoutRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/FlyoutContainer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/FlyoutPageRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/FrameRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/ImageButtonRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/IndicatorViewRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/NativeViewWrapperRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/PickerRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/ProgressBarRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/RadioButtonRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/RefreshViewRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/SearchBarRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/SliderRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/StepperRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/SwipeViewRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/SwitchRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/TabbedPageRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/TimePickerRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Renderers/WebViewRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shapes/EllipseRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shapes/LineRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shapes/PathRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shapes/PolygonRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shapes/PolylineRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shapes/RectangleRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shapes/ShapeRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shapes/ShapeView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/IFlyoutController.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/INavigationDrawer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/INavigationView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/IShellTabs.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/NavigationDrawer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/NavigationView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/SearchHandlerRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/SearchResultList.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/ShellItemRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/ShellMoreToolbar.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/ShellNavBar.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/ShellRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/ShellSectionRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/ShellSectionStack.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/ShellTabs.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/SimpleViewStack.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateAdaptor.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateSelector.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationDrawer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/TV/TVShellItemRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/TV/TVShellRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionStack.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/Watch/IShellItemRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationDrawer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/Watch/ShellContentRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/Watch/ShellItemRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRendererFactory.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionItemsRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionNavigationRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/SkiaSharp/BoxViewRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/SkiaSharp/CanvasViewRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/SkiaSharp/FrameRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/SkiaSharp/IBackgroundCanvas.cs delete mode 100644 src/Compatibility/Core/src/Tizen/SkiaSharp/ICanvasRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/SkiaSharp/IClipperCanvas.cs delete mode 100644 src/Compatibility/Core/src/Tizen/SkiaSharp/ImageRenderer.cs delete mode 100644 src/Compatibility/Core/src/Tizen/SkiaSharp/SKClipperView.cs delete mode 100644 src/Compatibility/Core/src/Tizen/SwipeGestureHandler.cs delete mode 100644 src/Compatibility/Core/src/Tizen/TapGestureHandler.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationDrawer.cs create mode 100644 src/Controls/src/Core/Platform/Tizen/Shell/TVNavigationView.cs rename src/Core/src/Platform/Tizen/{LayoutCanvas.cs => ContentViewGroup.cs} (67%) create mode 100644 src/Core/src/Platform/Tizen/HandlerExtensions.cs rename src/Core/src/Platform/Tizen/{ContentCanvas.cs => LayoutViewGroup.cs} (67%) delete mode 100644 src/Core/src/Platform/Tizen/ModalStack.cs diff --git a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets index bfa81e0fadab..01d6d8ff280f 100644 --- a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets +++ b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets @@ -113,5 +113,4 @@ WINDOWS_UWP;$(DefineConstants) - diff --git a/NuGet.config b/NuGet.config index f23d429c7020..049990a09731 100644 --- a/NuGet.config +++ b/NuGet.config @@ -22,6 +22,7 @@ + diff --git a/eng/Microsoft.Extensions.targets b/eng/Microsoft.Extensions.targets index 5ad399a2a787..931798a7942d 100644 --- a/eng/Microsoft.Extensions.targets +++ b/eng/Microsoft.Extensions.targets @@ -126,7 +126,7 @@ Version="$(MicrosoftCodeAnalysisPublicApiAnalyzersVersion)" /> ; +using ViewHandler = Microsoft.Maui.Handlers.ViewHandler; #elif (NETSTANDARD || !PLATFORM) using PlatformView = System.Object; using ViewHandler = Microsoft.Maui.Handlers.ViewHandler; diff --git a/src/Compatibility/Core/src/Tizen/Cells/CellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/CellRenderer.cs deleted file mode 100644 index 9ef5ce207515..000000000000 --- a/src/Compatibility/Core/src/Tizen/Cells/CellRenderer.cs +++ /dev/null @@ -1,198 +0,0 @@ -using System.Collections.Generic; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] - public abstract class CellRenderer : IRegisterable - { - const string HeightProperty = "Height"; - readonly Dictionary> _realizedNativeViews = new Dictionary>(); - - Native.ListView.ItemContext _currentItem; - GenItemClass _itemClass; - - protected CellRenderer(string style) - { - Style = style; - } - - public GenItemClass Class - { - get - { - if (_itemClass == null) - _itemClass = CreateItemClass(Style); - return _itemClass; - } - protected set - { - _itemClass?.Dispose(); - _itemClass = value; - } - } - - public virtual void SetGroupMode(bool enable) - { - } - - public string Style { get; protected set; } - - protected GenItemClass CreateItemClass(string style) - { - return new GenItemClass(style) - { - GetTextHandler = GetText, - GetContentHandler = GetContent, - DeleteHandler = ItemDeleted, - ReusableContentHandler = ReusableContent, - }; - } - - protected virtual bool OnCellPropertyChanged(Cell cell, string property, Dictionary realizedView) - { - if (property == HeightProperty) - { - return true; - } - return false; - } - - protected virtual Span OnGetText(Cell cell, string part) - { - return null; - } - protected virtual EvasObject OnGetContent(Cell cell, string part) - { - return null; - } - - protected virtual void OnCreated(Cell cell, bool isGroup) - { - } - - protected virtual void OnDeleted(Cell cell) - { - } - - protected virtual void OnUnrealizedCell(Cell cell) - { - } - - protected virtual EvasObject OnReusableContent(Cell cell, string part, EvasObject old) - { - return null; - } - - protected double FindCellContentHeight(Cell cell) - { - ViewCell viewCell = cell as ViewCell; - if (viewCell != null) - { - var parentWidth = (cell.Parent as VisualElement).Width; - var view = viewCell.View; - return view.Measure(parentWidth, double.PositiveInfinity).Request.Height; - } - else - return -1; - } - - static Native.Span ToNative(Span span) - { - var nativeSpan = new Native.Span(); - nativeSpan.Text = span.Text; - nativeSpan.ForegroundColor = span.TextColor.ToNative(); - nativeSpan.FontAttributes = span.FontAttributes; - nativeSpan.BackgroundColor = span.BackgroundColor.ToNative(); - nativeSpan.FontSize = span.FontSize; - nativeSpan.FontFamily = span.FontFamily; - return nativeSpan; - } - - public void SendCellPropertyChanged(Cell cell, GenItem item, string property) - { - Dictionary realizedView = null; - _realizedNativeViews.TryGetValue(cell, out realizedView); - - // just to prevent null reference exception in OnCellPropertyChanged - realizedView = realizedView ?? new Dictionary(); - - if (property == Cell.IsEnabledProperty.PropertyName) - { - item.IsEnabled = cell.IsEnabled; - } - // if true was returned, item was updated - // if it's possible to update the cell property without Update(), return false - else if (OnCellPropertyChanged(cell, property, realizedView)) - { - item.Update(); - } - } - - public void SendUnrealizedCell(Cell cell) - { - Dictionary realizedView = null; - _realizedNativeViews.TryGetValue(cell, out realizedView); - realizedView?.Clear(); - OnUnrealizedCell(cell); - } - - public void SendCreatedCell(Cell cell, bool isGroup = false) - { - OnCreated(cell, isGroup); - } - - internal Native.ListView.ItemContext GetCurrentItem() - { - return _currentItem; - } - - string GetText(object data, string part) - { - _currentItem = data as Native.ListView.ItemContext; - var span = OnGetText(_currentItem.Cell, part); - return span != null ? ToNative(span).GetMarkupText() : null; - } - - EvasObject GetContent(object data, string part) - { - _currentItem = data as Native.ListView.ItemContext; - var cell = _currentItem.Cell; - EvasObject nativeView = OnGetContent(cell, part); - UpdateRealizedView(cell, part, nativeView); - return nativeView; - } - - EvasObject ReusableContent(object data, string part, EvasObject old) - { - _currentItem = data as Native.ListView.ItemContext; - var cell = _currentItem.Cell; - EvasObject nativeView = OnReusableContent(cell, part, old); - UpdateRealizedView(cell, part, nativeView); - return nativeView; - } - - void UpdateRealizedView(Cell cell, string part, EvasObject nativeView) - { - if (part != null && nativeView != null) - { - Dictionary realizedView = null; - _realizedNativeViews.TryGetValue(cell, out realizedView); - if (realizedView == null) - { - realizedView = new Dictionary(); - _realizedNativeViews[cell] = realizedView; - } - realizedView[part] = nativeView; - } - } - - void ItemDeleted(object data) - { - _currentItem = data as Native.ListView.ItemContext; - var cell = _currentItem.Cell; - _realizedNativeViews.Remove(cell); - OnDeleted(cell); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Cells/EntryCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/EntryCellRenderer.cs deleted file mode 100644 index 55ab30338cef..000000000000 --- a/src/Compatibility/Core/src/Tizen/Cells/EntryCellRenderer.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using ElmSharp; -using XStackLayout = Microsoft.Maui.Controls.StackLayout; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] - public class EntryCellRenderer : ViewCellRenderer - { - readonly Dictionary _cacheCandidate = new Dictionary(); - - public EntryCellRenderer() - { - } - - protected override EvasObject OnGetContent(Cell cell, string part) - { - if (part == MainContentPart) - { - var entryCell = cell as EntryCell; - int pixelHeight = Forms.ConvertToScaledPixel(entryCell.RenderHeight); - pixelHeight = pixelHeight > 0 ? pixelHeight : this.GetDefaultHeightPixel(); - - var label = new Label() - { - HorizontalOptions = LayoutOptions.Start, - VerticalOptions = LayoutOptions.Center, - VerticalTextAlignment = TextAlignment.Center, - FontSize = -1 - }; - label.SetBinding(Label.TextProperty, new Binding(EntryCell.LabelProperty.PropertyName)); - label.SetBinding(Label.TextColorProperty, new Binding(EntryCell.LabelColorProperty.PropertyName, converter: new DefaultColorConverter())); - - var entry = new Entry() - { - HorizontalOptions = LayoutOptions.Fill, - VerticalOptions = LayoutOptions.Center, - FontSize = -1, - }; - entry.SetBinding(Entry.TextProperty, new Binding(EntryCell.TextProperty.PropertyName, BindingMode.TwoWay)); - entry.SetBinding(Entry.PlaceholderProperty, new Binding(EntryCell.PlaceholderProperty.PropertyName)); - entry.SetBinding(InputView.KeyboardProperty, new Binding(EntryCell.KeyboardProperty.PropertyName)); - entry.SetBinding(Entry.HorizontalTextAlignmentProperty, new Binding(EntryCell.HorizontalTextAlignmentProperty.PropertyName)); - - var layout = new XStackLayout() - { - Orientation = StackOrientation.Horizontal, - Children = { - label, - entry - } - }; - layout.Parent = cell; - layout.BindingContext = entryCell; - layout.MinimumHeightRequest = Forms.ConvertToScaledDP(pixelHeight); - - var renderer = Platform.GetOrCreateRenderer(layout); - (renderer as ILayoutRenderer)?.RegisterOnLayoutUpdated(); - - var nativeEntry = Platform.GetRenderer(entry)?.NativeView ?? null; - if (nativeEntry != null) - { - nativeEntry.PropagateEvents = false; - } - - var nativeView = renderer.NativeView; - nativeView.MinimumHeight = pixelHeight; - _cacheCandidate[nativeView] = layout; - nativeView.Deleted += (sender, e) => - { - _cacheCandidate.Remove(sender as EvasObject); - }; - - return nativeView; - } - return null; - } - - protected override EvasObject OnReusableContent(Cell cell, string part, EvasObject old) - { - if (!_cacheCandidate.ContainsKey(old)) - { - return null; - } - - var layout = _cacheCandidate[old]; - layout.BindingContext = cell; - int height = Forms.ConvertToScaledPixel(cell.RenderHeight); - height = height > 0 ? height : this.GetDefaultHeightPixel(); - old.MinimumHeight = height; - return old; - } - - class DefaultColorConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return (value == null || ((Color)value).IsDefault) ? ThemeConstants.EntryCell.ColorClass.DefaultLabelColor : value; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return value; - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Cells/ImageCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/ImageCellRenderer.cs deleted file mode 100644 index d11c12561ded..000000000000 --- a/src/Compatibility/Core/src/Tizen/Cells/ImageCellRenderer.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Collections.Generic; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] - public class ImageCellRenderer : TextCellRenderer - { - public ImageCellRenderer() : this(ThemeManager.GetImageCellRendererStyle()) - { - ImagePart = this.GetImagePart(); - } - - protected ImageCellRenderer(string style) : base(style) - { - } - - protected string ImagePart { get; set; } - - protected override EvasObject OnGetContent(Cell cell, string part) - { - if (part == ImagePart) - { - var imgCell = cell as ImageCell; - int pixelSize = Forms.ConvertToScaledPixel(imgCell.RenderHeight); - if (pixelSize <= 0) - { - pixelSize = this.GetDefaultHeightPixel(); - } - - var image = new Native.Image(Forms.NativeParent) - { - MinimumWidth = pixelSize, - MinimumHeight = pixelSize - }; - image.SetAlignment(-1.0, -1.0); // fill - image.SetWeight(1.0, 1.0); // expand - - var task = image.LoadFromImageSourceAsync(imgCell.ImageSource); - return image; - } - else - { - return null; - } - } - - protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary realizedView) - { - if (property == ImageCell.ImageSourceProperty.PropertyName) - { - EvasObject image; - realizedView.TryGetValue(ImagePart, out image); - (image as Native.Image)?.LoadFromImageSourceAsync((cell as ImageCell)?.ImageSource); - return false; - } - return base.OnCellPropertyChanged(cell, property, realizedView); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Cells/SwitchCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/SwitchCellRenderer.cs deleted file mode 100644 index ff1475b201bd..000000000000 --- a/src/Compatibility/Core/src/Tizen/Cells/SwitchCellRenderer.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Collections.Generic; -using Microsoft.Maui.Devices; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] - public class SwitchCellRenderer : CellRenderer - { - readonly Dictionary _cacheCandidate = new Dictionary(); - - protected SwitchCellRenderer(string style) : base(style) - { - } - - public SwitchCellRenderer() : this(ThemeManager.GetSwitchCellRendererStyle()) - { - MainPart = this.GetMainPart(); - SwitchPart = this.GetSwitchPart(); - } - - protected string MainPart { get; set; } - protected string SwitchPart { get; set; } - - protected override Span OnGetText(Cell cell, string part) - { - if (part == MainPart) - { - return new Span() - { - Text = (cell as SwitchCell).Text - }; - } - return null; - } - - protected override EvasObject OnGetContent(Cell cell, string part) - { - if (part == SwitchPart) - { - var toggle = new Switch() - { - BindingContext = cell, - Parent = cell.Parent - }; - toggle.SetBinding(Switch.IsToggledProperty, new Binding(SwitchCell.OnProperty.PropertyName)); - toggle.SetBinding(Switch.OnColorProperty, new Binding(SwitchCell.OnColorProperty.PropertyName)); - var nativeView = Platform.GetOrCreateRenderer(toggle).NativeView; - - if (DeviceInfo.Idiom == DeviceIdiom.Watch) - { - nativeView.MinimumWidth += 8; - } - - //It is a temporary way to prevent that the check of the Cell gets focus until the UX about views in the Cell for TV is defined. - if (DeviceInfo.Idiom == DeviceIdiom.TV) - { - ((Check)nativeView).AllowFocus(false); - } - else - { - nativeView.PropagateEvents = false; - } - - _cacheCandidate[nativeView] = toggle; - nativeView.Deleted += (sender, e) => - { - _cacheCandidate.Remove(sender as EvasObject); - }; - - return nativeView; - } - return null; - } - - protected override EvasObject OnReusableContent(Cell cell, string part, EvasObject old) - { - if (!_cacheCandidate.ContainsKey(old)) - { - return null; - } - _cacheCandidate[old].BindingContext = cell; - return old; - } - - protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary realizedView) - { - if (property == SwitchCell.TextProperty.PropertyName) - { - return true; - } - return base.OnCellPropertyChanged(cell, property, realizedView); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Cells/TextCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/TextCellRenderer.cs deleted file mode 100644 index 4c89702d5e11..000000000000 --- a/src/Compatibility/Core/src/Tizen/Cells/TextCellRenderer.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System.Collections.Generic; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] - public class TextCellRenderer : CellRenderer - { - bool _groupMode = false; - // TextCell.Detail property is not supported on TV profile due to UX limitation. - public TextCellRenderer() : this(ThemeManager.GetTextCellRendererStyle()) { } - - protected TextCellRenderer(string style) : base(style) - { - MainPart = this.GetMainPart(); - DetailPart = this.GetDetailPart(); - } - - protected string MainPart { get; set; } - protected string DetailPart { get; set; } - - public override void SetGroupMode(bool enable) - { - if (_groupMode == enable) - return; - - _groupMode = enable; - Class = null; - Style = ThemeManager.GetTextCellGroupModeStyle(enable); - DetailPart = this.GetDetailPart(); - } - - protected override Span OnGetText(Cell cell, string part) - { - var textCell = (TextCell)cell; - if (part == MainPart) - { - return OnMainText(textCell); - } - if (part == DetailPart) - { - return OnDetailText(textCell); - } - return null; - } - - protected virtual Span OnMainText(TextCell cell) - { - return new Span() - { - Text = cell.Text, - TextColor = cell.TextColor, - FontSize = -1 - }; - } - - protected virtual Span OnDetailText(TextCell cell) - { - return new Span() - { - Text = cell.Detail, - TextColor = cell.DetailColor, - FontSize = -1 - }; - } - - protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary realizedView) - { - if (property == TextCell.TextProperty.PropertyName || - property == TextCell.TextColorProperty.PropertyName || - property == TextCell.DetailProperty.PropertyName || - property == TextCell.DetailColorProperty.PropertyName) - { - return true; - } - return base.OnCellPropertyChanged(cell, property, realizedView); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Cells/ViewCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/ViewCellRenderer.cs deleted file mode 100644 index 7351d27fe6fb..000000000000 --- a/src/Compatibility/Core/src/Tizen/Cells/ViewCellRenderer.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System.Collections.Generic; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] - public class ViewCellRenderer : CellRenderer - { - readonly Dictionary _cacheCandidate = new Dictionary(); - public ViewCellRenderer() : base(ThemeManager.GetViewCellRendererStyle()) - { - MainContentPart = this.GetMainContentPart(); - } - - protected string MainContentPart { get; set; } - - protected override EvasObject OnReusableContent(Cell cell, string part, EvasObject old) - { - if (_cacheCandidate.ContainsKey(old)) - { - var viewCell = _cacheCandidate[old]; - var widget = (old as Widget); - if (widget != null) - widget.IsEnabled = true; - viewCell.BindingContext = cell.BindingContext; - return old; - } - return null; - } - - protected override EvasObject OnGetContent(Cell cell, string part) - { - if (part == MainContentPart) - { - var viewCell = (ViewCell)cell; - - var listView = viewCell?.RealParent as ListView; - - // It is a condition for reusable the cell - if (listView != null && - listView.HasUnevenRows == false && - !(listView.ItemTemplate is DataTemplateSelector) && !GetCurrentItem().IsGroupItem) - { - return CreateReusableContent(viewCell); - } - - Platform.GetRenderer(viewCell.View)?.Dispose(); - var renderer = Platform.GetOrCreateRenderer(viewCell.View); - double height = viewCell.RenderHeight; - height = height > 0 ? height : FindCellContentHeight(viewCell); - - renderer.NativeView.MinimumHeight = Forms.ConvertToScaledPixel(height); - (renderer as ILayoutRenderer)?.RegisterOnLayoutUpdated(); - - UpdatePropagateEvent(viewCell.View); - - return renderer.NativeView; - } - return null; - } - - protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary realizedView) - { - if (property == "View") - { - return true; - } - return base.OnCellPropertyChanged(cell, property, realizedView); - } - - EvasObject CreateReusableContent(ViewCell viewCell) - { - var listView = viewCell.RealParent as ListView; - ViewCell duplicatedCell = (ViewCell)listView.ItemTemplate.CreateContent(); - duplicatedCell.BindingContext = viewCell.BindingContext; - duplicatedCell.Parent = listView; - - var renderer = Platform.GetOrCreateRenderer(duplicatedCell.View); - double height = duplicatedCell.RenderHeight; - height = height > 0 ? height : FindCellContentHeight(duplicatedCell); - renderer.NativeView.MinimumHeight = Forms.ConvertToScaledPixel(height); - - _cacheCandidate[renderer.NativeView] = duplicatedCell; - renderer.NativeView.Deleted += (sender, e) => - { - _cacheCandidate.Remove((EvasObject)sender); - }; - (renderer as ILayoutRenderer)?.RegisterOnLayoutUpdated(); - - UpdatePropagateEvent(duplicatedCell.View); - return renderer.NativeView; - } - - void UpdatePropagateEvent(View view) - { - if (!view.IsPlatformEnabled) - return; - foreach (var element in view.Descendants()) - { - if (element is Button || element is Switch) - { - var nativeView = Platform.GetRenderer(element)?.NativeView ?? null; - if (nativeView != null) - { - nativeView.PropagateEvents = false; - } - } - } - } - - } -} diff --git a/src/Compatibility/Core/src/Tizen/CollectionView/CellContentFactory.cs b/src/Compatibility/Core/src/Tizen/CollectionView/CellContentFactory.cs new file mode 100644 index 000000000000..8d2ff06626f1 --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/CollectionView/CellContentFactory.cs @@ -0,0 +1,339 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + public class SectionCell : TextCell { } + + public class CellContentFactory + { + public static View CreateContent(object data, BindableObject container = null) + { + if (data is ImageCell imageCell) + { + return new CellContentView(imageCell, container) + { + Content = CreateContent(imageCell) + }; + } + else if (data is SectionCell sectionCell) + { + return new CellContentView(sectionCell, container, false, false) + { + Content = CreateContent(sectionCell) + }; + } + else if (data is EntryCell entryCell) + { + return new CellContentView(entryCell, container) + { + Content = CreateContent(entryCell) + }; + } + else if (data is TextCell textCell) + { + return new CellContentView(textCell, container) + { + Content = CreateContent(textCell) + }; + } + else if (data is ViewCell viewCell) + { + return new CellContentView(viewCell, container, false) + { + Content = CreateContent(viewCell) + }; + } + else if (data is SwitchCell switchCell) + { + return new CellContentView(switchCell, container) + { + Content = CreateContent(switchCell) + }; + } + else + { + return new StackLayout + { + BackgroundColor = Colors.Red + }; + } + } + + static View CreateContent(SectionCell sectionCell) + { + var text = new Label + { + HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.FillAndExpand, + FontAttributes = FontAttributes.Bold, + Margin = new Thickness(10, 0), + FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)) + }; + + text.SetBinding(Label.TextProperty, new Binding("Text", source: sectionCell)); + text.SetBinding(Label.TextColorProperty, new Binding("TextColor", source: sectionCell)); + + var layout = new StackLayout + { + HorizontalOptions = LayoutOptions.FillAndExpand, + BackgroundColor = Color.FromArgb("#e3f2fd"), + Padding = 5, + Children = + { + text, + } + }; + return layout; + } + + static View CreateContent(TextCell textcell) + { + var text = new Label(); + text.SetBinding(Label.TextProperty, new Binding("Text", source: textcell)); + text.SetBinding(Label.TextColorProperty, new Binding("TextColor", source: textcell)); + text.FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label)); + + var detail = new Label(); + detail.SetBinding(Label.TextProperty, new Binding("Detail", source: textcell)); + detail.SetBinding(Label.TextColorProperty, new Binding("DetailColor", source: textcell)); + detail.FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label)) / 2; + detail.Margin = new Thickness(10, 0, 0, 0); + + var layout = new StackLayout + { + Spacing = 0, + HorizontalOptions = LayoutOptions.FillAndExpand, + Padding = new Thickness(10, 5), + Children = + { + text, + detail, + } + }; + return layout; + } + + static View CreateContent(ImageCell imageCell) + { + var textcell = CreateContent((TextCell)imageCell); + textcell.HorizontalOptions = LayoutOptions.FillAndExpand; + var layout = new Grid + { + HorizontalOptions = LayoutOptions.FillAndExpand, + ColumnDefinitions = + { + new ColumnDefinition + { + Width = new GridLength(2, GridUnitType.Star) + }, + new ColumnDefinition + { + Width = new GridLength(8, GridUnitType.Star) + }, + } + }; + var img = new Image + { + HorizontalOptions = LayoutOptions.Start, + Aspect = Aspect.AspectFit, + }; + img.SetBinding(Image.SourceProperty, new Binding("ImageSource", source: imageCell)); + layout.Children.Add(img, 0, 0); + layout.Children.Add(textcell, 1, 0); + return layout; + } + + static View CreateContent(EntryCell entryCell) + { + var entry = new Entry(); + entry.SetBinding(Entry.TextProperty, new Binding("Text", BindingMode.TwoWay, source: entryCell)); + entry.SetBinding(Entry.PlaceholderProperty, new Binding("Placeholder", source: entryCell)); + entry.SetBinding(InputView.KeyboardProperty, new Binding("Keyboard", source: entryCell)); + entry.SetBinding(Entry.HorizontalTextAlignmentProperty, new Binding("HorizontalTextAlignment", source: entryCell)); + entry.SetBinding(Entry.VerticalTextAlignmentProperty, new Binding("VerticalTextAlignment", source: entryCell)); + + var label = new Label(); + label.SetBinding(Label.TextProperty, new Binding("Label", source: entryCell)); + label.SetBinding(Label.TextColorProperty, new Binding("LabelColor", source: entryCell)); + label.FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label)) / 2; + label.Margin = new Thickness(20, 0, 0, 0); + var layout = new StackLayout + { + HorizontalOptions = LayoutOptions.FillAndExpand, + Children = + { + label, + entry, + } + }; + + return layout; + } + + static View CreateContent(SwitchCell switchCell) + { + var text = new Label + { + HorizontalOptions = LayoutOptions.Start + }; + text.SetBinding(Label.TextProperty, new Binding("Text", source: switchCell)); + + var sw = new Switch + { + HorizontalOptions = LayoutOptions.End + }; + sw.SetBinding(Switch.IsToggledProperty, new Binding("On", BindingMode.TwoWay, source: switchCell)); + sw.SetBinding(Switch.OnColorProperty, new Binding("OnColor", source: switchCell)); + + var layout = new StackLayout + { + Padding = new Thickness(10, 5), + Spacing = 0, + HorizontalOptions = LayoutOptions.FillAndExpand, + Orientation = StackOrientation.Horizontal, + Children = + { + text, + sw + } + }; + return layout; + } + + static View CreateContent(ViewCell viewCell) + { + return viewCell.View; + } + + class CellContentView : ContentView + { + BindableObject _target; + public CellContentView(BindableObject target, BindableObject container = null, bool hasVisualState = true, bool hasSeparator = true) + { + var separator = new BoxView + { + Margin = new Thickness(10, 0), + Color = Color.FromRgb(120, 120, 120), + HeightRequest = 1, + }; + + var content = new ContentPresenter + { + VerticalOptions = LayoutOptions.FillAndExpand, + HorizontalOptions = LayoutOptions.FillAndExpand + }; + + + if (container is ListView listview) + { + if (listview.SeparatorVisibility == SeparatorVisibility.None) + { + separator.IsVisible = false; + } + if (!listview.SeparatorColor.IsDefault()) + { + separator.Color = listview.SeparatorColor; + } + if (listview.RowHeight > 0 && !listview.HasUnevenRows) + { + content.HeightRequest = listview.RowHeight; + } + } + + if (separator.IsVisible && !hasSeparator) + { + separator.IsVisible = false; + } + + + ControlTemplate = new ControlTemplate(() => + { + var layout = new StackLayout + { + Spacing = 0, + VerticalOptions = LayoutOptions.FillAndExpand, + HorizontalOptions = LayoutOptions.FillAndExpand, + Children = + { + content, + separator + } + }; + return layout; + }); + _target = target; + if (hasVisualState) + SetupVisualState(); + } + + void SetupVisualState() + { + VisualStateGroup stateGroup = new VisualStateGroup(); + var selected = new VisualState + { + Name = VisualStateManager.CommonStates.Selected, + TargetType = typeof(View), + Setters = + { + new Setter + { + Property = View.BackgroundColorProperty, + Value = Color.FromArgb("#f9fbe7"), + } + } + }; + + var normal = new VisualState + { + Name = VisualStateManager.CommonStates.Normal, + TargetType = typeof(View), + Setters = + { + new Setter + { + Property = View.BackgroundColorProperty, + Value = Colors.Transparent + } + } + }; + var focused = new VisualState + { + Name = VisualStateManager.CommonStates.Focused, + TargetType = typeof(View), + Setters = + { + new Setter + { + Property = View.BackgroundColorProperty, + Value = Color.FromArgb("#eeeeeeee") + } + } + }; + + var unfocused = new VisualState + { + Name = VisualStateManager.CommonStates.Normal, + TargetType = typeof(View), + Setters = + { + new Setter + { + Property = View.BackgroundColorProperty, + Value = Colors.Transparent + } + } + }; + stateGroup.States.Add(focused); + stateGroup.States.Add(selected); + stateGroup.States.Add(unfocused); + VisualStateManager.GetVisualStateGroups(this).Add(stateGroup); + } + + protected override void OnBindingContextChanged() + { + base.OnBindingContextChanged(); + _target.BindingContext = BindingContext; + } + } + } +} diff --git a/src/Compatibility/Core/src/Tizen/CollectionView/CellWrapperTemplate.cs b/src/Compatibility/Core/src/Tizen/CollectionView/CellWrapperTemplate.cs new file mode 100644 index 000000000000..e04625e2439f --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/CollectionView/CellWrapperTemplate.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using Microsoft.Maui.Controls.Internals; + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + public class CellWrapperTemplateSelector : DataTemplateSelector + { + Dictionary _cache = new Dictionary(); + DataTemplateSelector _selector; + public CellWrapperTemplateSelector(DataTemplateSelector selector) + { + _selector = selector; + } + protected override DataTemplate OnSelectTemplate(object item, BindableObject container) + { + var template = _selector.SelectTemplate(item, container); + if (_cache.ContainsKey(template)) + { + return _cache[template]; + } + var wrapper = new CellWrapperTemplate(template); + _cache[template] = wrapper; + return wrapper; + } + } + + public class CellWrapperTemplate : DataTemplate + { + BindableObject _container; + DataTemplate _sourceTemplate; + + public CellWrapperTemplate(DataTemplate source, BindableObject container = null) + { + _container = container; + _sourceTemplate = source; + + LoadTemplate = () => CellContentFactory.CreateContent(_sourceTemplate.CreateContent(), _container); + } + } +} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/EmptyItemAdaptor.cs b/src/Compatibility/Core/src/Tizen/CollectionView/EmptyItemAdaptor.cs similarity index 54% rename from src/Compatibility/Core/src/Tizen/Native/CollectionView/EmptyItemAdaptor.cs rename to src/Compatibility/Core/src/Tizen/CollectionView/EmptyItemAdaptor.cs index f194c7e3a678..60bce3413649 100644 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/EmptyItemAdaptor.cs +++ b/src/Compatibility/Core/src/Tizen/CollectionView/EmptyItemAdaptor.cs @@ -1,14 +1,13 @@ using System.Collections; using System.Collections.Generic; -using ElmSharp; -using ESize = ElmSharp.Size; +using NView = Tizen.NUI.BaseComponents.View; +using TSize = Tizen.UIExtensions.Common.Size; using XLabel = Microsoft.Maui.Controls.Label; -using XStackLayout = Microsoft.Maui.Controls.StackLayout; -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { [System.Obsolete] - public class EmptyItemAdaptor : ItemTemplateAdaptor, IEmptyAdaptor + public class EmptyItemAdaptor : ItemTemplateAdaptor { static DataTemplate s_defaultEmptyTemplate = new DataTemplate(typeof(EmptyView)); @@ -32,33 +31,22 @@ public static EmptyItemAdaptor Create(ItemsView itemsView) { template = itemsView.EmptyViewTemplate ?? s_defaultEmptyTemplate; } - var empty = new List - { - itemsView.EmptyView ?? new object() - }; - return new EmptyItemAdaptor(itemsView, empty, template); + + return new EmptyItemAdaptor(itemsView, new List(), template); } - public override ESize MeasureItem(int widthConstraint, int heightConstraint) + public override NView GetFooterView() { - return new ESize(widthConstraint, heightConstraint); + return null; } - public override EvasObject CreateNativeView(int index, EvasObject parent) + public override NView GetHeaderView() { - View emptyView = null; - if (ItemTemplate is DataTemplateSelector selector) - { - emptyView = selector.SelectTemplate(this[index], Element).CreateContent() as View; - } - else - { - emptyView = ItemTemplate.CreateContent() as View; - } + View emptyView = ItemTemplate.CreateContent() as View; var header = CreateHeaderView(); var footer = CreateFooterView(); - var layout = new XStackLayout(); + var layout = new StackLayout(); if (header != null) { @@ -76,12 +64,17 @@ public override EvasObject CreateNativeView(int index, EvasObject parent) return renderer.NativeView; } - public override void RemoveNativeView(EvasObject native) + public override TSize MeasureHeader(double widthConstraint, double heightConstraint) + { + return base.MeasureHeader(widthConstraint, heightConstraint); + } + + public override TSize MeasureItem(double widthConstraint, double heightConstraint) { - native.Unrealize(); + return new TSize(widthConstraint, heightConstraint); } - class EmptyView : XStackLayout + class EmptyView : StackLayout { public EmptyView() { @@ -91,10 +84,10 @@ public EmptyView() new XLabel { Text = "No items found", - VerticalOptions = LayoutOptions.Center, - HorizontalOptions = LayoutOptions.Center, - HorizontalTextAlignment = Maui.TextAlignment.Center, - VerticalTextAlignment = Maui.TextAlignment.Center, + VerticalOptions = LayoutOptions.CenterAndExpand, + HorizontalOptions = LayoutOptions.CenterAndExpand, + HorizontalTextAlignment = TextAlignment.Center, + VerticalTextAlignment = TextAlignment.Center, } ); } diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemTemplateAdaptor.cs b/src/Compatibility/Core/src/Tizen/CollectionView/ItemTemplateAdaptor.cs similarity index 66% rename from src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemTemplateAdaptor.cs rename to src/Compatibility/Core/src/Tizen/CollectionView/ItemTemplateAdaptor.cs index 20d73bbb5876..93e2695dd92a 100644 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemTemplateAdaptor.cs +++ b/src/Compatibility/Core/src/Tizen/CollectionView/ItemTemplateAdaptor.cs @@ -2,54 +2,23 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; -using ElmSharp; -using ESize = ElmSharp.Size; +using Microsoft.Maui.Graphics; +using Tizen.UIExtensions.NUI; +using NView = Tizen.NUI.BaseComponents.View; +using TSize = Tizen.UIExtensions.Common.Size; using XLabel = Microsoft.Maui.Controls.Label; -using XColor = Microsoft.Maui.Graphics.Color; -using XStackLayout = Microsoft.Maui.Controls.StackLayout; -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { - [Obsolete] - public class ItemDefaultTemplateAdaptor : ItemTemplateAdaptor + public class CollectionViewSelectionChangedEventArgs : EventArgs { - class ToTextConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value?.ToString() ?? string.Empty; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException(); - } - - public ItemDefaultTemplateAdaptor(ItemsView itemsView) : base(itemsView) - { - ItemTemplate = new DataTemplate(() => - { - var label = new XLabel - { - TextColor = XColor.FromRgb(0, 0, 0), - }; - label.SetBinding(XLabel.TextProperty, new Binding(".", converter: new ToTextConverter())); - - return new XStackLayout - { - BackgroundColor = XColor.FromRgb(255, 255, 255), - Padding = 30, - Children = - { - label - } - }; - }); - } + public IList SelectedItems { get; set; } } [Obsolete] public class ItemTemplateAdaptor : ItemAdaptor { - Dictionary _nativeFormsTable = new Dictionary(); + Dictionary _nativeFormsTable = new Dictionary(); Dictionary _dataBindedViewTable = new Dictionary(); protected View _headerCache; protected View _footerCache; @@ -63,15 +32,53 @@ protected ItemTemplateAdaptor(Element itemsView, IEnumerable items, DataTemplate IsSelectable = itemsView is SelectableItemsView; } + public event EventHandler SelectionChanged; + protected DataTemplate ItemTemplate { get; set; } protected Element Element { get; set; } protected virtual bool IsSelectable { get; } - public View GetTemplatedView(EvasObject evasObject) + public override void SendItemSelected(IEnumerable selected) { - return _nativeFormsTable[evasObject]; + var items = new List(); + foreach (var item in selected) + { + items.Add(this[item]); + } + SelectionChanged?.Invoke(this, new CollectionViewSelectionChangedEventArgs + { + SelectedItems = items + }); + } + + public override void UpdateViewState(NView view, ViewHolderState state) + { + base.UpdateViewState(view, state); + if (_nativeFormsTable.TryGetValue(view, out View formsView)) + { + switch (state) + { + case ViewHolderState.Focused: + VisualStateManager.GoToState(formsView, VisualStateManager.CommonStates.Focused); + formsView.SetValue(VisualElement.IsFocusedPropertyKey, true); + break; + case ViewHolderState.Normal: + VisualStateManager.GoToState(formsView, VisualStateManager.CommonStates.Normal); + formsView.SetValue(VisualElement.IsFocusedPropertyKey, false); + break; + case ViewHolderState.Selected: + if (IsSelectable) + VisualStateManager.GoToState(formsView, VisualStateManager.CommonStates.Selected); + break; + } + } + } + + public View GetTemplatedView(NView view) + { + return _nativeFormsTable[view]; } public View GetTemplatedView(int index) @@ -93,7 +100,7 @@ public override object GetViewCategory(int index) return base.GetViewCategory(index); } - public override EvasObject CreateNativeView(int index, EvasObject parent) + public override NView CreateNativeView(int index) { View view = null; if (ItemTemplate is DataTemplateSelector selector) @@ -114,12 +121,12 @@ public override EvasObject CreateNativeView(int index, EvasObject parent) return native; } - public override EvasObject CreateNativeView(EvasObject parent) + public override NView CreateNativeView() { - return CreateNativeView(0, parent); + return CreateNativeView(0); } - public override EvasObject GetHeaderView(EvasObject parent) + public override NView GetHeaderView() { _headerCache = CreateHeaderView(); if (_headerCache != null) @@ -132,7 +139,7 @@ public override EvasObject GetHeaderView(EvasObject parent) return null; } - public override EvasObject GetFooterView(EvasObject parent) + public override NView GetFooterView() { _footerCache = CreateFooterView(); if (_footerCache != null) @@ -145,7 +152,7 @@ public override EvasObject GetFooterView(EvasObject parent) return null; } - public override void RemoveNativeView(EvasObject native) + public override void RemoveNativeView(NView native) { UnBinding(native); if (_nativeFormsTable.TryGetValue(native, out View view)) @@ -155,20 +162,20 @@ public override void RemoveNativeView(EvasObject native) } } - public override void SetBinding(EvasObject native, int index) + public override void SetBinding(NView native, int index) { if (_nativeFormsTable.TryGetValue(native, out View view)) { ResetBindedView(view); view.BindingContext = this[index]; _dataBindedViewTable[this[index]] = view; - view.MeasureInvalidated += OnItemMeasureInvalidated; + AddLogicalChild(view); } } - public override void UnBinding(EvasObject native) + public override void UnBinding(NView native) { if (_nativeFormsTable.TryGetValue(native, out View view)) { @@ -177,16 +184,27 @@ public override void UnBinding(EvasObject native) } } - public override ESize MeasureItem(int widthConstraint, int heightConstraint) + public override TSize MeasureItem(double widthConstraint, double heightConstraint) { return MeasureItem(0, widthConstraint, heightConstraint); } - public override ESize MeasureItem(int index, int widthConstraint, int heightConstraint) + public override TSize MeasureItem(int index, double widthConstraint, double heightConstraint) { + if (index < 0 || index >= Count) + return new TSize(0, 0); + + widthConstraint = Forms.ConvertToScaledDP(widthConstraint); + heightConstraint = Forms.ConvertToScaledDP(heightConstraint); + // TODO. It is hack code, it should be updated by Tizen.UIExtensions + if (widthConstraint > heightConstraint) + widthConstraint = double.PositiveInfinity; + else + heightConstraint = double.PositiveInfinity; + if (_dataBindedViewTable.TryGetValue(this[index], out View createdView) && createdView != null) { - return createdView.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint), MeasureFlags.IncludeMargins).Request.ToEFLPixel(); + return createdView.Measure(widthConstraint, heightConstraint, MeasureFlags.IncludeMargins).Request.ToPixel(); } View view = null; @@ -203,42 +221,19 @@ public override ESize MeasureItem(int index, int widthConstraint, int heightCons view.Parent = Element; if (Count > index) view.BindingContext = this[index]; - var request = view.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint), MeasureFlags.IncludeMargins).Request; - return request.ToEFLPixel(); + var request = view.Measure(widthConstraint, heightConstraint, MeasureFlags.IncludeMargins).Request; + return request.ToPixel(); } } - public override ESize MeasureHeader(int widthConstraint, int heightConstraint) - { - return _headerCache?.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint)).Request.ToEFLPixel() ?? new ESize(0, 0); - } - - public override ESize MeasureFooter(int widthConstraint, int heightConstraint) + public override TSize MeasureHeader(double widthConstraint, double heightConstraint) { - return _footerCache?.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint)).Request.ToEFLPixel() ?? new ESize(0, 0); + return _headerCache?.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint)).Request.ToPixel() ?? new TSize(0, 0); } - public override void UpdateViewState(EvasObject view, ViewHolderState state) + public override TSize MeasureFooter(double widthConstraint, double heightConstraint) { - base.UpdateViewState(view, state); - if (_nativeFormsTable.TryGetValue(view, out View formsView)) - { - switch (state) - { - case ViewHolderState.Focused: - VisualStateManager.GoToState(formsView, VisualStateManager.CommonStates.Focused); - formsView.SetValue(VisualElement.IsFocusedPropertyKey, true); - break; - case ViewHolderState.Normal: - VisualStateManager.GoToState(formsView, VisualStateManager.CommonStates.Normal); - formsView.SetValue(VisualElement.IsFocusedPropertyKey, false); - break; - case ViewHolderState.Selected: - if (IsSelectable) - VisualStateManager.GoToState(formsView, VisualStateManager.CommonStates.Selected); - break; - } - } + return _footerCache?.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint)).Request.ToPixel() ?? new TSize(0, 0); } protected virtual View CreateHeaderView() @@ -283,7 +278,7 @@ protected virtual View CreateFooterView() footer = structuredItemsView.FooterTemplate.CreateContent() as View; footer.BindingContext = structuredItemsView.Footer; } - else if (structuredItemsView.Footer is String str) + else if (structuredItemsView.Footer is string str) { footer = new XLabel { Text = str, }; } @@ -338,4 +333,69 @@ void RemoveLogicalChild(Element element) } } + + public class ItemDefaultTemplateAdaptor : ItemTemplateAdaptor + { + class ToTextConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value?.ToString() ?? string.Empty; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException(); + } + + public ItemDefaultTemplateAdaptor(ItemsView itemsView) : base(itemsView) + { + ItemTemplate = new DataTemplate(() => + { + var label = new XLabel + { + TextColor = Colors.Black, + }; + label.SetBinding(XLabel.TextProperty, new Binding(".", converter: new ToTextConverter())); + + return new StackLayout + { + BackgroundColor = Colors.White, + Padding = 30, + Children = + { + label + } + }; + }); + } + } + + public class CarouselViewItemTemplateAdaptor : ItemTemplateAdaptor + { + public CarouselViewItemTemplateAdaptor(ItemsView itemsView) : base(itemsView) { } + + public override TSize MeasureItem(double widthConstraint, double heightConstraint) + { + return MeasureItem(0, widthConstraint, heightConstraint); + } + + public override TSize MeasureItem(int index, double widthConstraint, double heightConstraint) + { + return (CollectionView as NView).Size.ToCommon(); + } + } + + public class CarouselViewItemDefaultTemplateAdaptor : ItemDefaultTemplateAdaptor + { + public CarouselViewItemDefaultTemplateAdaptor(ItemsView itemsView) : base(itemsView) { } + + public override TSize MeasureItem(double widthConstraint, double heightConstraint) + { + return MeasureItem(0, widthConstraint, heightConstraint); + } + + public override TSize MeasureItem(int index, double widthConstraint, double heightConstraint) + { + return (CollectionView as NView).Size.ToCommon(); + } + } } diff --git a/src/Compatibility/Core/src/Tizen/CollectionView/ListViewAdaptor.cs b/src/Compatibility/Core/src/Tizen/CollectionView/ListViewAdaptor.cs new file mode 100644 index 000000000000..5f6b93caa83b --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/CollectionView/ListViewAdaptor.cs @@ -0,0 +1,49 @@ +using System.Collections; +using TSize = Tizen.UIExtensions.Common.Size; + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + public class ListViewAdaptor : ItemTemplateAdaptor + { + new ListView Element { get; set; } + + public ListViewAdaptor(ListView listview, IEnumerable items, DataTemplate template) : base(listview, items, template) + { + Element = listview; + } + + protected override bool IsSelectable => (Element?.SelectionMode ?? ListViewSelectionMode.None) == ListViewSelectionMode.Single; + + public override TSize MeasureItem(double widthConstraint, double heightConstraint) + { + if (Element.RowHeight > 0) + { + return new TSize(widthConstraint, Element.RowHeight); + } + return MeasureItem(0, widthConstraint, heightConstraint); + } + + public override TSize MeasureItem(int index, double widthConstraint, double heightConstraint) + { + if (index < 0 || index >= Element.TemplatedItems.Count) + return new TSize(0, 0); + + var cell = Element.TemplatedItems[index]; + if (cell.RenderHeight > 0) + { + return new TSize(widthConstraint, cell.RenderHeight); + } + return base.MeasureItem(index, widthConstraint, heightConstraint); + } + + protected override View CreateHeaderView() + { + return Element.HeaderElement as View; + } + + protected override View CreateFooterView() + { + return Element.FooterElement as View; + } + } +} diff --git a/src/Compatibility/Core/src/Tizen/CollectionView/TableViewAdaptor.cs b/src/Compatibility/Core/src/Tizen/CollectionView/TableViewAdaptor.cs new file mode 100644 index 000000000000..e0a676919e3f --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/CollectionView/TableViewAdaptor.cs @@ -0,0 +1,34 @@ +using System.Collections; +using TSize = Tizen.UIExtensions.Common.Size; + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + public class TableViewAdaptor : ItemTemplateAdaptor + { + new TableView Element { get; set; } + + public TableViewAdaptor(TableView tableView, IEnumerable items, DataTemplate template) : base(tableView, items, template) + { + Element = tableView; + } + + protected override bool IsSelectable => true; + + public override TSize MeasureItem(double widthConstraint, double heightConstraint) + { + if (Element.RowHeight > 0) + { + return new TSize(widthConstraint, Element.RowHeight); + } + return MeasureItem(0, widthConstraint, heightConstraint); + } + + public override TSize MeasureItem(int index, double widthConstraint, double heightConstraint) + { + if (index < 0 || index >= Count) + return new TSize(0, 0); + + return base.MeasureItem(index, widthConstraint, heightConstraint); + } + } +} diff --git a/src/Compatibility/Core/src/Tizen/DragGestureHandler.cs b/src/Compatibility/Core/src/Tizen/DragGestureHandler.cs deleted file mode 100644 index dc1e4001adb0..000000000000 --- a/src/Compatibility/Core/src/Tizen/DragGestureHandler.cs +++ /dev/null @@ -1,247 +0,0 @@ -using System; -using System.Threading; -using ElmSharp; -using Tizen.Common; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp; -using EGestureType = ElmSharp.GestureLayer.GestureType; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [Obsolete] - public class DragGestureHandler : GestureHandler - { - bool _isApi4; - - DragDropExtensions.Interop.DragIconCreateCallback _iconCallback; - DragDropExtensions.Interop.DragStateCallback _dragDoneCallback; - - static bool s_isDragging; - static CustomDragStateData s_currentDragStateData; - - public DragGestureHandler(IGestureRecognizer recognizer, IVisualElementRenderer renderer) : base(recognizer) - { - _iconCallback = OnIconCallback; - _dragDoneCallback = OnDragDoneCallback; - _isApi4 = DotnetUtil.TizenAPIVersion <= 4; - Renderer = renderer; - } - - public override EGestureType Type => EGestureType.LongTap; - - public IVisualElementRenderer Renderer { get; } - - public static CustomDragStateData CurrentStateData - { - get - { - return s_currentDragStateData; - } - } - - EvasObject NativeView - { - get - { - var native = Renderer.NativeView; - if (Renderer is SkiaSharp.ICanvasRenderer canvasRenderer) - { - native = canvasRenderer.RealNativeView; - } - return native; - } - } - - public void ResetCurrentStateData() - { - s_currentDragStateData = null; - } - - protected override void OnStarted(View sender, object data) - { - } - - protected override void OnMoved(View sender, object data) - { - //Workaround to prevent an error occuring by multiple StartDrag calling in Tizen 6.5 - if (!s_isDragging) - { - ResetCurrentStateData(); - StartDrag(); - } - } - - protected override void OnCompleted(View sender, object data) - { - } - - protected override void OnCanceled(View sender, object data) - { - } - - void StartDrag() - { - if (Recognizer is DragGestureRecognizer dragGestureRecognizer && dragGestureRecognizer.CanDrag) - { - if (Renderer == null) - return; - - if (Renderer.Element is not View view) - return; - - var arg = dragGestureRecognizer.SendDragStarting(view); - - if (arg.Cancel) - return; - - s_currentDragStateData = new CustomDragStateData(); - s_currentDragStateData.DataPackage = arg.Data; - - var target = DragDropExtensions.DragDropContentType.Text; - var strData = string.IsNullOrEmpty(arg.Data.Text) ? " " : arg.Data.Text; - - s_isDragging = true; - - DragDropExtensions.StartDrag(NativeView, - target, - strData, - DragDropExtensions.DragDropActionType.Move, - _iconCallback, - null, - null, - _dragDoneCallback); - } - } - - IntPtr OnIconCallback(IntPtr data, IntPtr window, ref int xoff, ref int yoff) - { - EvasObject icon = null; - EvasObject parent = new CustomWindow(NativeView, window); - - if (s_currentDragStateData.DataPackage.Image != null) - { - icon = GetImageIcon(parent); - } - else if (NativeView is ShapeView) - { - icon = GetShapeView(parent); - } - else - { - icon = GetDefaultIcon(parent); - } - var bound = NativeView.Geometry; - bound.X = 0; - bound.Y = 0; - icon.Geometry = bound; - - if (icon is Native.Label) - { - icon.Resized += (s, e) => - { - var map = new EvasMap(4); - map.PopulatePoints(icon.Geometry, 0); - map.Zoom(0.5, 0.5, 0, 0); - icon.IsMapEnabled = true; - icon.EvasMap = map; - }; - } - else - { - var map = new EvasMap(4); - map.PopulatePoints(icon.Geometry, 0); - map.Zoom(0.5, 0.5, 0, 0); - icon.IsMapEnabled = true; - icon.EvasMap = map; - } - - - return icon; - } - - EvasObject GetDefaultIcon(EvasObject parent) - { - if (!string.IsNullOrEmpty(s_currentDragStateData.DataPackage.Text)) - { - var label = new Native.Label(parent); - label.Text = s_currentDragStateData.DataPackage.Text; - - if (Renderer.Element is Label lb) - label.FontSize = lb.FontSize; - else if (Renderer.Element is Entry et) - label.FontSize = et.FontSize; - else if (Renderer.Element is Editor ed) - label.FontSize = ed.FontSize; - - return label; - } - else - { - var box = new ElmSharp.Rectangle(parent); - box.Color = new ElmSharp.Color(128, 128, 128, 128); - return box; - } - } - - EvasObject GetImageIcon(EvasObject parent) - { - var image = new Native.Image(parent); - _ = image.LoadFromImageSourceAsync(s_currentDragStateData.DataPackage.Image); - return image; - } - - EvasObject GetShapeView(EvasObject parent) - { - var copiedImg = new EvasImage(parent); - copiedImg.IsFilled = true; - - if (NativeView is ShapeView shapeView) - { - var canvas = shapeView.SKCanvasView; - var realHandle = DragDropExtensions.Interop.elm_object_part_content_get(canvas, "elm.swallow.content"); - - DragDropExtensions.Interop.evas_object_image_size_get(realHandle, out int w, out int h); - DragDropExtensions.Interop.evas_object_image_size_set(copiedImg, w, h); - - var imgData = DragDropExtensions.Interop.evas_object_image_data_get(realHandle, false); - DragDropExtensions.Interop.evas_object_image_data_set(copiedImg, imgData); - } - - return copiedImg; - } - - void OnDragDoneCallback(IntPtr data, IntPtr obj) - { - s_isDragging = false; - if (Recognizer is DragGestureRecognizer dragGestureRecognizer && dragGestureRecognizer.CanDrag) - { - dragGestureRecognizer.SendDropCompleted(new DropCompletedEventArgs()); - } - } - - public class CustomWindow : EvasObject - { - IntPtr _handle; - - public CustomWindow(EvasObject parent, IntPtr handle) : base() - { - _handle = handle; - Realize(parent); - } - - public CustomWindow(EvasObject handle) : base(handle) - { - } - - protected override IntPtr CreateHandle(EvasObject parent) - { - return _handle; - } - } - - public class CustomDragStateData - { - public DataPackage DataPackage { get; set; } - public DataPackageOperation AcceptedOperation { get; set; } = DataPackageOperation.Copy; - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/DropGestureHandler.cs b/src/Compatibility/Core/src/Tizen/DropGestureHandler.cs deleted file mode 100644 index 13b73ae158f2..000000000000 --- a/src/Compatibility/Core/src/Tizen/DropGestureHandler.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Linq; -using ElmSharp; -using Tizen.Common; -using EGestureType = ElmSharp.GestureLayer.GestureType; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [Obsolete] - public class DropGestureHandler : GestureHandler - { - bool _isApi4; - - DragDropExtensions.Interop.DragStateCallback _dragEnterCallback; - DragDropExtensions.Interop.DragStateCallback _dragLeaveCallback; - DragDropExtensions.Interop.DropCallback _dropCallback; - - public override EGestureType Type => default(EGestureType); - - public DropGestureHandler(IGestureRecognizer recognizer, IVisualElementRenderer renderer) : base(recognizer) - { - _dragEnterCallback = OnEnterCallback; - _dragLeaveCallback = OnLeaveCallback; - _dropCallback = OnDropCallback; - _isApi4 = DotnetUtil.TizenAPIVersion <= 4; - Renderer = renderer; - } - - public IVisualElementRenderer Renderer { get; } - - EvasObject NativeView - { - get - { - var native = Renderer.NativeView; - if (Renderer is SkiaSharp.ICanvasRenderer canvasRenderer) - { - native = canvasRenderer.RealNativeView; - } - - if (native is Native.Canvas canvas) - { - var child = canvas.Children.LastOrDefault(); - - if (child != null) - { - if (child.PassEvents) - child.PassEvents = false; - - return child; - } - } - return native; - } - } - - - public void AddDropGesture() - { - if (Renderer == null) - return; - - var target = DragDropExtensions.DragDropContentType.Targets; - - DragDropExtensions.AddDropTarget(NativeView, - target, - _dragEnterCallback, - _dragLeaveCallback, null, - _dropCallback); - } - - void OnEnterCallback(IntPtr data, IntPtr obj) - { - var currentStateData = DragGestureHandler.CurrentStateData; - if (currentStateData == null) - return; - - var arg = new DragEventArgs(currentStateData.DataPackage); - - if (Recognizer is DropGestureRecognizer dropRecognizer && dropRecognizer.AllowDrop) - dropRecognizer.SendDragOver(arg); - - DragGestureHandler.CurrentStateData.AcceptedOperation = arg.AcceptedOperation; - } - - void OnLeaveCallback(IntPtr data, IntPtr obj) - { - var currentStateData = DragGestureHandler.CurrentStateData; - if (currentStateData == null) - return; - - var arg = new DragEventArgs(currentStateData.DataPackage); - - if (Recognizer is DropGestureRecognizer dropRecognizer && dropRecognizer.AllowDrop) - dropRecognizer.SendDragLeave(arg); - - DragGestureHandler.CurrentStateData.AcceptedOperation = arg.AcceptedOperation; - } - - bool OnDropCallback(IntPtr data, IntPtr obj, IntPtr selectionData) - { - var currentStateData = DragGestureHandler.CurrentStateData; - - if (currentStateData.DataPackage == null || currentStateData.AcceptedOperation == DataPackageOperation.None) - return false; - - Application.Current?.Dispatcher.Dispatch(async () => - { - if (Recognizer is DropGestureRecognizer dropRecognizer && dropRecognizer.AllowDrop) - await dropRecognizer.SendDrop(new DropEventArgs(currentStateData.DataPackage.View)); - }); - - return true; - } - - #region GestureHandler - protected override void OnStarted(View sender, object data) - { - } - - protected override void OnMoved(View sender, object data) - { - } - - protected override void OnCompleted(View sender, object data) - { - } - - protected override void OnCanceled(View sender, object data) - { - } - #endregion - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Extensions/AccessibilityExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/AccessibilityExtensions.cs deleted file mode 100644 index 31d5923c59f0..000000000000 --- a/src/Compatibility/Core/src/Tizen/Extensions/AccessibilityExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -using ElmSharp.Accessible; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [System.Obsolete] - public static class AccessibilityExtensions - { - public static string SetAccessibilityName(this IAccessibleObject Control, Element Element, string _defaultAccessibilityName = null) - { - if (Element == null || Control == null) - return _defaultAccessibilityName; - - if (_defaultAccessibilityName == null) - _defaultAccessibilityName = Control.Name; - - Control.Name = (string)Element.GetValue(AutomationProperties.NameProperty) ?? _defaultAccessibilityName; - return _defaultAccessibilityName; - } - - public static string SetAccessibilityDescription(this IAccessibleObject Control, Element Element, string _defaultAccessibilityDescription = null) - { - if (Element == null || Control == null) - return _defaultAccessibilityDescription; - - if (_defaultAccessibilityDescription == null) - _defaultAccessibilityDescription = Control.Description; - - Control.Description = (string)Element.GetValue(AutomationProperties.HelpTextProperty) ?? _defaultAccessibilityDescription; - return _defaultAccessibilityDescription; - } - - public static bool? SetIsAccessibilityElement(this IAccessibleObject Control, Element Element, bool? _defaultIsAccessibilityElement = null) - { - if (Element == null || Control == null) - return _defaultIsAccessibilityElement; - - if (!_defaultIsAccessibilityElement.HasValue) - _defaultIsAccessibilityElement = Control.CanHighlight; - - Control.CanHighlight = (bool)((bool?)Element.GetValue(AutomationProperties.IsInAccessibleTreeProperty) ?? _defaultIsAccessibilityElement); - - // Images are ignored by default on Tizen. So, make accessible in order to enable the gesture and narration - if (Control.CanHighlight && Element is Image) - { - Control.Role = AccessRole.PushButton; - } - return _defaultIsAccessibilityElement; - } - - public static void SetLabeledBy(this IAccessibleObject Control, Element Element) - { - if (Element == null || Control == null) - return; - - var targetElement = (VisualElement)Element.GetValue(AutomationProperties.LabeledByProperty); - AccessibleObject view = (AccessibleObject)Platform.GetRenderer(targetElement)?.NativeView; - if (view != null) - { - Control.AppendRelation(new LabelledBy() { Target = view }); - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Extensions/BrushExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/BrushExtensions.cs index 4d641e206cc8..1f78c07e5ce3 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/BrushExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/BrushExtensions.cs @@ -1,8 +1,9 @@ using System; using System.Linq; +using Microsoft.Maui.Graphics; using SkiaSharp; using SkiaSharp.Views.Tizen; -using Microsoft.Maui.Graphics; +using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -83,7 +84,7 @@ public static SKShader CreateShader(this GradientBrush gradientBrush, SKRect bou public static SKColor ToSolidColor(this SolidColorBrush solidColorBrush) { - return solidColorBrush.Color.IsDefault() ? SKColor.Empty : solidColorBrush.Color.ToNative().ToSKColor(); + return solidColorBrush.Color.IsDefault() ? SKColor.Empty : solidColorBrush.Color.ToNativeEFL().ToSKColor(); } static SKShader CreateLinearGradient(LinearGradientBrush linearGradientBrush, SKRect pathBounds) @@ -91,7 +92,7 @@ static SKShader CreateLinearGradient(LinearGradientBrush linearGradientBrush, SK var startPoint = new SKPoint(pathBounds.Left + (float)linearGradientBrush.StartPoint.X * pathBounds.Width, pathBounds.Top + (float)linearGradientBrush.StartPoint.Y * pathBounds.Height); var endPoint = new SKPoint(pathBounds.Left + (float)linearGradientBrush.EndPoint.X * pathBounds.Width, pathBounds.Top + (float)linearGradientBrush.EndPoint.Y * pathBounds.Height); var orderedGradientStops = linearGradientBrush.GradientStops.OrderBy(x => x.Offset).ToList(); - var gradientColors = orderedGradientStops.Select(x => x.Color.ToNative().ToSKColor()).ToArray(); + var gradientColors = orderedGradientStops.Select(x => x.Color.ToNativeEFL().ToSKColor()).ToArray(); var gradientColorPos = orderedGradientStops.Select(x => x.Offset).ToArray(); return SKShader.CreateLinearGradient(startPoint, endPoint, gradientColors, gradientColorPos, SKShaderTileMode.Clamp); } @@ -101,9 +102,14 @@ static SKShader CreateRadialGradient(RadialGradientBrush radialGradientBrush, SK var center = new SKPoint((float)radialGradientBrush.Center.X * pathBounds.Width + pathBounds.Left, (float)radialGradientBrush.Center.Y * pathBounds.Height + pathBounds.Top); var radius = (float)radialGradientBrush.Radius * Math.Max(pathBounds.Height, pathBounds.Width); var orderedGradientStops = radialGradientBrush.GradientStops.OrderBy(x => x.Offset).ToList(); - var gradientColors = orderedGradientStops.Select(x => x.Color.ToNative().ToSKColor()).ToArray(); + var gradientColors = orderedGradientStops.Select(x => x.Color.ToNativeEFL().ToSKColor()).ToArray(); var gradientColorPos = orderedGradientStops.Select(x => x.Offset).ToArray(); return SKShader.CreateRadialGradient(center, radius, gradientColors, gradientColorPos, SKShaderTileMode.Clamp); } + + public static EColor ToNativeEFL(this Color c) + { + return c == null ? EColor.Default : new EColor((int)(255.0 * c.Red), (int)(255.0 * c.Green), (int)(255.0 * c.Blue), (int)(255.0 * c.Alpha)); + } } } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs index 0f86966258f1..09674b182621 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs @@ -1,5 +1,5 @@ using Microsoft.Maui.Graphics; -using EColor = ElmSharp.Color; +using TColor = Tizen.UIExtensions.Common.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -10,16 +10,16 @@ public static class ColorExtensions /// /// ElmSharp.Color instance representing a color which corresponds to the provided Microsoft.Maui.Controls.Compatibility.Color /// The Microsoft.Maui.Controls.Compatibility.Color instance which will be converted to a ElmSharp.Color - public static EColor ToNative(this Color c) + public static TColor ToNative(this Color c) { if (c == null) { // Trying to convert the default color, this may result in black color. - return EColor.Default; + return TColor.Default; } else { - return new EColor((int)(255.0 * c.Red), (int)(255.0 * c.Green), (int)(255.0 * c.Blue), (int)(255.0 * c.Alpha)); + return new TColor(c.Red, c.Green, c.Blue, c.Alpha); } } @@ -32,19 +32,5 @@ public static Color WithPremultiplied(this Color color, double alpha) { return new Color((int)(color.Red * alpha), (int)(color.Green * alpha), (int)(color.Blue * alpha), color.Alpha); } - - /// - /// Returns a string representing the provided ElmSharp.Color instance in a hexagonal notation - /// - /// string value containing the encoded color - /// The ElmSharp.Color class instance which will be serialized - internal static string ToHex(this EColor c) - { - if (c.IsDefault) - { - Log.Warn("Trying to convert the default color to hexagonal notation, it does not works as expected."); - } - return string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", c.R, c.G, c.B, c.A); - } } } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs index fb5402569265..c67889f81364 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs @@ -1,7 +1,8 @@ using Microsoft.Maui.Graphics; using Rect = Microsoft.Maui.Graphics.Rect; -using ERect = ElmSharp.Rect; -using ESize = ElmSharp.Size; +using TRect = Tizen.UIExtensions.Common.Rect; +using TSize = Tizen.UIExtensions.Common.Size; +using NSize = Tizen.NUI.Size2D; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -10,24 +11,29 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// public static class DensityIndependentPixelExtensions { - public static Rect ToDP(this ERect rect) + public static Rect ToDP(this TRect rect) { return new Rect(Forms.ConvertToScaledDP(rect.X), Forms.ConvertToScaledDP(rect.Y), Forms.ConvertToScaledDP(rect.Width), Forms.ConvertToScaledDP(rect.Height)); } - public static ERect ToPixel(this Rect rect) + public static TRect ToPixel(this Rect rect) { - return new ERect(Forms.ConvertToScaledPixel(rect.X), Forms.ConvertToScaledPixel(rect.Y), Forms.ConvertToScaledPixel(rect.Width), Forms.ConvertToScaledPixel(rect.Height)); + return new TRect(Forms.ConvertToScaledPixel(rect.X), Forms.ConvertToScaledPixel(rect.Y), Forms.ConvertToScaledPixel(rect.Width), Forms.ConvertToScaledPixel(rect.Height)); } - public static Size ToDP(this ESize size) + public static Size ToDP(this TSize size) { return new Size(Forms.ConvertToScaledDP(size.Width), Forms.ConvertToScaledDP(size.Height)); } - public static ESize ToPixel(this Size size) + public static Size ToDP(this NSize size) { - return new ESize(Forms.ConvertToScaledPixel(size.Width), Forms.ConvertToScaledPixel(size.Height)); + return new Size(Forms.ConvertToScaledDP(size.Width), Forms.ConvertToScaledDP(size.Height)); + } + + public static TSize ToPixel(this Size size) + { + return new TSize(Forms.ConvertToScaledPixel(size.Width), Forms.ConvertToScaledPixel(size.Height)); } } } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/DragDropExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/DragDropExtensions.cs deleted file mode 100644 index 77a9ccf0603d..000000000000 --- a/src/Compatibility/Core/src/Tizen/Extensions/DragDropExtensions.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - public static class DragDropExtensions - { - public static void AddDropTarget(EvasObject obj, DragDropContentType contentType, - Interop.DragStateCallback enterCallback, - Interop.DragStateCallback leaveCallback, - Interop.DragPositionCallback positionCallback, - Interop.DropCallback dropCallback) - { - Interop.elm_drop_target_add(obj.RealHandle, contentType, - enterCallback, IntPtr.Zero, - leaveCallback, IntPtr.Zero, - positionCallback, IntPtr.Zero, - dropCallback, IntPtr.Zero); - } - - public static void StartDrag(EvasObject obj, DragDropContentType contentType, - string data, DragDropActionType actionType, - Interop.DragIconCreateCallback iconCallback, - Interop.DragPositionCallback positionCallback, - Interop.DragAcceptCallback acceptCallback, - Interop.DragStateCallback statCallback) - { - var strData = Marshal.StringToHGlobalAnsi(data); - Interop.elm_drag_start(obj.RealHandle, contentType, strData, actionType, - iconCallback, IntPtr.Zero, - positionCallback, IntPtr.Zero, - acceptCallback, IntPtr.Zero, - statCallback, IntPtr.Zero); - } - - public enum DragDropContentType - { - Targets = -1, - None = 0, - Text = 1, - MarkUp = 2, - Image = 4, - VCard = 8, - Html = 16 - } - - public enum DragDropActionType - { - Unknown = 0, - Copy, - Move, - Private, - Ask, - List, - Link, - Description - } - - public class Interop - { - public const string LibElementary = "libelementary.so.1"; - public const string LibEvas = "libevas.so.1"; - - - public delegate IntPtr DragIconCreateCallback(IntPtr data, IntPtr window, ref int xoff, ref int yoff); - public delegate void DragPositionCallback(IntPtr data, IntPtr obj, int x, int y, int actionType); - public delegate void DragAcceptCallback(IntPtr data, IntPtr obj, bool accept); - public delegate void DragStateCallback(IntPtr data, IntPtr obj); - public delegate bool DropCallback(IntPtr data, IntPtr obj, IntPtr selectionData); - - [DllImport(LibElementary)] - internal static extern void elm_drop_target_add(IntPtr obj, - DragDropContentType type, - DragStateCallback enterCallback, - IntPtr enterData, - DragStateCallback leaveCallback, - IntPtr leaveData, - DragPositionCallback positionCallback, - IntPtr positionData, - DropCallback dropcallback, - IntPtr dropData); - - [DllImport(LibElementary)] - internal static extern void elm_drag_start(IntPtr obj, - DragDropContentType contentType, - IntPtr data, - DragDropActionType actionType, - DragIconCreateCallback iconCreateCallback, - IntPtr iconCreateData, - DragPositionCallback dragPositionCallback, - IntPtr dragPositonData, - DragAcceptCallback dragAcceptCallback, - IntPtr dragAcceptData, - DragStateCallback dragStateCallback, - IntPtr dragStateData); - - [DllImport(LibElementary)] - internal static extern IntPtr elm_object_part_content_get(IntPtr obj, string part); - - [DllImport(LibEvas)] - internal static extern IntPtr evas_object_image_data_get(IntPtr obj, bool forWriting); - - [DllImport(LibEvas)] - internal static extern void evas_object_image_data_set(IntPtr obj, IntPtr data); - - [DllImport(LibEvas)] - internal static extern void evas_object_image_size_get(IntPtr obj, out int w, out int h); - - [DllImport(LibEvas)] - internal static extern void evas_object_image_size_set(IntPtr obj, int w, int h); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Extensions/EntryExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/EntryExtensions.cs deleted file mode 100644 index 49a2fcd8aa7a..000000000000 --- a/src/Compatibility/Core/src/Tizen/Extensions/EntryExtensions.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using ElmSharp; -using EEntry = ElmSharp.Entry; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - internal static class EntryExtensions - { - internal static InputPanelReturnKeyType ToInputPanelReturnKeyType(this ReturnType returnType) - { - switch (returnType) - { - case ReturnType.Go: - return InputPanelReturnKeyType.Go; - case ReturnType.Next: - return InputPanelReturnKeyType.Next; - case ReturnType.Send: - return InputPanelReturnKeyType.Send; - case ReturnType.Search: - return InputPanelReturnKeyType.Search; - case ReturnType.Done: - return InputPanelReturnKeyType.Done; - case ReturnType.Default: - return InputPanelReturnKeyType.Default; - default: - throw new System.NotImplementedException($"ReturnType {returnType} not supported"); - } - } - public static void GetSelectRegion(this EEntry entry, out int start, out int end) - { - elm_entry_select_region_get(entry.RealHandle, out start, out end); - } - - [DllImport("libelementary.so.1")] - static extern void elm_entry_select_region_get(IntPtr obj, out int start, out int end); - } -} diff --git a/src/Compatibility/Core/src/Tizen/Extensions/EvasMapExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/EvasMapExtensions.cs deleted file mode 100644 index b6bf133a42a3..000000000000 --- a/src/Compatibility/Core/src/Tizen/Extensions/EvasMapExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - public static class EvasMapExtensions - { - public static void Perspective3D(this EvasMap map, int px, int py, int z0, int foc) - { - var mapType = typeof(EvasMap); - var propInfo = mapType.GetProperty("Handle", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - var handle = (IntPtr)propInfo.GetValue(map); - evas_map_util_3d_perspective(handle, px, py, z0, foc); - } - - [DllImport("libevas.so.1")] - static extern void evas_map_util_3d_perspective(IntPtr map, int px, int py, int z0, int foc); - } -} diff --git a/src/Compatibility/Core/src/Tizen/Extensions/ImageExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/ImageExtensions.cs index 72602c3966d2..6d55fcb0285a 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/ImageExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/ImageExtensions.cs @@ -1,35 +1,11 @@ using System.Threading.Tasks; -using EImage = ElmSharp.Image; +using NImage = Tizen.NUI.BaseComponents.ImageView; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { public static class ImageExtensions { - public static void ApplyAspect(this EImage image, Aspect aspect) - { - Aspect _aspect = aspect; - - switch (_aspect) - { - case Aspect.AspectFit: - image.IsFixedAspect = true; - image.CanFillOutside = false; - break; - case Aspect.AspectFill: - image.IsFixedAspect = true; - image.CanFillOutside = true; - break; - case Aspect.Fill: - image.IsFixedAspect = false; - image.CanFillOutside = false; - break; - default: - Log.Warn("Invalid Aspect value: {0}", _aspect); - break; - } - } - - public static async Task LoadFromImageSourceAsync(this EImage image, ImageSource source) + public static async Task LoadFromImageSourceAsync(this NImage image, ImageSource source) { IImageSourceHandler handler; bool isLoadComplate = false; @@ -37,24 +13,9 @@ public static async Task LoadFromImageSourceAsync(this EImage image, Image { isLoadComplate = await handler.LoadImageAsync(image, source); } - if (!isLoadComplate) - { - //If it fails, call the Load function to remove the previous image. - image.Load(string.Empty); - } - return isLoadComplate; } - public static bool LoadFromFile(this EImage image, string file) - { - if (!string.IsNullOrEmpty(file)) - { - return image.Load(ResourcePath.GetPath(file)); - } - return false; - } - public static bool IsNullOrEmpty(this ImageSource imageSource) => imageSource == null || imageSource.IsEmpty; } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/KeyboardExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/KeyboardExtensions.cs deleted file mode 100644 index d07cbba0edba..000000000000 --- a/src/Compatibility/Core/src/Tizen/Extensions/KeyboardExtensions.cs +++ /dev/null @@ -1,80 +0,0 @@ -using ElmSharp; -using EEntry = ElmSharp.Entry; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - public static class KeyboardExtensions - { - /// - /// Creates an instance of ElmSharp.Keyboard reflecting the provided Microsoft.Maui.Controls.Compatibility.Keyboard instance - /// - /// Keyboard type corresponding to the provided Microsoft.Maui.Controls.Compatibility.Keyboard - /// The Microsoft.Maui.Controls.Compatibility.Keyboard class instance to be converted to ElmSharp.Keyboard. - public static Native.Keyboard ToNative(this Keyboard keyboard) - { - if (keyboard == Keyboard.Numeric) - { - return Native.Keyboard.Numeric; - } - else if (keyboard == Keyboard.Telephone) - { - return Native.Keyboard.PhoneNumber; - } - else if (keyboard == Keyboard.Email) - { - return Native.Keyboard.Email; - } - else if (keyboard == Keyboard.Url) - { - return Native.Keyboard.Url; - } - else - { - return Native.Keyboard.Normal; - } - } - - public static AutoCapital ToAutoCapital(this KeyboardFlags keyboardFlags) - { - if (keyboardFlags.HasFlag(KeyboardFlags.CapitalizeSentence)) - { - return AutoCapital.Sentence; - } - else if (keyboardFlags.HasFlag(KeyboardFlags.CapitalizeWord)) - { - return AutoCapital.Word; - } - else if (keyboardFlags.HasFlag(KeyboardFlags.CapitalizeCharacter)) - { - return AutoCapital.All; - } - else - { - return AutoCapital.None; - } - } - - public static InputHints ToInputHints(this Keyboard keyboard, bool isSpellCheckEnabled, bool isTextPredictionEnabled) - { - if (keyboard is CustomKeyboard customKeyboard) - { - return customKeyboard.Flags.HasFlag(KeyboardFlags.Suggestions) || customKeyboard.Flags.HasFlag(KeyboardFlags.Spellcheck) ? InputHints.AutoComplete : InputHints.None; - } - return isSpellCheckEnabled && isTextPredictionEnabled ? InputHints.AutoComplete : InputHints.None; - } - - public static void UpdateKeyboard(this Native.IEntry control, Keyboard keyboard, bool isSpellCheckEnabled, bool isTextPredictionEnabled) - { - control.Keyboard = keyboard.ToNative(); - if (keyboard is CustomKeyboard customKeyboard) - { - (control as EEntry).AutoCapital = customKeyboard.Flags.ToAutoCapital(); - } - else - { - (control as EEntry).AutoCapital = AutoCapital.None; - } - (control as EEntry).InputHint = keyboard.ToInputHints(isSpellCheckEnabled, isTextPredictionEnabled); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Extensions/LayoutExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/LayoutExtensions.cs index cf26d2f53f6e..ff745dccd056 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/LayoutExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/LayoutExtensions.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using ElmSharp; +using NView = Tizen.NUI.BaseComponents.View; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -19,7 +19,7 @@ public static class LayoutExtensions /// The extended class. /// Object to be added. /// Optional delegate which provides measurements for the added object. - public static void Add(this IList children, EvasObject obj, MeasureDelegate measureDelegate = null) + public static void Add(this IList children, NView obj, MeasureDelegate measureDelegate = null) { children.Add(obj.ToView(measureDelegate)); } @@ -30,7 +30,7 @@ public static void Add(this IList children, EvasObject obj, MeasureDelegat /// The Xamarin view which wraps the evas object. /// The extended class. /// Optional delegate which provides measurements for the evas object. - public static View ToView(this EvasObject obj, MeasureDelegate measureDelegate = null) + public static View ToView(this NView obj, MeasureDelegate measureDelegate = null) { return new NativeViewWrapper(obj, measureDelegate); } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/NativeBindingExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/NativeBindingExtensions.cs index a833dd5bf914..5cbb35f62b12 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/NativeBindingExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/NativeBindingExtensions.cs @@ -1,33 +1,33 @@ using System; using System.Collections.Generic; using Microsoft.Maui.Controls.Internals; -using EObject = ElmSharp.EvasObject; +using NView = Tizen.NUI.BaseComponents.View; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { public static class NativeBindingExtensions { - public static void SetBinding(this EObject view, string propertyName, BindingBase binding, string updateSourceEventName = null) + public static void SetBinding(this NView view, string propertyName, BindingBase binding, string updateSourceEventName = null) { PlatformBindingHelpers.SetBinding(view, propertyName, binding, updateSourceEventName); } - public static void SetBinding(this EObject view, BindableProperty targetProperty, BindingBase binding) + public static void SetBinding(this NView view, BindableProperty targetProperty, BindingBase binding) { PlatformBindingHelpers.SetBinding(view, targetProperty, binding); } - public static void SetValue(this EObject target, BindableProperty targetProperty, object value) + public static void SetValue(this NView target, BindableProperty targetProperty, object value) { PlatformBindingHelpers.SetValue(target, targetProperty, value); } - public static void SetBindingContext(this EObject target, object bindingContext, Func> getChildren = null) + public static void SetBindingContext(this NView target, object bindingContext, Func> getChildren = null) { PlatformBindingHelpers.SetBindingContext(target, bindingContext, getChildren); } - internal static void TransferBindablePropertiesToWrapper(this EObject target, View wrapper) + internal static void TransferBindablePropertiesToWrapper(this NView target, View wrapper) { PlatformBindingHelpers.TransferBindablePropertiesToWrapper(target, wrapper); } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/PageExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/PageExtensions.cs deleted file mode 100644 index 490ffb4b2c46..000000000000 --- a/src/Compatibility/Core/src/Tizen/Extensions/PageExtensions.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility -{ - [Obsolete] - public static class PageExtensions - { - public static EvasObject CreateEvasObject(this Page page, EvasObject parent, bool hasAlpha = false) - { - if (!Forms.IsInitialized) - throw new InvalidOperationException("call Forms.Init() before this"); - - if (parent == null) - throw new InvalidOperationException("Window could not be null"); - - if (!(page.RealParent is Application)) - { - Application app = new DefaultApplication(); - app.MainPage = page; - } - - var platform = Platform.Tizen.Platform.CreatePlatform(parent); - platform.HasAlpha = hasAlpha; - platform.SetPage(page); - return platform.GetRootNativeView(); - } - - class DefaultApplication : Application - { - } - } -} - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [Obsolete] - public static class PageExtensions - { - public static EvasObject CreateEvasObject(this ContentPage page, EvasObject parent, bool hasAlpha = false) - { - return Microsoft.Maui.Controls.Compatibility.PageExtensions.CreateEvasObject(page, parent, hasAlpha); - } - - public static void UpdateFocusTreePolicy<[DynamicallyAccessedMembers(BindableProperty.DeclaringTypeMembers)] T>(this MultiPage multiPage) where T : Page - { - foreach (var pageItem in multiPage.Children) - { - if (Platform.GetRenderer(pageItem)?.NativeView is ElmSharp.Widget nativeWidget) - { - if (pageItem == multiPage.CurrentPage) - { - nativeWidget.AllowTreeFocus = true; - continue; - } - nativeWidget.AllowTreeFocus = false; - } - } - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Extensions/ScrollToPositionExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/ScrollToPositionExtensions.cs deleted file mode 100644 index 31a1fde1a9af..000000000000 --- a/src/Compatibility/Core/src/Tizen/Extensions/ScrollToPositionExtensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using EScrollToPosition = ElmSharp.ScrollToPosition; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - public static class ScrollToPositionExtensions - { - public static EScrollToPosition ToNative(this ScrollToPosition position) - { - switch (position) - { - case ScrollToPosition.Center: - return EScrollToPosition.Middle; - - case ScrollToPosition.End: - return EScrollToPosition.Bottom; - - case ScrollToPosition.MakeVisible: - return EScrollToPosition.In; - - case ScrollToPosition.Start: - return EScrollToPosition.Top; - - default: - return EScrollToPosition.Top; - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Forms.cs b/src/Compatibility/Core/src/Tizen/Forms.cs index a1bde68e84e0..351ea57a9fb2 100644 --- a/src/Compatibility/Core/src/Tizen/Forms.cs +++ b/src/Compatibility/Core/src/Tizen/Forms.cs @@ -1,20 +1,16 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using ElmSharp; -using ElmSharp.Wearable; -using Tizen.Applications; -using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; -using Microsoft.Maui.Controls.Shapes; -using Microsoft.Maui.Devices; -using ELayout = ElmSharp.Layout; -using TSystemInfo = Tizen.System.Information; -using Size = Microsoft.Maui.Graphics.Size; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; +using Tizen.Applications; using Color = Microsoft.Maui.Graphics.Color; +using DeviceOrientation = Microsoft.Maui.Controls.Internals.DeviceOrientation; +using NView = Tizen.NUI.BaseComponents.View; +using TDeviceInfo = Tizen.UIExtensions.Common.DeviceInfo; namespace Microsoft.Maui.Controls.Compatibility { @@ -36,7 +32,6 @@ public class InitializationOptions { public CoreApplication Context { get; set; } public bool UseDeviceIndependentPixel { get; set; } - public bool UseSkiaSharp { get; set; } = true; public HandlerAttribute[] Handlers { get; set; } public Dictionary> CustomHandlers { get; set; } // for static registers public Assembly[] Assemblies { get; set; } @@ -45,7 +40,9 @@ public class InitializationOptions public StaticRegistrarStrategy StaticRegistarStrategy { get; set; } public PlatformType PlatformType { get; set; } public bool UseMessagingCenter { get; set; } = true; - public bool UseFastLayout { get; set; } = false; + + public bool UseSkiaSharp { get; set; } + public DisplayResolutionUnit DisplayResolutionUnit { get; set; } @@ -54,6 +51,7 @@ public struct EffectScope public string Name; public ExportEffectAttribute[] Effects; } + public InitializationOptions() { } @@ -92,164 +90,57 @@ public static class Forms #pragma warning disable CS0612 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete { - static Lazy s_profile = new Lazy(() => - { - //TODO : Fix me if elm_config_profile_get() unavailable - return Elementary.GetProfile(); - }); + static Lazy s_naturalOrientation = new Lazy(() => GetDeviceNaturalOrientation()); - static Lazy s_dpi = new Lazy(() => - { - int dpi = 0; - if (s_profile.Value == "tv") - { - // Use fixed DPI value (72) if TV profile - return 72; - } - TSystemInfo.TryGetValue("http://tizen.org/feature/screen.dpi", out dpi); - return dpi; - }); + static IReadOnlyList s_flags; - static Lazy s_elmScale = new Lazy(() => - { - return s_deviceScale.Value / Elementary.GetScale(); - }); + public static event EventHandler ViewInitialized; - static Lazy s_deviceType = new Lazy(() => - { - if (!TSystemInfo.TryGetValue("http://tizen.org/system/device_type", out string deviceType)) - { - // Since, above key("http://tizen.org/system/device_type") is not available on Tizen 4.0, we uses profile to decide the type of device on 4.0. - var profile = GetProfile(); - if (profile == "mobile") - { - deviceType = "Mobile"; - } - else if (profile == "tv") - { - deviceType = "TV"; - } - else if (profile == "wearable") - { - deviceType = "Wearable"; - } - else - { - deviceType = "Unknown"; - } - } - return deviceType; - }); + public static CoreApplication Context { get; internal set; } - static Lazy s_deviceScale = new Lazy(() => - { - // This is the base scale value and varies from profile - return ThemeManager.GetBaseScale(s_deviceType.Value); - }); + public static bool IsInitialized { get; private set; } - static Lazy s_scalingFactor = new Lazy(() => - { - int width = 0; - int height = 0; + public static DeviceOrientation NaturalOrientation => s_naturalOrientation.Value; - TSystemInfo.TryGetValue("http://tizen.org/feature/screen.width", out width); - TSystemInfo.TryGetValue("http://tizen.org/feature/screen.height", out height); + public static StaticRegistrarStrategy StaticRegistrarStrategy { get; private set; } - var scalingFactor = 1.0; // scaling is disabled, we're using pixels as Xamarin's geometry units - if (DisplayResolutionUnit.UseVP && DisplayResolutionUnit.ViewportWidth > 0) - { - scalingFactor = width / DisplayResolutionUnit.ViewportWidth; - } - else - { - if (DisplayResolutionUnit.UseDP) - { - scalingFactor = s_dpi.Value / 160.0; - } + public static PlatformType PlatformType { get; private set; } - if (DisplayResolutionUnit.UseDeviceScale) - { - var portraitSize = Math.Min(PhysicalScreenSize.Width, PhysicalScreenSize.Height); - if (portraitSize > 2000) - { - scalingFactor *= 4; - } - else if (portraitSize > 1000) - { - scalingFactor *= 2.5; - } - } - } - return scalingFactor; - }); + public static bool UseMessagingCenter { get; private set; } - static StaticRegistrarStrategy s_staticRegistrarStrategy = StaticRegistrarStrategy.None; + public static DisplayResolutionUnit DisplayResolutionUnit { get; private set; } - static PlatformType s_platformType = PlatformType.Defalut; + public static int ScreenDPI => TDeviceInfo.DPI; - static bool s_useMessagingCenter = true; + public static Size PhysicalScreenSize => (Device.info as TizenDeviceInfo).PhysicalScreenSize; - public static event EventHandler ViewInitialized; + public static IReadOnlyList Flags => s_flags ?? (s_flags = new string[0]); - public static IMauiContext MauiContext - { - get; - internal set; - } + public static IMauiContext MauiContext { get; internal set;} - public static CoreApplication Context + internal static TizenTitleBarVisibility TitleBarVisibility { get; - internal set; - } - - public static EvasObject NativeParent - { - get; internal set; - } - - public static ELayout BaseLayout => NativeParent as ELayout; - - public static CircleSurface CircleSurface - { - get; internal set; + private set; } - [EditorBrowsable(EditorBrowsableState.Never)] - public static Element RotaryFocusObject + static DeviceOrientation GetDeviceNaturalOrientation() { - get; internal set; - } + int width = TDeviceInfo.ScreenWidth; + int height = TDeviceInfo.ScreenHeight; - public static bool IsInitialized - { - get; - private set; + if (height >= width) + { + return DeviceOrientation.Portrait; + } + else + { + return DeviceOrientation.Landscape; + } } - public static StaticRegistrarStrategy StaticRegistrarStrategy => s_staticRegistrarStrategy; - - public static PlatformType PlatformType => s_platformType; - - public static bool UseMessagingCenter => s_useMessagingCenter; - - public static bool UseSkiaSharp { get; private set; } - public static bool UseFastLayout { get; private set; } - - public static DisplayResolutionUnit DisplayResolutionUnit { get; private set; } = DisplayResolutionUnit.Pixel(); - - public static int ScreenDPI => s_dpi.Value; - - public static Size PhysicalScreenSize => DeviceDisplay.MainDisplayInfo.GetScaledScreenSize(); - - internal static TizenTitleBarVisibility TitleBarVisibility - { - get; - private set; - } - - internal static void SendViewInitialized(this VisualElement self, EvasObject nativeView) + internal static void SendViewInitialized(this VisualElement self, NView nativeView) { EventHandler viewInitialized = Forms.ViewInitialized; if (viewInitialized != null) @@ -271,7 +162,7 @@ public static void SetTitleBarVisibility(TizenTitleBarVisibility visibility) public static TOut GetHandler(Type type, params object[] args) where TOut : class, IRegisterable { - if (s_staticRegistrarStrategy == StaticRegistrarStrategy.None) + if (StaticRegistrarStrategy == StaticRegistrarStrategy.None) { // Find hander in internal registrar, that is using reflection (default). return Registrar.Registered.GetHandler(type, args); @@ -282,7 +173,7 @@ public static TOut GetHandler(Type type, params object[] args) where TOut TOut ret = StaticRegistrar.Registered.GetHandler(type, args); // 2. If there is no handler, try to find hander in internal registrar, that is using reflection. - if (ret == null && s_staticRegistrarStrategy == StaticRegistrarStrategy.All) + if (ret == null && StaticRegistrarStrategy == StaticRegistrarStrategy.All) { ret = Registrar.Registered.GetHandler(type, args); } @@ -292,7 +183,7 @@ public static TOut GetHandler(Type type, params object[] args) where TOut public static TOut GetHandlerForObject(object obj) where TOut : class, IRegisterable { - if (s_staticRegistrarStrategy == StaticRegistrarStrategy.None) + if (StaticRegistrarStrategy == StaticRegistrarStrategy.None) { // Find hander in internal registrar, that is using reflection (default). return Registrar.Registered.GetHandlerForObject(obj); @@ -303,7 +194,7 @@ public static TOut GetHandlerForObject(object obj) where TOut : class, IRe TOut ret = StaticRegistrar.Registered.GetHandlerForObject(obj); // 2. If there is no handler, try to find hander in internal registrar, that is using reflection. - if (ret == null && s_staticRegistrarStrategy == StaticRegistrarStrategy.All) + if (ret == null && StaticRegistrarStrategy == StaticRegistrarStrategy.All) { ret = Registrar.Registered.GetHandlerForObject(obj); } @@ -313,7 +204,7 @@ public static TOut GetHandlerForObject(object obj) where TOut : class, IRe public static TOut GetHandlerForObject(object obj, params object[] args) where TOut : class, IRegisterable { - if (s_staticRegistrarStrategy == StaticRegistrarStrategy.None) + if (StaticRegistrarStrategy == StaticRegistrarStrategy.None) { // Find hander in internal registrar, that is using reflection (default). return Registrar.Registered.GetHandlerForObject(obj, args); @@ -324,7 +215,7 @@ public static TOut GetHandlerForObject(object obj, params object[] args) w TOut ret = StaticRegistrar.Registered.GetHandlerForObject(obj, args); // 2. If there is no handler, try to find hander in internal registrar, that is using reflection. - if (ret == null && s_staticRegistrarStrategy == StaticRegistrarStrategy.All) + if (ret == null && StaticRegistrarStrategy == StaticRegistrarStrategy.All) { ret = StaticRegistrar.Registered.GetHandlerForObject(obj, args); } @@ -363,30 +254,52 @@ static void SetupInit(IMauiContext context, InitializationOptions options = null TizenSynchronizationContext.Initialize(); } - Elementary.Initialize(); - Elementary.ThemeOverlay(); - Utility.AppendGlobalFontPath(@"/usr/share/fonts"); + Tizen.NUI.FontClient.Instance.AddCustomFontDirectory(@"/usr/share/fonts"); } Device.DefaultRendererAssembly = typeof(Forms).Assembly; + if (Device.info != null) + { + ((TizenDeviceInfo)Device.info).Dispose(); + Device.info = null; + } + Device.Info = new TizenDeviceInfo(); + if (options?.Flags.HasFlag(InitializationFlags.SkipRenderers) != true) RegisterCompatRenderers(options); + string profile = TDeviceInfo.Profile; + if (profile == "mobile") + { + Device.SetIdiom(TargetIdiom.Phone); + } + else if (profile == "tv") + { + Device.SetIdiom(TargetIdiom.TV); + } + else if (profile == "desktop") + { + Device.SetIdiom(TargetIdiom.Desktop); + } + else if (profile == "wearable") + { + Device.SetIdiom(TargetIdiom.Watch); + } + else + { + Device.SetIdiom(TargetIdiom.Unsupported); + } + if (options != null) { - s_platformType = options.PlatformType; - s_useMessagingCenter = options.UseMessagingCenter; - UseSkiaSharp = options.UseSkiaSharp; - UseFastLayout = options.UseFastLayout; + PlatformType = options.PlatformType; + UseMessagingCenter = options.UseMessagingCenter; } Application.AccentColor = GetAccentColor(); ExpressionSearch.Default = new TizenExpressionSearch(); - if (Context is WatchApplication) - s_platformType = PlatformType.Lightweight; - IsInitialized = true; } @@ -438,21 +351,6 @@ internal static void RegisterCompatRenderers(InitializationOptions maybeOptions } } - static void RegisterSkiaSharpRenderers() - { - // Register all skiasharp-based rednerers here. - Registrar.Registered.Register(typeof(Frame), typeof(Platform.Tizen.SkiaSharp.FrameRenderer)); - Registrar.Registered.Register(typeof(BoxView), typeof(Platform.Tizen.SkiaSharp.BoxViewRenderer)); - Registrar.Registered.Register(typeof(Image), typeof(Platform.Tizen.SkiaSharp.ImageRenderer)); - - Registrar.Registered.Register(typeof(Ellipse), typeof(Platform.Tizen.SkiaSharp.EllipseRenderer)); - Registrar.Registered.Register(typeof(Line), typeof(Platform.Tizen.SkiaSharp.LineRenderer)); - Registrar.Registered.Register(typeof(Path), typeof(Platform.Tizen.SkiaSharp.PathRenderer)); - Registrar.Registered.Register(typeof(Shapes.Polygon), typeof(Platform.Tizen.SkiaSharp.PolygonRenderer)); - Registrar.Registered.Register(typeof(Polyline), typeof(Platform.Tizen.SkiaSharp.PolylineRenderer)); - Registrar.Registered.Register(typeof(Shapes.Rectangle), typeof(Platform.Tizen.SkiaSharp.RectangleRenderer)); - } - static Color GetAccentColor() { // On Windows Phone, this is the complementary color chosen by the user. @@ -482,7 +380,7 @@ static Color GetAccentColor() /// public static int ConvertToPixel(double dp) { - return (int)Math.Round(dp * s_dpi.Value / 160.0); + return (int)Math.Round(dp * TDeviceInfo.DPI / 160.0); } /// @@ -496,7 +394,7 @@ public static int ConvertToPixel(double dp) /// public static int ConvertToScaledPixel(double dp) { - return (int)Math.Round(dp * s_scalingFactor.Value); + return (int)Math.Round(dp * TDeviceInfo.ScalingFactor); } /// @@ -511,7 +409,7 @@ public static double ConvertToScaledDP(int pixel) { if (pixel == int.MaxValue) return double.PositiveInfinity; - return pixel / s_scalingFactor.Value; + return pixel / TDeviceInfo.ScalingFactor; } /// @@ -526,7 +424,7 @@ public static double ConvertToScaledDP(double pixel) { if (pixel == double.PositiveInfinity) return double.PositiveInfinity; - return pixel / s_scalingFactor.Value; + return pixel / TDeviceInfo.ScalingFactor; } /// @@ -536,7 +434,9 @@ public static double ConvertToScaledDP(double pixel) /// public static int ConvertToEflFontPoint(double sp) { - return (int)Math.Round(ConvertToScaledPixel(sp) * s_elmScale.Value); + if (sp == -1) + return -1; + return (int)sp.ToScaledPoint(); } /// @@ -546,7 +446,7 @@ public static int ConvertToEflFontPoint(double sp) /// public static double ConvertToDPFont(int eflPt) { - return ConvertToScaledDP(eflPt / s_elmScale.Value); + return eflPt.ToScaledDP(); } /// @@ -555,23 +455,35 @@ public static double ConvertToDPFont(int eflPt) /// public static string GetProfile() { - return s_profile.Value; + return TDeviceInfo.Profile; } public static string GetDeviceType() { - return s_deviceType.Value; + return TDeviceInfo.DeviceType.ToString(); } - // for internal use only - [EditorBrowsable(EditorBrowsableState.Never)] - public static void Preload() + class TizenDeviceInfo : DeviceInfo { - Elementary.Initialize(); - Elementary.ThemeOverlay(); - var window = new Microsoft.Maui.Controls.Compatibility.Platform.Tizen.PreloadedWindow(); - TSystemInfo.TryGetValue("http://tizen.org/feature/screen.width", out int width); - TSystemInfo.TryGetValue("http://tizen.org/feature/screen.height", out int height); + public override Size PixelScreenSize => new Size(TDeviceInfo.PixelScreenSize.Width, TDeviceInfo.PixelScreenSize.Height); + + public override Size ScaledScreenSize => new Size(TDeviceInfo.ScaledDPScreenSize.Width, TDeviceInfo.ScaledDPScreenSize.Height); + + public Size PhysicalScreenSize + { + get + { + int width = TDeviceInfo.ScreenWidth; + int height = TDeviceInfo.ScreenHeight; + + var physicalScale = TDeviceInfo.DPI / 160.0; + return new Size(width / physicalScale, height / physicalScale); + } + } + + public override double ScalingFactor => TDeviceInfo.ScalingFactor; + + public string Profile => TDeviceInfo.Profile; } } diff --git a/src/Compatibility/Core/src/Tizen/FormsApplication.cs b/src/Compatibility/Core/src/Tizen/FormsApplication.cs index 330de47c62cb..8a3470d8ecaf 100644 --- a/src/Compatibility/Core/src/Tizen/FormsApplication.cs +++ b/src/Compatibility/Core/src/Tizen/FormsApplication.cs @@ -1,30 +1,20 @@ using System; using System.ComponentModel; -using System.Diagnostics; -using System.Reflection; using System.Threading.Tasks; -using ElmSharp; -using ElmSharp.Wearable; -using Tizen.Applications; using Tizen.Common; -using Microsoft.Maui.Controls.Internals; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; -using Microsoft.Maui.Devices; -using EWindow = ElmSharp.Window; -using ELayout = ElmSharp.Layout; -using EDisplayRotation = ElmSharp.DisplayRotation; -using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Application; +using Tizen.NUI; +using DeviceOrientation = Microsoft.Maui.Controls.Internals.DeviceOrientation; +using NWindow = Tizen.NUI.Window; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { [Obsolete] - public class FormsApplication : CoreUIApplication + public class FormsApplication : NUIApplication { ITizenPlatform _platform; Application _application; - EWindow _window; - bool _useBezelInteration; + NWindow _window; protected FormsApplication() { @@ -34,7 +24,7 @@ protected FormsApplication() /// Gets the main window or null if it's not set. /// /// The main window or null. - public EWindow MainWindow + public NWindow MainWindow { get { @@ -47,18 +37,6 @@ protected set } } - public ELayout BaseLayout - { - get; protected set; - } - - public CircleSurface BaseCircleSurface - { - get; protected set; - } - - public bool UseBezelInteration => _useBezelInteration; - protected override void OnPreCreate() { base.OnPreCreate(); @@ -70,26 +48,7 @@ protected override void OnPreCreate() Environment.SetEnvironmentVariable("XDG_DATA_HOME", Current.DirectoryInfo.Data); } - var type = typeof(EWindow); - // Use reflection to avoid breaking compatibility. ElmSharp.Window.CreateWindow() is has been added since API6. - var methodInfo = type.GetMethod("CreateWindow", BindingFlags.NonPublic | BindingFlags.Static); - EWindow window = null; - if (methodInfo != null) - { - window = (EWindow)methodInfo.Invoke(null, new object[] { "FormsWindow" }); - BaseLayout = (ELayout)window.GetType().GetProperty("BaseLayout")?.GetValue(window); - BaseCircleSurface = (CircleSurface)window.GetType().GetProperty("BaseCircleSurface")?.GetValue(window); - Forms.CircleSurface = BaseCircleSurface; - } - else // in case of Xamarin Preload - { - window = PreloadedWindow.GetInstance() ?? new EWindow("FormsWindow"); - if (window is PreloadedWindow precreated) - { - BaseLayout = precreated.BaseLayout; - } - } - MainWindow = window; + MainWindow = NWindow.Instance; } protected override void OnTerminate() @@ -143,11 +102,6 @@ public async void LoadApplication(Application application) application.SendStart(); application.PropertyChanged += new PropertyChangedEventHandler(this.AppOnPropertyChanged); SetPage(_application.MainPage); - if (DeviceInfo.Idiom == DeviceIdiom.Watch) - { - _useBezelInteration = Specific.GetUseBezelInteraction(_application); - UpdateOverlayContent(); - } } void AppOnPropertyChanged(object sender, PropertyChangedEventArgs args) @@ -156,30 +110,6 @@ void AppOnPropertyChanged(object sender, PropertyChangedEventArgs args) { SetPage(_application.MainPage); } - else if (DeviceInfo.Idiom == DeviceIdiom.Watch) - { - if (Specific.UseBezelInteractionProperty.PropertyName == args.PropertyName) - { - _useBezelInteration = Specific.GetUseBezelInteraction(_application); - } - else if (Specific.OverlayContentProperty.PropertyName == args.PropertyName) - { - UpdateOverlayContent(); - } - } - } - - void UpdateOverlayContent() - { - EvasObject nativeView = null; - var content = Specific.GetOverlayContent(_application); - if (content != null) - { - var renderer = Platform.GetOrCreateRenderer(content); - (renderer as ILayoutRenderer)?.RegisterOnLayoutUpdated(); - nativeView = renderer?.NativeView; - } - Forms.BaseLayout.SetOverlayPart(nativeView); } void SetPage(Page page) @@ -188,59 +118,44 @@ void SetPage(Page page) { throw new InvalidOperationException("Call Forms.Init (UIApplication) before this"); } - - _platform.HasAlpha = MainWindow.Alpha; _platform.SetPage(page); } void InitializeWindow() { - Debug.Assert(MainWindow != null, "EWindow cannot be null"); - - MainWindow.Active(); MainWindow.Show(); - // in case of no use of preloaded window - if (BaseLayout == null) + MainWindow.KeyEvent += (s, e) => { - var conformant = new Conformant(MainWindow); - conformant.Show(); - - var layout = new ApplicationLayout(conformant); - - layout.Show(); - - BaseLayout = layout; - - if (DeviceInfo.Idiom == DeviceIdiom.Watch) + if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape")) { - BaseCircleSurface = new CircleSurface(conformant); - Forms.CircleSurface = BaseCircleSurface; - } - conformant.SetContent(BaseLayout); - } - MainWindow.AvailableRotations = EDisplayRotation.Degree_0 | EDisplayRotation.Degree_90 | EDisplayRotation.Degree_180 | EDisplayRotation.Degree_270; - - MainWindow.Deleted += (s, e) => - { - Exit(); - }; + if (global::Tizen.UIExtensions.NUI.Popup.HasOpenedPopup) + { + global::Tizen.UIExtensions.NUI.Popup.CloseLast(); + return; + } - MainWindow.BackButtonPressed += (sender, e) => - { - if (_platform != null) - { - if (!_platform.SendBackButtonPressed()) + if (!(_platform?.SendBackButtonPressed() ?? false)) { Exit(); } } }; - _platform = Platform.CreatePlatform(BaseLayout); - BaseLayout.SetContent(_platform.GetRootNativeView()); - _platform.RootNativeViewChanged += (s, e) => BaseLayout.SetContent(e.RootNativeView); + MainWindow.AddAvailableOrientation(NWindow.WindowOrientation.Landscape); + MainWindow.AddAvailableOrientation(NWindow.WindowOrientation.LandscapeInverse); + MainWindow.AddAvailableOrientation(NWindow.WindowOrientation.Portrait); + MainWindow.AddAvailableOrientation(NWindow.WindowOrientation.PortraitInverse); + MainWindow.Resized += (s, e) => + { + Device.Info.CurrentOrientation = MainWindow.GetDeviceOrientation(); + }; + + Device.Info.CurrentOrientation = MainWindow.GetDeviceOrientation(); + + _platform = new DefaultPlatform(); + MainWindow.GetDefaultLayer().Add(_platform.GetRootNativeView()); } public void Run() @@ -271,4 +186,27 @@ public override void Exit() base.Exit(); } } + static class WindowExtension + { + public static DeviceOrientation GetDeviceOrientation(this NWindow window) + { + DeviceOrientation orientation = DeviceOrientation.Other; + switch (window.GetCurrentOrientation()) + { + case NWindow.WindowOrientation.Landscape: + orientation = DeviceOrientation.Landscape; + break; + case NWindow.WindowOrientation.LandscapeInverse: + orientation = DeviceOrientation.LandscapeLeft; + break; + case NWindow.WindowOrientation.Portrait: + orientation = DeviceOrientation.Portrait; + break; + case NWindow.WindowOrientation.PortraitInverse: + orientation = DeviceOrientation.PortraitDown; + break; + } + return orientation; + } + } } diff --git a/src/Compatibility/Core/src/Tizen/Gesture/GestureDetector.cs b/src/Compatibility/Core/src/Tizen/Gesture/GestureDetector.cs new file mode 100644 index 000000000000..cbfee6afff8f --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/Gesture/GestureDetector.cs @@ -0,0 +1,105 @@ +using System.Collections.Generic; + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + public class GestureDetector + { + Dictionary _handlers = new Dictionary(); + + IVisualElementRenderer _renderer; + + bool _isEnabled = true; + + public GestureDetector(IVisualElementRenderer renderer) + { + _renderer = renderer; + } + + public bool IsEnabled + { + get => _isEnabled; + set + { + if (_isEnabled != value) + { + _isEnabled = value; + UpdateIsEnabled(); + } + } + } + + public void AddGestures(IEnumerable gestures) + { + foreach (var gesture in gestures) + { + AddGesture(gesture); + } + } + + public void AddGesture(IGestureRecognizer gesture) + { + var handler = CreateHandler(gesture); + if (handler == null) + return; + + _handlers.Add(gesture, handler); + + if (IsEnabled) + handler.Attach(_renderer); + } + + public void RemoveGestures(IEnumerable gestures) + { + foreach (var gesture in gestures) + { + RemoveGesture(gesture); + } + } + + public void RemoveGesture(IGestureRecognizer gesture) + { + if (_handlers.TryGetValue(gesture, out GestureHandler handler)) + { + _handlers.Remove(gesture); + handler.Dispose(); + } + } + + public void Clear() + { + foreach (var handler in _handlers) + { + handler.Value.Dispose(); + } + _handlers.Clear(); + } + + void UpdateIsEnabled() + { + if (IsEnabled) + { + foreach (var handler in _handlers.Values) + { + handler.Attach(_renderer); + } + } + else + { + foreach (var handler in _handlers.Values) + { + handler.Detach(); + } + } + } + + GestureHandler CreateHandler(IGestureRecognizer recognizer) + { + if (recognizer is TapGestureRecognizer) + return new TapGestureHandler(recognizer); + if (recognizer is PanGestureRecognizer) + return new PanGestureHandler(recognizer); + return Forms.GetHandlerForObject(recognizer, recognizer); + } + + } +} diff --git a/src/Compatibility/Core/src/Tizen/Gesture/GestureHandler.cs b/src/Compatibility/Core/src/Tizen/Gesture/GestureHandler.cs new file mode 100644 index 000000000000..fab70c699269 --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/Gesture/GestureHandler.cs @@ -0,0 +1,54 @@ +using System; +using NGestureDetector = Tizen.NUI.GestureDetector; + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + public abstract class GestureHandler : IRegisterable, IDisposable + { + bool _disposedValue; + + public IGestureRecognizer Recognizer { get; private set; } + + public NGestureDetector NativeDetector { get; } + + protected IVisualElementRenderer Renderer { get; private set; } + protected View View => Renderer.Element as View; + + public void Attach(IVisualElementRenderer renderer) + { + Renderer = renderer; + NativeDetector.Attach(Renderer.NativeView); + } + + public void Detach() + { + NativeDetector.Detach(Renderer.NativeView); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected abstract NGestureDetector CreateNativeDetector(IGestureRecognizer recognizer); + + protected GestureHandler(IGestureRecognizer recognizer) + { + Recognizer = recognizer; + NativeDetector = CreateNativeDetector(recognizer); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + NativeDetector.Dispose(); + } + _disposedValue = true; + } + } + } +} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Gesture/PanGestureHandler.cs b/src/Compatibility/Core/src/Tizen/Gesture/PanGestureHandler.cs new file mode 100644 index 000000000000..ec2a1e435ce1 --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/Gesture/PanGestureHandler.cs @@ -0,0 +1,53 @@ +using NGestureDetector = Tizen.NUI.GestureDetector; +using PanGestureDetector = Tizen.NUI.PanGestureDetector; +using GestureStateType = Tizen.NUI.Gesture.StateType; + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + public class PanGestureHandler : GestureHandler + { + int _gestureId = 0; + + double _totalX; + double _totalY; + + public PanGestureHandler(IGestureRecognizer recognizer) : base(recognizer) + { + NativeDetector.Detected += OnDetected; + } + + new IPanGestureController Recognizer => base.Recognizer as IPanGestureController; + new PanGestureDetector NativeDetector => base.NativeDetector as PanGestureDetector; + + protected override NGestureDetector CreateNativeDetector(IGestureRecognizer recognizer) + { + return new PanGestureDetector(); + } + + void OnDetected(object source, PanGestureDetector.DetectedEventArgs e) + { + if (e.PanGesture.State == GestureStateType.Started) + { + _gestureId++; + _totalX = 0; + _totalY = 0; + Recognizer.SendPanStarted(View, _gestureId); + } + else if (e.PanGesture.State == GestureStateType.Continuing) + { + _totalX += e.PanGesture.Displacement.X; + _totalY += e.PanGesture.Displacement.Y; + Recognizer.SendPan(View, Forms.ConvertToScaledDP(_totalX), Forms.ConvertToScaledDP(_totalY), _gestureId); + } + else if (e.PanGesture.State == GestureStateType.Cancelled) + { + Recognizer.SendPanCanceled(View, _gestureId); + } + else if (e.PanGesture.State == GestureStateType.Finished) + { + Recognizer.SendPanCompleted(View, _gestureId); + } + } + + } +} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Gesture/TapGestureHandler.cs b/src/Compatibility/Core/src/Tizen/Gesture/TapGestureHandler.cs new file mode 100644 index 000000000000..c4da708f91a9 --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/Gesture/TapGestureHandler.cs @@ -0,0 +1,29 @@ +using System; +using NGestureDetector = Tizen.NUI.GestureDetector; +using TapGestureDetector = Tizen.NUI.TapGestureDetector; + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ + public class TapGestureHandler : GestureHandler + { + public TapGestureHandler(IGestureRecognizer recognizer) : base(recognizer) + { + NativeDetector.Detected += OnTapped; + } + + new TapGestureRecognizer Recognizer => base.Recognizer as TapGestureRecognizer; + new TapGestureDetector NativeDetector => base.NativeDetector as TapGestureDetector; + + protected override NGestureDetector CreateNativeDetector(IGestureRecognizer recognizer) + { + return new TapGestureDetector((uint)(recognizer as TapGestureRecognizer).NumberOfTapsRequired); + } + + void OnTapped(object source, TapGestureDetector.DetectedEventArgs e) + { + if (e.TapGesture.NumberOfTaps == Recognizer.NumberOfTapsRequired) + Recognizer.SendTapped(View); + } + + } +} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/GestureDetector.cs b/src/Compatibility/Core/src/Tizen/GestureDetector.cs deleted file mode 100644 index a5c7fca2630b..000000000000 --- a/src/Compatibility/Core/src/Tizen/GestureDetector.cs +++ /dev/null @@ -1,602 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Maui.Devices; -using ElmSharp; -using EGestureType = ElmSharp.GestureLayer.GestureType; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [Obsolete] - internal class GestureDetector - { - readonly IDictionary> _handlerCache; - - readonly IVisualElementRenderer _renderer; - GestureLayer _gestureLayer; - double _doubleTapTime = 0; - double _longTapTime = 0; - bool _inputTransparent = false; - bool _isEnabled; - - View View => _renderer.Element as View; - - public bool IsEnabled - { - get - { - return _isEnabled; - } - set - { - _isEnabled = value; - UpdateGestureLayerEnabled(); - } - } - - public bool InputTransparent - { - get - { - return _inputTransparent; - } - set - { - _inputTransparent = value; - UpdateGestureLayerEnabled(); - } - } - - public GestureDetector(IVisualElementRenderer renderer) - { - _handlerCache = new Dictionary>(); - _renderer = renderer; - _isEnabled = View.IsEnabled; - _inputTransparent = View.InputTransparent; - } - - public void Clear() - { - // this will clear all callbacks in ElmSharp GestureLayer - _gestureLayer?.Unrealize(); - _gestureLayer = null; - foreach (var handlers in _handlerCache.Values) - { - foreach (var handler in handlers) - { - handler.PropertyChanged -= OnGestureRecognizerPropertyChanged; - } - } - _handlerCache.Clear(); - - if (DeviceInfo.Idiom == DeviceIdiom.TV) - { - _renderer.NativeView.KeyDown -= OnKeyDown; - } - } - - public void AddGestures(IEnumerable recognizers) - { - if (_gestureLayer == null) - { - CreateGestureLayer(); - } - - foreach (var item in recognizers) - AddGesture(item); - } - - public void RemoveGestures(IEnumerable recognizers) - { - foreach (var item in recognizers) - RemoveGesture(item); - } - - void CreateGestureLayer() - { - _gestureLayer = new GestureLayer(_renderer.NativeView); - _gestureLayer.Attach(_renderer.NativeView); - _gestureLayer.Deleted += (s, e) => - { - _gestureLayer = null; - Clear(); - }; - UpdateGestureLayerEnabled(); - - if (DeviceInfo.Idiom == DeviceIdiom.TV) - { - _renderer.NativeView.KeyDown += OnKeyDown; - } - } - - void UpdateGestureLayerEnabled() - { - if (_gestureLayer != null) - { - _gestureLayer.IsEnabled = !_inputTransparent && _isEnabled; - } - } - - void AddGesture(IGestureRecognizer recognizer) - { - var handler = CreateHandler(recognizer); - if (handler == null) - return; - - var gestureType = handler.Type; - var timeout = handler.Timeout; - var cache = _handlerCache; - - if (!cache.ContainsKey(gestureType)) - { - cache[gestureType] = new List(); - } - - handler.PropertyChanged += OnGestureRecognizerPropertyChanged; - cache[gestureType].Add(handler); - - if (cache[gestureType].Count == 1) - { - switch (gestureType) - { - case EGestureType.Tap: - case EGestureType.TripleTap: - AddTapGesture(gestureType); - break; - - case EGestureType.DoubleTap: - AddDoubleTapGesture(gestureType, timeout); - break; - - case EGestureType.LongTap: - AddLongTapGesture(gestureType, timeout); - break; - - case EGestureType.Line: - AddLineGesture(gestureType); - break; - - case EGestureType.Flick: - AddFlickGesture(gestureType, timeout); - break; - - case EGestureType.Rotate: - AddRotateGesture(gestureType); - break; - - case EGestureType.Momentum: - AddMomentumGesture(gestureType); - break; - - case EGestureType.Zoom: - AddPinchGesture(gestureType); - break; - - default: - break; - } - } - - if (handler is DropGestureHandler dropGestureHandler) - { - dropGestureHandler.AddDropGesture(); - } - } - - void RemoveGesture(IGestureRecognizer recognizer) - { - var cache = _handlerCache; - var handler = LookupHandler(recognizer); - var gestureType = cache.FirstOrDefault(x => x.Value.Contains(handler)).Key; - - handler.PropertyChanged -= OnGestureRecognizerPropertyChanged; - cache[gestureType].Remove(handler); - - if (cache[gestureType].Count == 0) - { - switch (gestureType) - { - case EGestureType.Tap: - case EGestureType.DoubleTap: - case EGestureType.TripleTap: - case EGestureType.LongTap: - RemoveTapGesture(gestureType); - break; - - case EGestureType.Line: - RemoveLineGesture(); - break; - - case EGestureType.Flick: - RemoveFlickGesture(); - break; - - case EGestureType.Rotate: - RemoveRotateGesture(); - break; - - case EGestureType.Momentum: - RemoveMomentumGesture(); - break; - - case EGestureType.Zoom: - RemovePinchGesture(); - break; - - default: - break; - } - } - } - - void AddLineGesture(EGestureType type) - { - _gestureLayer.SetLineCallback(GestureLayer.GestureState.Start, (data) => { OnGestureStarted(type, data); }); - _gestureLayer.SetLineCallback(GestureLayer.GestureState.Move, (data) => { OnGestureMoved(type, data); }); - _gestureLayer.SetLineCallback(GestureLayer.GestureState.End, (data) => { OnGestureCompleted(type, data); }); - _gestureLayer.SetLineCallback(GestureLayer.GestureState.Abort, (data) => { OnGestureCanceled(type, data); }); - } - - void AddPinchGesture(EGestureType type) - { - _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Start, (data) => { OnGestureStarted(type, data); }); - _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Move, (data) => { OnGestureMoved(type, data); }); - _gestureLayer.SetZoomCallback(GestureLayer.GestureState.End, (data) => { OnGestureCompleted(type, data); }); - _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Abort, (data) => { OnGestureCanceled(type, data); }); - } - - void AddTapGesture(EGestureType type) - { - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.Start, (data) => { OnGestureStarted(type, data); }); - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.End, (data) => { OnGestureCompleted(type, data); }); - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.Abort, (data) => { OnGestureCanceled(type, data); }); - } - - void AddDoubleTapGesture(EGestureType type, double timeout) - { - if (timeout > 0) - _gestureLayer.DoubleTapTimeout = timeout; - - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.Start, (data) => { OnDoubleTapStarted(type, data); }); - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.End, (data) => { OnDoubleTapCompleted(type, data); }); - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.Abort, (data) => { OnGestureCanceled(type, data); }); - } - - void AddLongTapGesture(EGestureType type, double timeout) - { - if (timeout > 0) - _gestureLayer.LongTapTimeout = timeout; - - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.Start, (data) => { OnLongTapStarted(type, data); }); - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.Move, (data) => { OnLongTapMoved(type, data); }); - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.End, (data) => { OnLongTapCompleted(type, data); }); - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.Abort, (data) => { OnGestureCanceled(type, data); }); - } - - void AddFlickGesture(EGestureType type, double timeout) - { - if (timeout > 0) - _gestureLayer.FlickTimeLimit = (int)(timeout * 1000); - - // Task to correct wrong coordinates information when applying EvasMap(Xamarin ex: Translation, Scale, Rotate property) - // Always change to the absolute coordinates of the pointer. - int startX = 0; - int startY = 0; - _gestureLayer.SetFlickCallback(GestureLayer.GestureState.Start, (data) => - { - startX = _gestureLayer.EvasCanvas.Pointer.X; - startY = _gestureLayer.EvasCanvas.Pointer.Y; - data.X1 = startX; - data.Y1 = startY; - OnGestureStarted(type, data); - }); - _gestureLayer.SetFlickCallback(GestureLayer.GestureState.Move, (data) => - { - data.X1 = startX; - data.Y1 = startY; - data.X2 = _gestureLayer.EvasCanvas.Pointer.X; - data.Y2 = _gestureLayer.EvasCanvas.Pointer.Y; - OnGestureMoved(type, data); - }); - _gestureLayer.SetFlickCallback(GestureLayer.GestureState.End, (data) => - { - data.X1 = startX; - data.Y1 = startY; - data.X2 = _gestureLayer.EvasCanvas.Pointer.X; - data.Y2 = _gestureLayer.EvasCanvas.Pointer.Y; - OnGestureCompleted(type, data); - }); - _gestureLayer.SetFlickCallback(GestureLayer.GestureState.Abort, (data) => { OnGestureCanceled(type, data); }); - } - - void AddRotateGesture(EGestureType type) - { - _gestureLayer.SetRotateCallback(GestureLayer.GestureState.Start, (data) => { OnGestureStarted(type, data); }); - _gestureLayer.SetRotateCallback(GestureLayer.GestureState.Move, (data) => { OnGestureMoved(type, data); }); - _gestureLayer.SetRotateCallback(GestureLayer.GestureState.End, (data) => { OnGestureCompleted(type, data); }); - _gestureLayer.SetRotateCallback(GestureLayer.GestureState.Abort, (data) => { OnGestureCanceled(type, data); }); - } - - void AddMomentumGesture(EGestureType type) - { - // Task to correct wrong coordinates information when applying EvasMap(Xamarin ex: Translation, Scale, Rotate property) - // Always change to the absolute coordinates of the pointer. - int startX = 0; - int startY = 0; - _gestureLayer.SetMomentumCallback(GestureLayer.GestureState.Start, (data) => - { - startX = _gestureLayer.EvasCanvas.Pointer.X; - startY = _gestureLayer.EvasCanvas.Pointer.Y; - OnGestureStarted(type, data); - }); - _gestureLayer.SetMomentumCallback(GestureLayer.GestureState.Move, (data) => - { - data.X1 = startX; - data.Y1 = startY; - data.X2 = _gestureLayer.EvasCanvas.Pointer.X; - data.Y2 = _gestureLayer.EvasCanvas.Pointer.Y; - OnGestureMoved(type, data); - }); - _gestureLayer.SetMomentumCallback(GestureLayer.GestureState.End, (data) => { OnGestureCompleted(type, data); }); - _gestureLayer.SetMomentumCallback(GestureLayer.GestureState.Abort, (data) => { OnGestureCanceled(type, data); }); - } - - void RemoveLineGesture() - { - _gestureLayer.SetLineCallback(GestureLayer.GestureState.Start, null); - _gestureLayer.SetLineCallback(GestureLayer.GestureState.Move, null); - _gestureLayer.SetLineCallback(GestureLayer.GestureState.End, null); - _gestureLayer.SetLineCallback(GestureLayer.GestureState.Abort, null); - } - - void RemovePinchGesture() - { - _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Start, null); - _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Move, null); - _gestureLayer.SetZoomCallback(GestureLayer.GestureState.End, null); - _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Abort, null); - } - - void RemoveTapGesture(EGestureType type) - { - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.Start, null); - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.End, null); - _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.Abort, null); - } - - void RemoveFlickGesture() - { - _gestureLayer.SetFlickCallback(GestureLayer.GestureState.Start, null); - _gestureLayer.SetFlickCallback(GestureLayer.GestureState.Move, null); - _gestureLayer.SetFlickCallback(GestureLayer.GestureState.End, null); - _gestureLayer.SetFlickCallback(GestureLayer.GestureState.Abort, null); - } - - void RemoveRotateGesture() - { - _gestureLayer.SetRotateCallback(GestureLayer.GestureState.Start, null); - _gestureLayer.SetRotateCallback(GestureLayer.GestureState.Move, null); - _gestureLayer.SetRotateCallback(GestureLayer.GestureState.End, null); - _gestureLayer.SetRotateCallback(GestureLayer.GestureState.Abort, null); - } - - void RemoveMomentumGesture() - { - _gestureLayer.SetMomentumCallback(GestureLayer.GestureState.Start, null); - _gestureLayer.SetMomentumCallback(GestureLayer.GestureState.Move, null); - _gestureLayer.SetMomentumCallback(GestureLayer.GestureState.End, null); - _gestureLayer.SetMomentumCallback(GestureLayer.GestureState.Abort, null); - } - - #region GestureCallback - - void OnGestureStarted(EGestureType type, object data) - { - var cache = _handlerCache; - if (cache.ContainsKey(type)) - { - foreach (var handler in cache[type]) - { - (handler as IGestureController)?.SendStarted(View, data); - } - } - } - - void OnGestureMoved(EGestureType type, object data) - { - var cache = _handlerCache; - if (cache.ContainsKey(type)) - { - foreach (var handler in cache[type]) - { - (handler as IGestureController)?.SendMoved(View, data); - } - } - } - - void OnGestureCompleted(EGestureType type, object data) - { - var cache = _handlerCache; - if (cache.ContainsKey(type)) - { - foreach (var handler in cache[type]) - { - (handler as IGestureController)?.SendCompleted(View, data); - } - } - } - - void OnGestureCanceled(EGestureType type, object data) - { - var cache = _handlerCache; - if (cache.ContainsKey(type)) - { - foreach (var handler in cache[type]) - { - (handler as IGestureController)?.SendCanceled(View, data); - } - } - } - - void OnDoubleTapStarted(EGestureType type, object data) - { - _doubleTapTime = ((GestureLayer.TapData)data).Timestamp; - OnGestureStarted(type, data); - } - - void OnDoubleTapCompleted(EGestureType type, object data) - { - _doubleTapTime = ((GestureLayer.TapData)data).Timestamp - _doubleTapTime; - var cache = _handlerCache; - - if (cache.ContainsKey(type)) - { - foreach (var handler in cache[type]) - { - if ((handler.Timeout * 1000) >= _longTapTime) - (handler as IGestureController)?.SendCompleted(View, data); - else - (handler as IGestureController)?.SendCanceled(View, data); - } - } - } - - void OnLongTapStarted(EGestureType type, object data) - { - _longTapTime = ((GestureLayer.TapData)data).Timestamp; - OnGestureStarted(type, data); - } - - void OnLongTapMoved(EGestureType type, object data) - { - OnGestureMoved(type, data); - } - - void OnLongTapCompleted(EGestureType type, object data) - { - _longTapTime = ((GestureLayer.TapData)data).Timestamp - _longTapTime; - var cache = _handlerCache; - - if (cache.ContainsKey(type)) - { - foreach (var handler in cache[type]) - { - if ((handler.Timeout * 1000) <= _longTapTime) - (handler as IGestureController)?.SendCompleted(View, data); - else - (handler as IGestureController)?.SendCanceled(View, data); - } - } - } - - #endregion GestureCallback - - GestureHandler CreateHandler(IGestureRecognizer recognizer) - { - if (recognizer is TapGestureRecognizer) - { - return new TapGestureHandler(recognizer); - } - else if (recognizer is PinchGestureRecognizer) - { - return new PinchGestureHandler(recognizer); - } - else if (recognizer is PanGestureRecognizer) - { - return new PanGestureHandler(recognizer); - } - else if (recognizer is SwipeGestureRecognizer) - { - return new SwipeGestureHandler(recognizer); - } - else if (recognizer is DragGestureRecognizer) - { - return new DragGestureHandler(recognizer, _renderer); - } - else if (recognizer is DropGestureRecognizer) - { - return new DropGestureHandler(recognizer, _renderer); - } - return Forms.GetHandlerForObject(recognizer, recognizer); - } - - GestureHandler LookupHandler(IGestureRecognizer recognizer) - { - var cache = _handlerCache; - - foreach (var handlers in cache.Values) - { - foreach (var handler in handlers) - { - if (handler.Recognizer == recognizer) - return handler; - } - } - return null; - } - - void UpdateTapGesture(GestureHandler handler) - { - RemoveGesture(handler.Recognizer); - AddGesture(handler.Recognizer); - - if (handler.Timeout > _gestureLayer.DoubleTapTimeout) - _gestureLayer.DoubleTapTimeout = handler.Timeout; - } - - void UpdateLongTapGesture(GestureHandler handler) - { - if (handler.Timeout > 0 && handler.Timeout < _gestureLayer.LongTapTimeout) - _gestureLayer.LongTapTimeout = handler.Timeout; - } - - void UpdateFlickGesture(GestureHandler handler) - { - if (handler.Timeout > _gestureLayer.FlickTimeLimit) - _gestureLayer.FlickTimeLimit = (int)(handler.Timeout * 1000); - } - - void OnGestureRecognizerPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) - { - var handler = sender as GestureHandler; - if (handler != null) - { - switch (handler.Type) - { - case EGestureType.Tap: - case EGestureType.DoubleTap: - case EGestureType.TripleTap: - UpdateTapGesture(handler); - break; - - case EGestureType.LongTap: - UpdateLongTapGesture(handler); - break; - - case EGestureType.Flick: - UpdateFlickGesture(handler); - break; - - default: - break; - } - } - } - - void OnKeyDown(object sender, EvasKeyEventArgs e) - { - if (e.KeyName == "Return" && _gestureLayer.IsEnabled) - { - var cache = _handlerCache; - if (cache.ContainsKey(EGestureType.Tap)) - { - foreach (var handler in cache[EGestureType.Tap]) - { - (handler as IGestureController)?.SendStarted(View, null); - (handler as IGestureController)?.SendCompleted(View, null); - } - } - } - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/GestureHandler.cs b/src/Compatibility/Core/src/Tizen/GestureHandler.cs deleted file mode 100644 index 0df0a9928058..000000000000 --- a/src/Compatibility/Core/src/Tizen/GestureHandler.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.ComponentModel; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [Obsolete] - public abstract class GestureHandler : IGestureController, INotifyPropertyChanged, IRegisterable - { - public IGestureRecognizer Recognizer { get; private set; } - - public abstract GestureLayer.GestureType Type { get; } - - public virtual double Timeout { get; } - - protected GestureHandler(IGestureRecognizer recognizer) - { - Recognizer = recognizer; - Recognizer.PropertyChanged += OnRecognizerPropertyChanged; - } - - public event PropertyChangedEventHandler PropertyChanged; - - protected abstract void OnStarted(View sender, object data); - - protected abstract void OnMoved(View sender, object data); - - protected abstract void OnCompleted(View sender, object data); - - protected abstract void OnCanceled(View sender, object data); - - void IGestureController.SendStarted(View sender, object data) - { - OnStarted(sender, data); - } - - void IGestureController.SendCompleted(View sender, object data) - { - OnCompleted(sender, data); - } - - void IGestureController.SendMoved(View sender, object data) - { - OnMoved(sender, data); - } - - void IGestureController.SendCanceled(View sender, object data) - { - OnCanceled(sender, data); - } - - protected virtual void OnRecognizerPropertyChanged(object sender, PropertyChangedEventArgs e) - { - PropertyChanged?.Invoke(this, e); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs index 5cde81e81b25..8cb11efa8040 100644 --- a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs +++ b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs @@ -3,10 +3,7 @@ using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Graphics; -using Microsoft.Maui.Handlers; -using Rect = Microsoft.Maui.Graphics.Rect; -using ERect = ElmSharp.Rect; -using EvasObject = ElmSharp.EvasObject; +using NView = Tizen.NUI.BaseComponents.View; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -26,7 +23,7 @@ public HandlerToRendererShim(IPlatformViewHandler vh) public VisualElement Element { get; private set; } - public EvasObject NativeView => ViewHandler.ContainerView ?? ViewHandler.PlatformView; + public NView NativeView => ViewHandler.ContainerView ?? ViewHandler.PlatformView; public event EventHandler ElementChanged; public event EventHandler ElementPropertyChanged; @@ -64,16 +61,6 @@ public void SetElement(VisualElement element) if (ViewHandler.VirtualView != element) ViewHandler.SetVirtualView((IView)element); - if (element.RealParent is IView view && view.Handler is IPlatformViewHandler nvh) - { - ViewHandler.SetParent(nvh); - } - else - { - ViewHandler.SetParent(new MockParentHandler(element.RealParent as VisualElement)); - } - - NativeView.Deleted += OnNativeDeleted; ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(oldElement, Element)); } @@ -106,93 +93,5 @@ public void UpdateLayout() { ViewHandler.PlatformArrange(Element.Bounds); } - - public ERect GetNativeContentGeometry() - { - return NativeView.Geometry; - } - - class MockParentHandler : IPlatformViewHandler - { - - public MockParentHandler(VisualElement parent) - { - RealParent = parent; - } - - VisualElement RealParent { get; } - - public bool ForceContainer { get; set; } - - IVisualElementRenderer Renderer => RealParent != null ? Platform.GetRenderer(RealParent) : null; - public EvasObject PlatformView => Renderer.NativeView; - - public EvasObject ContainerView => PlatformView; - - public IPlatformViewHandler Parent => null; - - public IView VirtualView => Renderer.Element as IView; - - public IMauiContext MauiContext => null; - - object IElementHandler.PlatformView => PlatformView; - - object IViewHandler.ContainerView => PlatformView; - - bool IViewHandler.HasContainer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - - Maui.IElement IElementHandler.VirtualView => throw new NotImplementedException(); - - public void DisconnectHandler() { } - - public void Dispose() - { - } - - public Size GetDesiredSize(double widthConstraint, double heightConstraint) - { - throw new NotImplementedException(); - } - - public ERect GetPlatformContentGeometry() - { - return Renderer?.GetNativeContentGeometry() ?? new ERect(0, 0, 0, 0); - } - - public void PlatformArrange(Rect frame) - { - throw new NotImplementedException(); - } - - public void SetMauiContext(IMauiContext mauiContext) - { - throw new NotImplementedException(); - } - - public void SetParent(IPlatformViewHandler parent) - { - throw new NotImplementedException(); - } - - public void SetVirtualView(IView view) - { - throw new NotImplementedException(); - } - - public void UpdateValue(string property) - { - throw new NotImplementedException(); - } - - public void SetVirtualView(Maui.IElement view) - { - throw new NotImplementedException(); - } - - public void Invoke(string command, object args) - { - throw new NotImplementedException(); - } - } } } diff --git a/src/Compatibility/Core/src/Tizen/IGestureController.cs b/src/Compatibility/Core/src/Tizen/IGestureController.cs deleted file mode 100644 index 7882064e1bff..000000000000 --- a/src/Compatibility/Core/src/Tizen/IGestureController.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - public interface IGestureController - { - void SendStarted(View sender, object data); - - void SendMoved(View sender, object data); - - void SendCompleted(View sender, object data); - - void SendCanceled(View sender, object data); - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/IMEApplication.cs b/src/Compatibility/Core/src/Tizen/IMEApplication.cs deleted file mode 100644 index 96c07ef7802f..000000000000 --- a/src/Compatibility/Core/src/Tizen/IMEApplication.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using ElmSharp; -using Tizen.Uix.InputMethod; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [Obsolete] - public class IMEApplication : FormsApplication - { - public EditorWindow EditorWindow - { - get { return MainWindow as EditorWindow; } - } - - protected IMEApplication() - { - } - - protected override void OnPreCreate() - { - Application.ClearCurrent(); - - /* - * Since the IMEWindow class acquires window handle from InputMethod module and - * the handle is created internally when calling InputMethodEditor.Create() function, - * this needs to be called BEFORE creating new IMEWindow instance. - */ - InputMethodEditor.Create(); - MainWindow = InputMethodEditor.GetMainWindow(); - MainWindow.IndicatorMode = IndicatorMode.Hide; - } - - protected override void OnTerminate() - { - InputMethodEditor.Destroy(); - base.OnTerminate(); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/IRotaryInteraction.cs b/src/Compatibility/Core/src/Tizen/IRotaryInteraction.cs deleted file mode 100644 index 16e34cfbdd97..000000000000 --- a/src/Compatibility/Core/src/Tizen/IRotaryInteraction.cs +++ /dev/null @@ -1,9 +0,0 @@ -using ElmSharp.Wearable; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - public interface IRotaryInteraction - { - IRotaryActionWidget RotaryWidget { get; } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/LightweightPlatform.cs b/src/Compatibility/Core/src/Tizen/LightweightPlatform.cs deleted file mode 100644 index 71e404694419..000000000000 --- a/src/Compatibility/Core/src/Tizen/LightweightPlatform.cs +++ /dev/null @@ -1,216 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using ElmSharp; -using Microsoft.Maui.Controls.Internals; -using Microsoft.Maui.Devices; -using EColor = ElmSharp.Color; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [Obsolete] - public class LightweightPlatform : ITizenPlatform, INavigation, IDisposable - { - NavigationModel _navModel = new NavigationModel(); - Native.Canvas _viewStack; - readonly PopupManager _popupManager; - bool _hasAlpha; - readonly EColor _defaultPlatformColor; - - public LightweightPlatform(EvasObject parent) - { - Forms.NativeParent = parent; - _defaultPlatformColor = DeviceInfo.Idiom == DeviceIdiom.Phone ? EColor.White : EColor.Transparent; - _viewStack = new Native.Canvas(parent) - { - BackgroundColor = _defaultPlatformColor, - }; - _viewStack.SetAlignment(-1, -1); - _viewStack.SetWeight(1.0, 1.0); - _viewStack.LayoutUpdated += OnLayout; - _viewStack.Show(); - - if (Forms.UseMessagingCenter) - { - _popupManager = new PopupManager(this); - } - } - -#pragma warning disable 0067 - public event EventHandler RootNativeViewChanged; -#pragma warning restore 0067 - - public bool HasAlpha - { - get => _hasAlpha; - set - { - _hasAlpha = value; - _viewStack.BackgroundColor = _hasAlpha ? EColor.Transparent : _defaultPlatformColor; - } - } - - IPageController CurrentPageController => _navModel.CurrentPage as IPageController; - - IReadOnlyList INavigation.ModalStack => _navModel.Modals.ToList(); - - IReadOnlyList INavigation.NavigationStack => new List(); - - public void SetPage(Page page) - { - ResetChildren(); - _navModel = new NavigationModel(); - if (page == null) - return; - - _navModel.Push(page, null); - - ((Application)page.RealParent).NavigationProxy.Inner = this; - - var renderer = Platform.CreateRenderer(page); - renderer.NativeView.Geometry = _viewStack.Geometry; - _viewStack.Children.Add(renderer.NativeView); - - CurrentPageController?.SendAppearing(); - } - - public bool SendBackButtonPressed() - { - return _navModel?.CurrentPage?.SendBackButtonPressed() ?? false; - } - - public EvasObject GetRootNativeView() - { - return _viewStack; - } - - public bool PageIsChildOfPlatform(Page page) - { - var parent = page.AncestorToRoot(); - return _navModel.Modals.FirstOrDefault() == page || _navModel.Roots.Contains(parent); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _popupManager?.Dispose(); - _viewStack?.Unrealize(); - } - } - - Task INavigation.PopModalAsync() - { - return (this as INavigation).PopModalAsync(true); - } - - Task INavigation.PopModalAsync(bool animated) - { - Page page = _navModel.PopModal(); - (page as IPageController)?.SendDisappearing(); - - var renderer = Platform.GetRenderer(page); - _viewStack.Children.Remove(renderer.NativeView); - renderer.Dispose(); - - _viewStack.Children.LastOrDefault()?.Show(); - - CurrentPageController?.SendAppearing(); - return Task.FromResult(page); - } - - Task INavigation.PushModalAsync(Page modal) - { - return (this as INavigation).PushModalAsync(modal, true); - } - - Task INavigation.PushModalAsync(Page page, bool animated) - { - var previousPage = CurrentPageController; - previousPage?.SendDisappearing(); - - _navModel.PushModal(page); - - var lastTop = _viewStack.Children.LastOrDefault(); - - var renderer = Platform.GetOrCreateRenderer(page); - renderer.NativeView.Geometry = _viewStack.Geometry; - - _viewStack.Children.Add(renderer.NativeView); - if (lastTop != null) - { - lastTop.Hide(); - renderer.NativeView.StackAbove(lastTop); - } - - // Verify that the modal is still on the stack - if (_navModel.CurrentPage == page) - CurrentPageController.SendAppearing(); - return Task.CompletedTask; - } - - void INavigation.InsertPageBefore(Page page, Page before) - { - throw new InvalidOperationException("InsertPageBefore is not supported globally on Tizen, please use a NavigationPage."); - } - - Task INavigation.PopAsync() - { - return ((INavigation)this).PopAsync(true); - } - - Task INavigation.PopAsync(bool animated) - { - throw new InvalidOperationException("PopAsync is not supported globally on Tizen, please use a NavigationPage."); - } - - Task INavigation.PopToRootAsync() - { - return ((INavigation)this).PopToRootAsync(true); - } - - Task INavigation.PopToRootAsync(bool animated) - { - throw new InvalidOperationException("PopToRootAsync is not supported globally on Tizen, please use a NavigationPage."); - } - - Task INavigation.PushAsync(Page root) - { - return ((INavigation)this).PushAsync(root, true); - } - - Task INavigation.PushAsync(Page root, bool animated) - { - throw new InvalidOperationException("PushAsync is not supported globally on Tizen, please use a NavigationPage."); - } - - void INavigation.RemovePage(Page page) - { - throw new InvalidOperationException("RemovePage is not supported globally on Tizen, please use a NavigationPage."); - } - - void OnLayout(object sender, Native.LayoutEventArgs e) - { - foreach (var child in _viewStack.Children) - { - child.Geometry = _viewStack.Geometry; - } - } - - void ResetChildren() - { - var children = _viewStack.Children.ToList(); - _viewStack.Children.Clear(); - foreach (var child in children) - { - child.Unrealize(); - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/BatchableExtensions.cs b/src/Compatibility/Core/src/Tizen/Native/BatchableExtensions.cs deleted file mode 100644 index f931ddc1280c..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/BatchableExtensions.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - internal static class BatchableExtensions - { - static readonly ConditionalWeakTable s_counters = new ConditionalWeakTable(); - - public static void BatchBegin(this IBatchable target) - { - BatchCount value = null; - - if (s_counters.TryGetValue(target, out value)) - { - value.Count++; - } - else - { - s_counters.Add(target, new BatchCount()); - } - } - - public static void BatchCommit(this IBatchable target) - { - BatchCount value = null; - if (s_counters.TryGetValue(target, out value)) - { - value.Count--; - if (value.Count == 0) - { - target.OnBatchCommitted(); - } - else if (value.Count < 0) - { - Log.Error("Called BatchCommit() without BatchBegin()."); - value.Count = 0; - } - } - else - { - Log.Error("Called BatchCommit() without BatchBegin()."); - } - } - - public static bool IsBatched(this IBatchable target) - { - BatchCount value = null; - - if (s_counters.TryGetValue(target, out value)) - { - return value.Count != 0; - } - else - { - return false; - } - } - - class BatchCount - { - public int Count = 1; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/BorderRectangle.cs b/src/Compatibility/Core/src/Tizen/Native/BorderRectangle.cs deleted file mode 100644 index db0dcdb2c3bc..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/BorderRectangle.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class BorderRectangle : RoundRectangle - { - public BorderRectangle(EvasObject parent) : base(parent) { } - - public int BorderWidth { get; set; } - - protected override void DrawPoints() - { - ClearPoints(); - if (BorderWidth > 0) - { - IReadOnlyList radius = GetRadius(); - DrawRect(radius[0], radius[1], radius[2], radius[3], - 0, 0, Width, Height); - DrawRect(Math.Max(radius[0] - BorderWidth, 0), - Math.Max(radius[1] - BorderWidth, 0), - Math.Max(radius[2] - BorderWidth, 0), - Math.Max(radius[3] - BorderWidth, 0), - BorderWidth, BorderWidth, Width - BorderWidth * 2, Height - BorderWidth * 2); - } - } - - protected void DrawRect(int topLeft, int topRight, int bottomLeft, int bottomRight, int startX, int startY, int width, int height) - { - int[] radius = new int[4]; - int maxR = Math.Min(width / 2, height / 2); - radius[0] = Math.Min(topLeft, maxR); - radius[1] = Math.Min(topRight, maxR); - radius[2] = Math.Min(bottomLeft, maxR); - radius[3] = Math.Min(bottomRight, maxR); - - Graphics.Point first = new Graphics.Point(-1, -1); - for (int i = 0; i <= radius[0]; i++) - { - int x = i; - int dx = radius[0] - x; - int y = radius[0] - (int)Math.Sqrt((radius[0] * radius[0]) - (dx * dx)); - AddRelativePoint(startX + x, startY + y); - if (first.X < 0 && first.Y < 0) - { - first.X = startX + x; - first.Y = startY + y; - } - } - - AddRelativePoint(startX + width - radius[1], startY); - - for (int i = width - radius[1]; i <= width; i++) - { - int x = i; - int dx = radius[1] - (width - x); - int y = radius[1] - (int)Math.Sqrt((radius[1] * radius[1]) - (dx * dx)); - AddRelativePoint(startX + x, startY + y); - } - - AddRelativePoint(startX + width, startY + height - radius[3]); - - for (int i = width; i >= width - radius[3]; i--) - { - int x = i; - int dx = radius[3] - (width - x); - int y = height - radius[3] + (int)Math.Sqrt((radius[3] * radius[3]) - (dx * dx)); - AddRelativePoint(startX + x, startY + y); - } - - AddRelativePoint(startX + radius[2], startY + height); - - for (int i = radius[2]; i >= 0; i--) - { - int x = i; - int dx = radius[2] - x; - int y = height - radius[2] + (int)Math.Sqrt((radius[2] * radius[2]) - (dx * dx)); - AddRelativePoint(startX + x, startY + y); - } - AddRelativePoint((int)first.X, (int)first.Y); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Box.cs b/src/Compatibility/Core/src/Tizen/Native/Box.cs deleted file mode 100644 index 10e6d240f74e..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Box.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using ElmSharp; -using EBox = ElmSharp.Box; -using ERect = ElmSharp.Rect; - -#if __MATERIAL__ -using Tizen.NET.MaterialComponents; -#endif - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ -#if __MATERIAL__ - public class MaterialBox : MCard - { - public MaterialBox(EvasObject parent) : base(parent) - { - SetLayoutCallback(() => { NotifyOnLayout(); }); - } -#else - /// - /// Extends the ElmSharp.Box class with functionality useful to Microsoft.Maui.Controls.Compatibility renderer. - /// - /// - /// This class overrides the layout mechanism. Instead of using the native layout, - /// LayoutUpdated event is sent. - /// - public class Box : EBox - { - public Box(EvasObject parent) : base(parent) - { - SetLayoutCallback(() => { NotifyOnLayout(); }); - } -#endif - - /// - /// Notifies that the layout has been updated. - /// - public event EventHandler LayoutUpdated; - - /// - /// Triggers the LayoutUpdated event. - /// - /// - /// This method is called whenever there is a possibility that the size and/or position has been changed. - /// - void NotifyOnLayout() - { - if (null != LayoutUpdated) - { - LayoutUpdated(this, new LayoutEventArgs() { Geometry = Geometry }); - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Button.cs b/src/Compatibility/Core/src/Tizen/Native/Button.cs deleted file mode 100644 index f53ecefb664d..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Button.cs +++ /dev/null @@ -1,282 +0,0 @@ -using System; -using ElmSharp; -using EButton = ElmSharp.Button; -using EColor = ElmSharp.Color; -using ESize = ElmSharp.Size; -using TSButtonStyle = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.ButtonStyle; - -#if __MATERIAL__ -using Tizen.NET.MaterialComponents; -#endif - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ -#if __MATERIAL__ - public class MaterialButton : MButton, IMeasurable, IBatchable, IButton - { - public MaterialButton(EvasObject parent) : base(parent) - { - } -#else - /// - /// Extends the EButton control, providing basic formatting features, - /// i.e. font color, size, additional image. - /// - public class Button : EButton, IMeasurable, IBatchable, IButton - { - /// - /// Initializes a new instance of the class. - /// - /// Parent evas object. - public Button(EvasObject parent) : base(parent) - { - } -#endif - /// - /// Holds the formatted text of the button. - /// - readonly Span _span = new Span(); - - /// - /// Optional image, if set will be drawn on the button. - /// - Image _image; - - /// - /// Gets or sets the button's text. - /// - /// The text. - public override string Text - { - get - { - return _span.Text; - } - - set - { - if (value != _span.Text) - { - _span.Text = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the color of the text. - /// - /// The color of the text. - public EColor TextColor - { - get - { - return _span.ForegroundColor; - } - - set - { - if (!_span.ForegroundColor.Equals(value)) - { - _span.ForegroundColor = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the color of the text background. - /// - /// The color of the text background. - public EColor TextBackgroundColor - { - get - { - return _span.BackgroundColor; - } - - set - { - if (!_span.BackgroundColor.Equals(value)) - { - _span.BackgroundColor = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the font family. - /// - /// The font family. - public string FontFamily - { - get - { - return _span.FontFamily; - } - - set - { - if (value != _span.FontFamily) - { - _span.FontFamily = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the font attributes. - /// - /// The font attributes. - public FontAttributes FontAttributes - { - get - { - return _span.FontAttributes; - } - - set - { - if (value != _span.FontAttributes) - { - _span.FontAttributes = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the size of the font. - /// - /// The size of the font. - public double FontSize - { - get - { - return _span.FontSize; - } - - set - { - if (value != _span.FontSize) - { - _span.FontSize = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the image to be displayed next to the button's text. - /// - /// The image displayed on the button. - public Image Image - { - get - { - return _image; - } - - set - { - if (value != _image) - { - ApplyImage(value); - } - } - } - - /// - /// Implementation of the IMeasurable.Measure() method. - /// - public virtual ESize Measure(int availableWidth, int availableHeight) - { - if (Style == TSButtonStyle.Circle) - { - return new ESize(MinimumWidth, MinimumHeight); - } - else - { - if (Image != null) - MinimumWidth += Image.Geometry.Width; - - var rawSize = this.GetTextBlockNativeSize(); - return new ESize(rawSize.Width + MinimumWidth, Math.Max(MinimumHeight, rawSize.Height)); - } - } - - void IBatchable.OnBatchCommitted() - { - ApplyTextAndStyle(); - } - - /// - /// Applies the button's text and its style. - /// - void ApplyTextAndStyle() - { - if (!this.IsBatched()) - { - SetInternalTextAndStyle(_span.GetDecoratedText(), _span.GetStyle()); - } - } - - /// - /// Sets the button's internal text and its style. - /// - /// Formatted text, supports HTML tags. - /// Style applied to the formattedText. - void SetInternalTextAndStyle(string formattedText, string textStyle) - { - bool isVisible = true; - if (string.IsNullOrEmpty(formattedText)) - { - formattedText = null; - textStyle = null; - isVisible = false; - } - base.Text = formattedText; - this.SetTextBlockStyle(textStyle); - this.SendTextVisibleSignal(isVisible); - } - - /// - /// Applies the image to be displayed on the button. If value is null, - /// image will be removed. - /// - /// Image to be displayed or null. - void ApplyImage(Image image) - { - _image = image; - - SetInternalImage(); - } - - /// - /// Sets the internal image. If value is null, image will be removed. - /// - void SetInternalImage() - { - this.SetIconPart(_image); - } - - /// - /// Update the button's style - /// - /// The style of button - public void UpdateStyle(string style) - { - if (Style != style) - { - Style = style; - if (Style == TSButtonStyle.Default) - _span.HorizontalTextAlignment = TextAlignment.Auto; - else - _span.HorizontalTextAlignment = TextAlignment.Center; - ApplyTextAndStyle(); - } - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/Canvas.cs b/src/Compatibility/Core/src/Tizen/Native/Canvas.cs deleted file mode 100644 index c90634a29d2b..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Canvas.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Specialized; -using ElmSharp; - -#if __MATERIAL__ -using Tizen.NET.MaterialComponents; -#endif - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ -#if __MATERIAL__ - public class MaterialCanvas : MaterialBox, IContainable - { - public MaterialCanvas(EvasObject parent) : base(parent) - { - Initilize(); - } - -#else - /// - /// A Canvas provides a class which can be a container for other controls. - /// - /// - /// This class is used as a container view for Layouts from Microsoft.Maui.Controls.Compatibility.Platform.Tizen framework. - /// It is used for implementing xamarin pages and layouts. - /// - public class Canvas : Box, IContainable - { - /// - /// Initializes a new instance of the class. - /// - /// Canvas doesn't support replacing its children, this will be ignored. - /// Parent of this instance. - public Canvas(EvasObject parent) : base(parent) - { - Initilize(); - } -#endif - - /// - /// The list of Views. - /// - readonly ObservableCollection _children = new ObservableCollection(); - - /// - /// Gets list of native elements that are placed in the canvas. - /// - public new IList Children - { - get - { - return _children; - } - } - - /// - /// Provides destruction for native element and contained elements. - /// - protected override void OnUnrealize() - { - foreach (var child in _children) - { - child.Unrealize(); - } - - base.OnUnrealize(); - } - - /// - /// Initializes a new instance of the the class - /// - void Initilize() - { - _children.CollectionChanged += (o, e) => - { - if (e.Action == NotifyCollectionChangedAction.Add) - { - foreach (var v in e.NewItems) - { - var view = v as EvasObject; - if (null != view) - { - OnAdd(view); - } - } - } - else if (e.Action == NotifyCollectionChangedAction.Remove) - { - foreach (var v in e.OldItems) - { - var view = v as EvasObject; - if (null != view) - { - OnRemove(view); - } - } - } - else if (e.Action == NotifyCollectionChangedAction.Reset) - { - OnRemoveAll(); - } - }; - } - - /// - /// Adds a new child to a container. - /// - /// Native element which will be added - void OnAdd(EvasObject view) - { - PackEnd(view); - } - - /// - /// Removes a child from a container. - /// - /// Child element to be removed from canvas - void OnRemove(EvasObject view) - { - UnPack(view); - } - - /// - /// Removes all children from a canvas. - /// - void OnRemoveAll() - { - UnPackAll(); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/CarouselView.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/CarouselView.cs deleted file mode 100644 index a1207c500fad..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/CarouselView.cs +++ /dev/null @@ -1,23 +0,0 @@ -using ElmSharp; -using EScroller = ElmSharp.Scroller; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class CarouselView : CollectionView, ICollectionViewController - { - public CarouselView(EvasObject parent) : base(parent) - { - SelectionMode = CollectionViewSelectionMode.Single; - Scroll.ScrollBlock = ScrollBlock.None; - SnapPointsType = SnapPointsType.MandatorySingle; - } - - public EScroller Scroll => base.Scroller; - - ESize ICollectionViewController.GetItemSize(int widthConstraint, int heightConstraint) - { - return AllocatedSize; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/CollectionView.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/CollectionView.cs deleted file mode 100644 index 46dbbefb1d95..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/CollectionView.cs +++ /dev/null @@ -1,793 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using Microsoft.Maui.Devices; -using ElmSharp; -using ElmSharp.Wearable; -using EBox = ElmSharp.Box; -using EPoint = ElmSharp.Point; -using ERect = ElmSharp.Rect; -using EScroller = ElmSharp.Scroller; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class CollectionView : EBox, ICollectionViewController, IRotaryInteraction - { - RecyclerPool _pool = new RecyclerPool(); - ICollectionViewLayoutManager _layoutManager; - ItemAdaptor _adaptor; - EBox _innerLayout; - EvasObject _emptyView; - - Dictionary _viewHolderIndexTable = new Dictionary(); - ViewHolder _lastSelectedViewHolder; - int _selectedItemIndex = -1; - CollectionViewSelectionMode _selectionMode = CollectionViewSelectionMode.None; - - bool _requestLayoutItems = false; - SnapPointsType _snapPoints; - ESize _itemSize = new ESize(-1, -1); - - EvasObject _headerView; - EvasObject _footerView; - SmartEvent _scrollAnimationStop; - SmartEvent _scrollAnimationStart; - bool _isScrollAnimationStarted; - bool _allowFocusOnItem; - - public event EventHandler Scrolled; - - public CollectionView(EvasObject parent) : base(parent) - { - AllowFocus(true); - SetLayoutCallback(OnLayout); - Scroller = CreateScroller(parent); - Scroller.Show(); - PackEnd(Scroller); - Scroller.Scrolled += OnScrolled; - - _scrollAnimationStart = new SmartEvent(Scroller, ThemeConstants.Scroller.Signals.StartScrollAnimation); - _scrollAnimationStart.On += OnScrollStarted; - - _scrollAnimationStop = new SmartEvent(Scroller, ThemeConstants.Scroller.Signals.StopScrollAnimation); - _scrollAnimationStop.On += OnScrollStopped; - - Scroller.DragStart += OnDragStart; - Scroller.KeyDown += OnKeyDown; - - _innerLayout = new EBox(parent); - _innerLayout.SetLayoutCallback(OnInnerLayout); - _innerLayout.Show(); - Scroller.SetContent(_innerLayout); - } - - public IRotaryActionWidget RotaryWidget { get => Scroller as IRotaryActionWidget; } - - public CollectionViewSelectionMode SelectionMode - { - get => _selectionMode; - set - { - _selectionMode = value; - UpdateSelectionMode(); - } - } - - public int SelectedItemIndex - { - get => _selectedItemIndex; - set - { - if (_selectedItemIndex != value) - { - _selectedItemIndex = value; - UpdateSelectedItemIndex(); - } - } - } - - public SnapPointsType SnapPointsType - { - get => _snapPoints; - set - { - _snapPoints = value; - UpdateSnapPointsType(_snapPoints); - } - } - - protected EScroller Scroller { get; } - - public ICollectionViewLayoutManager LayoutManager - { - get => _layoutManager; - set - { - OnLayoutManagerChanging(); - _layoutManager = value; - OnLayoutManagerChanged(); - } - } - - public ItemAdaptor Adaptor - { - get => _adaptor; - set - { - OnAdaptorChanging(); - _adaptor = value; - OnAdaptorChanged(); - } - } - - public ScrollBarVisiblePolicy VerticalScrollBarVisiblePolicy - { - get => Scroller.VerticalScrollBarVisiblePolicy; - set => Scroller.VerticalScrollBarVisiblePolicy = value; - } - - public ScrollBarVisiblePolicy HorizontalScrollBarVisiblePolicy - { - get => Scroller.HorizontalScrollBarVisiblePolicy; - set => Scroller.HorizontalScrollBarVisiblePolicy = value; - } - - public ScrollToPosition FocusedItemScrollPosition { get; set; } - - int ICollectionViewController.Count - { - get - { - if (Adaptor == null || Adaptor is IEmptyAdaptor) - return 0; - return Adaptor.Count; - } - } - - EPoint ICollectionViewController.ParentPosition => new EPoint - { - X = Scroller.Geometry.X - Scroller.CurrentRegion.X, - Y = Scroller.Geometry.Y - Scroller.CurrentRegion.Y - }; - - protected ESize AllocatedSize { get; set; } - - ERect ViewPort => Scroller.CurrentRegion; - - public void ScrollTo(int index, ScrollToPosition position = ScrollToPosition.MakeVisible, bool animate = true) - { - var itemBound = LayoutManager.GetItemBound(index); - int itemStart; - int itemEnd; - int scrollStart; - int scrollEnd; - int itemPadding = 0; - int itemSize; - int viewportSize; - - if (LayoutManager.IsHorizontal) - { - itemStart = itemBound.Left; - itemEnd = itemBound.Right; - itemSize = itemBound.Width; - scrollStart = Scroller.CurrentRegion.Left; - scrollEnd = Scroller.CurrentRegion.Right; - viewportSize = AllocatedSize.Width; - } - else - { - itemStart = itemBound.Top; - itemEnd = itemBound.Bottom; - itemSize = itemBound.Height; - scrollStart = Scroller.CurrentRegion.Top; - scrollEnd = Scroller.CurrentRegion.Bottom; - viewportSize = AllocatedSize.Height; - } - - if (position == ScrollToPosition.MakeVisible) - { - if (itemStart < scrollStart) - { - position = ScrollToPosition.Start; - } - else if (itemEnd > scrollEnd) - { - position = ScrollToPosition.End; - } - else - { - // already visible - return; - } - } - - if (itemSize < viewportSize) - { - switch (position) - { - case ScrollToPosition.Center: - itemPadding = (viewportSize - itemSize) / 2; - break; - case ScrollToPosition.End: - itemPadding = (viewportSize - itemSize); - break; - } - itemSize = viewportSize; - } - - if (LayoutManager.IsHorizontal) - { - itemBound.X -= itemPadding; - itemBound.Width = itemSize; - } - else - { - itemBound.Y -= itemPadding; - itemBound.Height = itemSize; - } - - Scroller.ScrollTo(itemBound, animate); - } - - public void ScrollTo(object item, ScrollToPosition position = ScrollToPosition.MakeVisible, bool animate = true) - { - ScrollTo(Adaptor.GetItemIndex(item), position, animate); - } - - public void ItemMeasureInvalidated(int index) - { - // If a first item size was updated, need to reset _itemSize - if (index == 0) - { - _itemSize = new ESize(-1, -1); - } - LayoutManager?.ItemMeasureInvalidated(index); - } - - void ICollectionViewController.RequestLayoutItems() => RequestLayoutItems(); - - ESize ICollectionViewController.GetItemSize() - { - return (this as ICollectionViewController).GetItemSize(LayoutManager.IsHorizontal ? AllocatedSize.Width * 100 : AllocatedSize.Width, LayoutManager.IsHorizontal ? AllocatedSize.Height : AllocatedSize.Height * 100); - } - - ESize ICollectionViewController.GetItemSize(int widthConstraint, int heightConstraint) - { - if (Adaptor == null) - { - return new ESize(0, 0); - } - - if (_itemSize.Width > 0 && _itemSize.Height > 0) - { - return _itemSize; - } - - _itemSize = Adaptor.MeasureItem(widthConstraint, heightConstraint); - _itemSize.Width = Math.Max(_itemSize.Width, 10); - _itemSize.Height = Math.Max(_itemSize.Height, 10); - - if (_snapPoints != SnapPointsType.None) - { - Scroller.SetPageSize(_itemSize.Width, _itemSize.Height); - } - return _itemSize; - } - - ESize ICollectionViewController.GetItemSize(int index, int widthConstraint, int heightConstraint) - { - if (Adaptor == null) - { - return new ESize(0, 0); - } - return Adaptor.MeasureItem(index, widthConstraint, heightConstraint); - } - - protected virtual ViewHolder CreateViewHolder() - { - return new ViewHolder(this); - } - - ViewHolder ICollectionViewController.RealizeView(int index) - { - if (Adaptor == null) - return null; - - var holder = _pool.GetRecyclerView(Adaptor.GetViewCategory(index)); - if (holder != null) - { - holder.Show(); - } - else - { - var content = Adaptor.CreateNativeView(index, this); - holder = CreateViewHolder(); - holder.RequestSelected += OnRequestItemSelection; - holder.StateUpdated += OnItemStateChanged; - holder.Content = content; - holder.ViewCategory = Adaptor.GetViewCategory(index); - _innerLayout.PackEnd(holder); - } - - holder.AllowItemFocus = _allowFocusOnItem; - - Adaptor.SetBinding(holder.Content, index); - _viewHolderIndexTable[holder] = index; - if (index == SelectedItemIndex) - { - OnRequestItemSelection(holder, EventArgs.Empty); - } - return holder; - } - - void OnItemStateChanged(object sender, EventArgs e) - { - ViewHolder holder = (ViewHolder)sender; - if (holder.Content != null) - { - Adaptor?.UpdateViewState(holder.Content, holder.State); - } - - if (holder.State == ViewHolderState.Focused && FocusedItemScrollPosition != ScrollToPosition.MakeVisible) - { - - Application.Current.Dispatcher.Dispatch(() => - { - if (holder.State == ViewHolderState.Focused && _viewHolderIndexTable.TryGetValue(holder, out int itemIndex)) - { - ScrollTo(itemIndex, FocusedItemScrollPosition, true); - } - }); - } - } - - void OnRequestItemSelection(object sender, EventArgs e) - { - if (SelectionMode == CollectionViewSelectionMode.None) - return; - - if (_lastSelectedViewHolder != null) - { - _lastSelectedViewHolder.ResetState(); - } - - _lastSelectedViewHolder = sender as ViewHolder; - if (_lastSelectedViewHolder != null) - { - _lastSelectedViewHolder.State = ViewHolderState.Selected; - if (_viewHolderIndexTable.TryGetValue(_lastSelectedViewHolder, out int index)) - { - _selectedItemIndex = index; - Adaptor?.SendItemSelected(index); - } - } - } - - void ICollectionViewController.UnrealizeView(ViewHolder view) - { - _viewHolderIndexTable.Remove(view); - Adaptor.UnBinding(view.Content); - view.ResetState(); - view.Hide(); - - _pool.AddRecyclerView(view); - if (_lastSelectedViewHolder == view) - { - _lastSelectedViewHolder = null; - } - } - - void ICollectionViewController.ContentSizeUpdated() - { - OnInnerLayout(); - } - - protected virtual EScroller CreateScroller(EvasObject parent) - { - if (DeviceInfo.Idiom == DeviceIdiom.Watch) - { - return new CircleScroller(parent, Forms.CircleSurface); - } - else - { - return new EScroller(parent); - } - } - - void UpdateSelectedItemIndex() - { - if (SelectionMode == CollectionViewSelectionMode.None) - return; - - ViewHolder holder = null; - foreach (var item in _viewHolderIndexTable) - { - if (item.Value == SelectedItemIndex) - { - holder = item.Key; - break; - } - } - OnRequestItemSelection(holder, EventArgs.Empty); - } - - void UpdateSelectionMode() - { - if (SelectionMode == CollectionViewSelectionMode.None) - { - if (_lastSelectedViewHolder != null) - { - _lastSelectedViewHolder.ResetState(); - _lastSelectedViewHolder = null; - } - _selectedItemIndex = -1; - } - } - - void OnLayoutManagerChanging() - { - _layoutManager?.Reset(); - } - - void OnLayoutManagerChanged() - { - if (_layoutManager == null) - return; - - _itemSize = new ESize(-1, -1); - _layoutManager.CollectionView = this; - _layoutManager.SizeAllocated(AllocatedSize); - UpdateSnapPointsType(SnapPointsType); - if (Adaptor != null) - { - LayoutManager?.SetHeader(_headerView, Adaptor.MeasureHeader(AllocatedSize.Width, AllocatedSize.Height)); - LayoutManager?.SetFooter(_footerView, Adaptor.MeasureFooter(AllocatedSize.Width, AllocatedSize.Height)); - } - RequestLayoutItems(); - } - - void OnAdaptorChanging() - { - if (Adaptor is IEmptyAdaptor) - { - RemoveEmptyView(); - } - else - { - if (_headerView != null) - { - _innerLayout.UnPack(_headerView); - _headerView.Unrealize(); - } - if (_footerView != null) - { - _innerLayout.UnPack(_footerView); - _footerView.Unrealize(); - } - } - _headerView = null; - _footerView = null; - - _layoutManager?.Reset(); - if (Adaptor != null) - { - _pool.Clear(Adaptor); - (Adaptor as INotifyCollectionChanged).CollectionChanged -= OnCollectionChanged; - Adaptor.CollectionView = null; - } - } - - void OnAdaptorChanged() - { - if (_adaptor == null) - return; - - _itemSize = new ESize(-1, -1); - Adaptor.CollectionView = this; - (Adaptor as INotifyCollectionChanged).CollectionChanged += OnCollectionChanged; - - UpdateSnapPointsType(SnapPointsType); - LayoutManager?.ItemSourceUpdated(); - RequestLayoutItems(); - - if (Adaptor is IEmptyAdaptor) - { - CreateEmptyView(); - } - else - { - _headerView = Adaptor.GetHeaderView(this); - if (_headerView != null) - { - _innerLayout.PackEnd(_headerView); - } - _footerView = Adaptor.GetFooterView(this); - if (_footerView != null) - { - _innerLayout.PackEnd(_footerView); - } - LayoutManager?.SetHeader(_headerView, Adaptor.MeasureHeader(AllocatedSize.Width, AllocatedSize.Height)); - LayoutManager?.SetFooter(_footerView, Adaptor.MeasureFooter(AllocatedSize.Width, AllocatedSize.Height)); - } - } - - void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - // CollectionChanged could be called when Apaptor was changed on CollectionChanged event - if (Adaptor is IEmptyAdaptor) - { - return; - } - - if (e.Action == NotifyCollectionChangedAction.Add) - { - int idx = e.NewStartingIndex; - if (idx == -1) - { - idx = Adaptor.Count - e.NewItems.Count; - } - foreach (var item in e.NewItems) - { - foreach (var viewHolder in _viewHolderIndexTable.Keys.ToList()) - { - if (_viewHolderIndexTable[viewHolder] >= idx) - { - _viewHolderIndexTable[viewHolder]++; - } - } - LayoutManager.ItemInserted(idx++); - } - } - else if (e.Action == NotifyCollectionChangedAction.Remove) - { - int idx = e.OldStartingIndex; - - // Can't tracking remove if there is no data of old index - if (idx == -1) - { - LayoutManager.ItemSourceUpdated(); - } - else - { - foreach (var item in e.OldItems) - { - LayoutManager.ItemRemoved(idx); - foreach (var viewHolder in _viewHolderIndexTable.Keys.ToList()) - { - if (_viewHolderIndexTable[viewHolder] > idx) - { - _viewHolderIndexTable[viewHolder]--; - } - } - } - } - } - else if (e.Action == NotifyCollectionChangedAction.Move) - { - LayoutManager.ItemRemoved(e.OldStartingIndex); - LayoutManager.ItemInserted(e.NewStartingIndex); - } - else if (e.Action == NotifyCollectionChangedAction.Replace) - { - // Can't tracking if there is no information old data - if (e.OldItems.Count > 1 || e.NewStartingIndex == -1) - { - LayoutManager.ItemSourceUpdated(); - } - else - { - LayoutManager.ItemUpdated(e.NewStartingIndex); - } - } - else if (e.Action == NotifyCollectionChangedAction.Reset) - { - LayoutManager.Reset(); - LayoutManager.ItemSourceUpdated(); - } - RequestLayoutItems(); - } - - ERect _lastGeometry; - void OnLayout() - { - if (_lastGeometry == Geometry) - { - return; - } - - _lastGeometry = Geometry; - Scroller.Geometry = Geometry; - Scroller.ScrollBlock = ScrollBlock.None; - AllocatedSize = Geometry.Size; - _itemSize = new ESize(-1, -1); - - if (_adaptor != null && _layoutManager != null) - { - _layoutManager?.SizeAllocated(Geometry.Size); - - _layoutManager?.LayoutItems(ViewPort); - _layoutManager?.SetHeader(_headerView, Adaptor.MeasureHeader(AllocatedSize.Width, AllocatedSize.Height)); - _layoutManager?.SetFooter(_footerView, Adaptor.MeasureFooter(AllocatedSize.Width, AllocatedSize.Height)); - Scroller.ScrollBlock = LayoutManager.IsHorizontal ? ScrollBlock.Vertical : ScrollBlock.Horizontal; - Scroller.HorizontalStepSize = _layoutManager.GetScrollBlockSize(); - Scroller.VerticalStepSize = _layoutManager.GetScrollBlockSize(); - UpdateSnapPointsType(SnapPointsType); - Application.Current.Dispatcher.Dispatch(SendScrolledEvent); - } - } - - void RequestLayoutItems() - { - if (AllocatedSize.Width <= 0 || AllocatedSize.Height <= 0) - return; - - if (!_requestLayoutItems) - { - _requestLayoutItems = true; - Application.Current.Dispatcher.Dispatch(() => - { - _requestLayoutItems = false; - if (_adaptor != null && _layoutManager != null) - { - OnInnerLayout(); - _layoutManager?.LayoutItems(ViewPort, true); - } - }); - } - } - - void OnInnerLayout() - { - // OnInnerLayout was called when child item was added - // so, need to check scroll canvas size - var size = _layoutManager.GetScrollCanvasSize(); - _innerLayout.MinimumWidth = size.Width; - _innerLayout.MinimumHeight = size.Height; - } - - int _previousHorizontalOffset = 0; - int _previousVerticalOffset = 0; - - void OnScrollStarted(object sender, EventArgs e) - { - _isScrollAnimationStarted = true; - } - - void OnScrollStopped(object sender, EventArgs e) - { - SendScrolledEvent(); - _isScrollAnimationStarted = false; - } - - void OnScrolled(object sender, EventArgs e) - { - _layoutManager.LayoutItems(ViewPort); - if (!_isScrollAnimationStarted) - { - SendScrolledEvent(); - } - } - - void OnKeyDown(object sender, EvasKeyEventArgs e) - { - _allowFocusOnItem = true; - UpdateAllowFocusOnItem(_allowFocusOnItem); - } - - void OnDragStart(object sender, EventArgs e) - { - _allowFocusOnItem = false; - UpdateAllowFocusOnItem(_allowFocusOnItem); - } - - void SendScrolledEvent() - { - var args = new ItemsViewScrolledEventArgs(); - args.FirstVisibleItemIndex = _layoutManager.GetVisibleItemIndex(ViewPort.X, ViewPort.Y); - args.CenterItemIndex = _layoutManager.GetVisibleItemIndex(ViewPort.X + (ViewPort.Width / 2), ViewPort.Y + (ViewPort.Height / 2)); - args.LastVisibleItemIndex = _layoutManager.GetVisibleItemIndex(ViewPort.X + ViewPort.Width, ViewPort.Y + ViewPort.Height); - args.HorizontalOffset = ViewPort.X; - args.HorizontalDelta = ViewPort.X - _previousHorizontalOffset; - args.VerticalOffset = ViewPort.Y; - args.VerticalDelta = ViewPort.Y - _previousVerticalOffset; - - Scrolled?.Invoke(this, args); - - _previousHorizontalOffset = ViewPort.X; - _previousVerticalOffset = ViewPort.Y; - } - - void UpdateSnapPointsType(SnapPointsType snapPoints) - { - if (LayoutManager == null) - return; - - int itemSize = 0; - switch (snapPoints) - { - case SnapPointsType.None: - Scroller.HorizontalPageScrollLimit = 0; - Scroller.VerticalPageScrollLimit = 0; - itemSize = 0; - break; - case SnapPointsType.MandatorySingle: - Scroller.HorizontalPageScrollLimit = 1; - Scroller.VerticalPageScrollLimit = 1; - itemSize = LayoutManager.GetScrollBlockSize(); - break; - case SnapPointsType.Mandatory: - Scroller.HorizontalPageScrollLimit = 0; - Scroller.VerticalPageScrollLimit = 0; - itemSize = LayoutManager.GetScrollBlockSize(); - break; - } - - if (LayoutManager.IsHorizontal) - { - Scroller.SetPageSize(itemSize, 0); - } - else - { - Scroller.SetPageSize(0, itemSize); - } - } - - void CreateEmptyView() - { - _emptyView = Adaptor.CreateNativeView(this); - _emptyView.Show(); - Adaptor.SetBinding(_emptyView, 0); - _emptyView.Geometry = Geometry; - _emptyView.MinimumHeight = Geometry.Height; - _emptyView.MinimumWidth = Geometry.Width; - - Scroller.SetContent(_emptyView, true); - _innerLayout.Hide(); - } - - void RemoveEmptyView() - { - _innerLayout.Show(); - Scroller.SetContent(_innerLayout, true); - Adaptor.RemoveNativeView(_emptyView); - _emptyView = null; - } - - void UpdateAllowFocusOnItem(bool allowFocus) - { - foreach (var holer in _viewHolderIndexTable) - { - holer.Key.AllowItemFocus = allowFocus; - } - } - } - - public interface ICollectionViewController - { - EPoint ParentPosition { get; } - - ViewHolder RealizeView(int index); - - void UnrealizeView(ViewHolder view); - - void RequestLayoutItems(); - - int Count { get; } - - ESize GetItemSize(); - - ESize GetItemSize(int widthConstraint, int heightConstraint); - - ESize GetItemSize(int index, int widthConstraint, int heightConstraint); - - void ContentSizeUpdated(); - } - - public enum CollectionViewSelectionMode - { - None, - Single, - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/GridLayoutManager.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/GridLayoutManager.cs deleted file mode 100644 index 595b532a4585..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/GridLayoutManager.cs +++ /dev/null @@ -1,708 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElmSharp; -using ERect = ElmSharp.Rect; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class GridLayoutManager : ICollectionViewLayoutManager - { - ESize _allocatedSize; - ESize _scrollCanvasSize; - bool _isLayouting; - ERect _last; - Dictionary _realizedItem = new Dictionary(); - - List _itemSizes; - List _cached; - List _accumulatedItemSizes; - bool _hasUnevenRows; - int _baseItemSize; - - ESize _headerSize; - EvasObject _header; - ESize _footerSize; - EvasObject _footer; - - - public GridLayoutManager(bool isHorizontal, int span = 1) : this(isHorizontal, span, ItemSizingStrategy.MeasureFirstItem) { } - - public GridLayoutManager(bool isHorizontal, int span, ItemSizingStrategy sizingStrategy) : this(isHorizontal, span, sizingStrategy, 0, 0) { } - - public GridLayoutManager(bool isHorizontal, int span, ItemSizingStrategy sizingStrategy, int verticalSpacing, int horizontalSpacing) - { - IsHorizontal = isHorizontal; - Span = span; - _hasUnevenRows = sizingStrategy == ItemSizingStrategy.MeasureAllItems; - VerticalItemSpacing = verticalSpacing; - HorizontalItemSpacing = horizontalSpacing; - } - - public int Span { get; private set; } - - public bool IsHorizontal { get; } - - public int VerticalItemSpacing { get; } - - public int HorizontalItemSpacing { get; } - - public ICollectionViewController CollectionView { get; set; } - - public void SizeAllocated(ESize size) - { - Reset(); - _allocatedSize = size; - InitializeMeasureCache(); - } - - public ESize GetScrollCanvasSize() - { - if (CollectionView.Count == 0 || _allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) - return _allocatedSize; - - if (_scrollCanvasSize.Width > 0 && _scrollCanvasSize.Height > 0) - return _scrollCanvasSize; - - int totalItemSize = 0; - - if (_hasUnevenRows) - { - totalItemSize = _accumulatedItemSizes[_accumulatedItemSizes.Count - 1] + FooterSizeWithSpacing; - } - else - { - totalItemSize = (int)Math.Ceiling(CollectionView.Count / (double)Span) * (BaseItemSize + ItemSpacing) - ItemSpacing + ItemStartPoint + FooterSizeWithSpacing; - } - - if (IsHorizontal) - { - _scrollCanvasSize = new ESize(totalItemSize, _allocatedSize.Height); - } - else - { - _scrollCanvasSize = new ESize(_allocatedSize.Width, totalItemSize); - } - - return _scrollCanvasSize; - } - - public int GetScrollBlockSize() - { - return BaseItemSize + ItemSpacing; - } - - int BaseItemSize - { - get - { - if (_baseItemSize == 0) - { - if (_allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) - return 0; - - var itembound = CollectionView.GetItemSize(ItemWidthConstraint, ItemHeightConstraint); - _baseItemSize = IsHorizontal ? itembound.Width : itembound.Height; - } - return _baseItemSize; - } - } - - int ItemSpacing => IsHorizontal ? HorizontalItemSpacing : VerticalItemSpacing; - - // It is a rule, if you want to fit with a content natural size, constraint should be infinity - int ItemWidthConstraint => IsHorizontal ? int.MaxValue : ColumnSize; - int ItemHeightConstraint => IsHorizontal ? ColumnSize : int.MaxValue; - - int ColumnSize - { - get - { - return (IsHorizontal ? _allocatedSize.Height / Span : _allocatedSize.Width / Span) - ((Span - 1) * ColumnSpacing / Span); - } - } - - int ColumnSpacing => IsHorizontal ? VerticalItemSpacing : HorizontalItemSpacing; - - int FooterSize => IsHorizontal ? _footerSize.Width : _footerSize.Height; - - int HeaderSize => IsHorizontal ? _headerSize.Width : _headerSize.Height; - - int ItemStartPoint - { - get - { - var startPoint = HeaderSize; - if (startPoint > 0) - { - startPoint += ItemSpacing; - } - return startPoint; - } - } - - int FooterSizeWithSpacing - { - get - { - var size = FooterSize; - if (size > 0) - { - size += ItemSpacing; - } - return size; - } - } - - bool ShouldRearrange(ERect viewport) - { - if (_isLayouting) - return false; - if (_last.Size != viewport.Size) - return true; - - var diff = IsHorizontal ? Math.Abs(_last.X - viewport.X) : Math.Abs(_last.Y - viewport.Y); - if (diff > BaseItemSize) - return true; - - return false; - } - - public void LayoutItems(ERect bound, bool force) - { - if (_allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) - return; - - // TODO : need to optimization. it was frequently called with similar bound value. - if (!ShouldRearrange(bound) && !force) - { - return; - } - - _isLayouting = true; - _last = bound; - - int padding = Span; - int startIndex = Math.Max(GetStartIndex(bound) - padding, 0); - int endIndex = Math.Min(GetEndIndex(bound) + padding, CollectionView.Count - 1); - - foreach (var index in _realizedItem.Keys.ToList()) - { - if (index < startIndex || index > endIndex) - { - CollectionView.UnrealizeView(_realizedItem[index].View); - _realizedItem.Remove(index); - } - } - - var parent = CollectionView.ParentPosition; - for (int i = startIndex; i <= endIndex; i++) - { - EvasObject itemView = null; - if (!_realizedItem.ContainsKey(i)) - { - var view = CollectionView.RealizeView(i); - - _realizedItem[i] = new RealizedItem - { - View = view, - Index = i, - }; - itemView = view; - } - else - { - itemView = _realizedItem[i].View; - } - - var itemBound = GetItemBound(i); - itemBound.X += parent.X; - itemBound.Y += parent.Y; - itemView.Geometry = itemBound; - } - _isLayouting = false; - } - - public void UpdateSpan(int span) - { - Span = span; - InitializeMeasureCache(); - CollectionView.RequestLayoutItems(); - } - - public void ItemInserted(int inserted) - { - var items = _realizedItem.Keys.OrderByDescending(key => key); - foreach (var index in items) - { - if (index >= inserted) - { - _realizedItem[index + 1] = _realizedItem[index]; - } - } - if (_realizedItem.ContainsKey(inserted)) - { - _realizedItem.Remove(inserted); - } - else - { - var last = items.LastOrDefault(); - if (last >= inserted) - { - _realizedItem.Remove(last); - } - } - - UpdateInsertedSize(inserted); - - _scrollCanvasSize = new ESize(0, 0); - } - - public void ItemRemoved(int removed) - { - if (_realizedItem.ContainsKey(removed)) - { - CollectionView.UnrealizeView(_realizedItem[removed].View); - _realizedItem.Remove(removed); - } - - var items = _realizedItem.Keys.OrderBy(key => key); - foreach (var index in items) - { - if (index > removed) - { - _realizedItem[index - 1] = _realizedItem[index]; - } - } - - var last = items.LastOrDefault(); - if (last > removed) - { - _realizedItem.Remove(last); - } - - UpdateRemovedSize(removed); - _scrollCanvasSize = new ESize(0, 0); - } - - public void ItemUpdated(int index) - { - if (_realizedItem.ContainsKey(index)) - { - var bound = _realizedItem[index].View.Geometry; - CollectionView.UnrealizeView(_realizedItem[index].View); - var view = CollectionView.RealizeView(index); - _realizedItem[index].View = view; - view.Geometry = bound; - } - } - - public ERect GetItemBound(int index) - { - int rowIndex = index / Span; - int columnIndex = index % Span; - var columnSize = ColumnSize; - - int rowStartPoint = 0; - int columnStartPoint = 0; - int itemSize = 0; - - if (!_hasUnevenRows) - { - itemSize = BaseItemSize; - rowStartPoint = ItemStartPoint + rowIndex * (BaseItemSize + ItemSpacing); - columnStartPoint = columnIndex * (columnSize + ColumnSpacing); - } - else if (_cached[index]) - { - var updatedMaxItemSize = GetMaxItemSize(index); - itemSize = _itemSizes[index]; - rowStartPoint = _accumulatedItemSizes[rowIndex] - updatedMaxItemSize + (updatedMaxItemSize - itemSize) / 2; - columnStartPoint = columnIndex * (columnSize + ColumnSpacing); - } - else - { - var oldMaxItemSize = GetMaxItemSize(index); - - var measured = CollectionView.GetItemSize(index, ItemWidthConstraint, ItemHeightConstraint); - itemSize = IsHorizontal ? measured.Width : measured.Height; - - if (itemSize != _itemSizes[index]) - { - _itemSizes[index] = itemSize; - } - - var updatedMaxItemSize = GetMaxItemSize(index); - if (oldMaxItemSize != updatedMaxItemSize) - { - UpdateAccumulatedItemSize(rowIndex, updatedMaxItemSize - oldMaxItemSize); - int columnStart = (index / Span) * Span; - for (int toUpdate = columnStart; toUpdate < index; toUpdate++) - { - if (_realizedItem.ContainsKey(toUpdate)) - { - var updated = _realizedItem[toUpdate].View.Geometry; - if (IsHorizontal) - { - updated.X += (updatedMaxItemSize - oldMaxItemSize) / 2; - } - else - { - updated.Y += (updatedMaxItemSize - oldMaxItemSize) / 2; - } - _realizedItem[toUpdate].View.Geometry = updated; - } - } - CollectionView.ContentSizeUpdated(); - } - rowStartPoint = _accumulatedItemSizes[rowIndex] - updatedMaxItemSize + (updatedMaxItemSize - itemSize) / 2; - columnStartPoint = columnIndex * (columnSize + ColumnSpacing); - - _cached[index] = true; - } - - return IsHorizontal ? - new ERect(rowStartPoint, columnStartPoint, itemSize, columnSize) : - new ERect(columnStartPoint, rowStartPoint, columnSize, itemSize); - } - - public void Reset() - { - foreach (var realizedItem in _realizedItem.Values.ToList()) - { - CollectionView.UnrealizeView(realizedItem.View); - } - _realizedItem.Clear(); - _scrollCanvasSize = new ESize(0, 0); - } - - public void ItemSourceUpdated() - { - InitializeMeasureCache(); - } - - public void ItemMeasureInvalidated(int index) - { - if (_hasUnevenRows) - { - if (_cached.Count > index) - _cached[index] = false; - - if (_realizedItem.ContainsKey(index)) - { - CollectionView.RequestLayoutItems(); - } - } - else if (index == 0) // MeasureFirstItem - { - // Reset item size to measure updated size - InitializeMeasureCache(); - CollectionView.RequestLayoutItems(); - } - } - - public int GetVisibleItemIndex(int x, int y) - { - int index = 0; - if (x < 0 || y < 0 || _accumulatedItemSizes == null) - return index; - if (_scrollCanvasSize.Width < x || _scrollCanvasSize.Height < y) - return CollectionView.Count - 1; - - int first = 0; - if (!_hasUnevenRows) - { - first = Math.Min(Math.Max(0, ((IsHorizontal ? x : y) - ItemStartPoint) / (BaseItemSize + ItemSpacing)), ((CollectionView.Count - 1) / Span)); - } - else - { - first = _accumulatedItemSizes.FindIndex(current => (IsHorizontal ? x : y) <= current); - if (first == -1) - first = (CollectionView.Count - 1) / Span; - } - - int second = (IsHorizontal ? y : x) / (ColumnSize + ColumnSpacing); - if (second == Span) - second -= 1; - - index = (first * Span) + second; - - if (index < CollectionView.Count) - return index; - return CollectionView.Count - 1; - } - - public void SetHeader(EvasObject header, ESize size) - { - bool contentSizeChanged = false; - if (IsHorizontal) - { - if (_headerSize.Width != size.Width) - contentSizeChanged = true; - } - else - { - if (_headerSize.Height != size.Height) - contentSizeChanged = true; - } - - _header = header; - _headerSize = size; - - if (contentSizeChanged) - { - InitializeMeasureCache(); - CollectionView.ContentSizeUpdated(); - } - - var position = CollectionView.ParentPosition; - if (_header != null) - { - var bound = new ERect(position.X, position.Y, _headerSize.Width, _headerSize.Height); - if (IsHorizontal) - { - bound.Height = _allocatedSize.Height; - } - else - { - bound.Width = _allocatedSize.Width; - } - _header.Geometry = bound; - } - } - - public void SetFooter(EvasObject footer, ESize size) - { - bool contentSizeChanged = false; - if (IsHorizontal) - { - if (_footerSize.Width != size.Width) - contentSizeChanged = true; - } - else - { - if (_footerSize.Height != size.Height) - contentSizeChanged = true; - } - - _footer = footer; - _footerSize = size; - - if (contentSizeChanged) - { - InitializeMeasureCache(); - CollectionView.ContentSizeUpdated(); - } - - UpdateFooterPosition(); - } - - void UpdateFooterPosition() - { - if (_footer == null) - return; - - var position = CollectionView.ParentPosition; - if (IsHorizontal) - { - position.X += (GetScrollCanvasSize().Width - _footerSize.Width); - } - else - { - position.Y += (GetScrollCanvasSize().Height - _footerSize.Height); - } - - var bound = new ERect(position.X, position.Y, _footerSize.Width, _footerSize.Height); - if (IsHorizontal) - { - bound.Height = _allocatedSize.Height; - } - else - { - bound.Width = _allocatedSize.Width; - } - _footer.Geometry = bound; - } - - void InitializeMeasureCache() - { - _baseItemSize = 0; - _scrollCanvasSize = new ESize(0, 0); - _last = new ERect(0, 0, 0, 0); - - if (!_hasUnevenRows) - return; - - if (_allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) - return; - - int n = CollectionView.Count; - _itemSizes = new List(); - _cached = new List(); - _accumulatedItemSizes = new List(); - - for (int i = 0; i < n; i++) - { - _cached.Add(false); - _itemSizes.Add(BaseItemSize); - if (i % Span == 0) - { - int accIndex = i / Span; - _accumulatedItemSizes.Add((accIndex > 0 ? (_accumulatedItemSizes[accIndex - 1] + ItemSpacing) : ItemStartPoint) + _itemSizes[i]); - } - } - } - - void BuildAccumulatedSize() - { - _accumulatedItemSizes = new List(); - int n = _itemSizes.Count; - for (int i = 0; i < n; i++) - { - int accIndex = i / Span; - int prevSize = accIndex > 0 ? (_accumulatedItemSizes[accIndex - 1] + ItemSpacing) : 0; - if (i % Span == 0) - { - _accumulatedItemSizes.Add(prevSize); - } - int columnMax = _accumulatedItemSizes[accIndex] - prevSize; - if (columnMax < _itemSizes[i]) - { - _accumulatedItemSizes[accIndex] += (_itemSizes[i] - columnMax); - } - } - } - - void UpdateInsertedSize(int inserted) - { - if (!_hasUnevenRows) - return; - - _cached.Insert(inserted, false); - _itemSizes.Insert(inserted, BaseItemSize); - BuildAccumulatedSize(); - } - - void UpdateRemovedSize(int removed) - { - if (!_hasUnevenRows) - return; - - _itemSizes.RemoveAt(removed); - _cached.RemoveAt(removed); - BuildAccumulatedSize(); - } - - void UpdateAccumulatedItemSize(int index, int diff) - { - for (int i = index; i < _accumulatedItemSizes.Count; i++) - { - _accumulatedItemSizes[i] += diff; - } - - if (_scrollCanvasSize.Width > 0 && _scrollCanvasSize.Height > 0) - { - if (IsHorizontal) - { - _scrollCanvasSize.Width += diff; - } - else - { - _scrollCanvasSize.Height += diff; - } - } - UpdateFooterPosition(); - } - - int GetMaxItemSize(int index) - { - int columnStart = (index / Span) * Span; - int columnEnd = columnStart + Span - 1; - int max = 0; - for (int i = columnStart; i <= columnEnd && i < _itemSizes.Count; i++) - { - max = Math.Max(max, _itemSizes[i]); - } - return max; - } - - int GetStartIndex(ERect bound, int itemSize) - { - return (ViewPortStartPoint(bound) - ItemStartPoint) / itemSize * Span; - } - - int GetStartIndex(ERect bound) - { - if (!_hasUnevenRows) - { - return GetStartIndex(bound, BaseItemSize + ItemSpacing); - } - - return FindFirstGreaterOrEqualTo(_accumulatedItemSizes, ViewPortStartPoint(bound)) * Span; - } - - int GetEndIndex(ERect bound, int itemSize) - { - return (int)Math.Ceiling(ViewPortEndPoint(bound) / (double)itemSize) * Span - 1; - } - - int GetEndIndex(ERect bound) - { - if (!_hasUnevenRows) - { - return GetEndIndex(bound, BaseItemSize + ItemSpacing); - } - var tmp = FindFirstGreaterOrEqualTo(_accumulatedItemSizes, ViewPortEndPoint(bound)); - - return (FindFirstGreaterOrEqualTo(_accumulatedItemSizes, ViewPortEndPoint(bound)) + 1) * Span - 1; - } - - int ViewPortStartPoint(ERect viewPort) - { - return IsHorizontal ? viewPort.X : viewPort.Y; - } - - int ViewPortEndPoint(ERect viewPort) - { - return ViewPortStartPoint(viewPort) + ViewPortSize(viewPort); - } - - int ViewPortSize(ERect viewPort) - { - return IsHorizontal ? viewPort.Width : viewPort.Height; - } - - static int FindFirstGreaterOrEqualTo(IList data, int value) - { - if (data.Count == 0) - return 0; - - int start = 0; - int end = data.Count - 1; - while (start < end) - { - int mid = (start + end) / 2; - if (data[mid] < value) - { - start = mid + 1; - } - else - { - end = mid - 1; - } - } - if (data[start] < value) - { - start++; - } - return start; - } - - class RealizedItem - { - public ViewHolder View { get; set; } - public int Index { get; set; } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ICollectionViewLayoutManager.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/ICollectionViewLayoutManager.cs deleted file mode 100644 index 6a30aed26f38..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ICollectionViewLayoutManager.cs +++ /dev/null @@ -1,41 +0,0 @@ -using ElmSharp; -using ERect = ElmSharp.Rect; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public interface ICollectionViewLayoutManager - { - ICollectionViewController CollectionView { get; set; } - - bool IsHorizontal { get; } - - void SizeAllocated(ESize size); - - ESize GetScrollCanvasSize(); - - void LayoutItems(ERect bound, bool force = false); - - ERect GetItemBound(int index); - - void ItemInserted(int index); - - void ItemRemoved(int index); - - void ItemUpdated(int index); - - void ItemSourceUpdated(); - - void Reset(); - - void ItemMeasureInvalidated(int index); - - int GetVisibleItemIndex(int x, int y); - - int GetScrollBlockSize(); - - void SetHeader(EvasObject header, ESize size); - - void SetFooter(EvasObject footer, ESize size); - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/IndicatorView.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/IndicatorView.cs deleted file mode 100644 index 593c4a698454..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/IndicatorView.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Maui.Devices; -using ElmSharp; -using Index = ElmSharp.Index; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class IndicatorView : Index - { - const int OddMiddleItem = 10; - const int EvenMiddleItem = 11; - List _list = new List(); - - public IndicatorView(EvasObject parent) : base(parent) - { - AutoHide = false; - IsHorizontal = true; - this.SetStyledIndex(); - } - - public event EventHandler SelectedPosition; - - public void UpdateSelectedIndex(int index) - { - if (index > -1 && index < _list.Count) - { - _list[index].Select(true); - } - } - - public void AppendIndex(int count = 1) - { - for (int i = 0; i < count; i++) - { - var item = Append(null); - item.Selected += OnSelected; - _list.Add(item); - } - if (DeviceInfo.Idiom == DeviceIdiom.Watch) - ApplyStyle(); - } - - public void ClearIndex() - { - foreach (var item in _list) - { - item.Selected -= OnSelected; - } - _list.Clear(); - Clear(); - } - - void ApplyStyle() - { - foreach (var item in _list) - { - item.SetIndexItemStyle(_list.Count, _list.IndexOf(item), EvenMiddleItem, OddMiddleItem); - } - } - - void OnSelected(object sender, EventArgs e) - { - var index = _list.IndexOf((IndexItem)sender); - SelectedPosition?.Invoke(this, new SelectedPositionChangedEventArgs(index)); - UpdateSelectedIndex(index); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemAdaptor.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemAdaptor.cs deleted file mode 100644 index 2ced6753b575..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemAdaptor.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using ElmSharp; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public interface IEmptyAdaptor { } - - public abstract class ItemAdaptor : INotifyCollectionChanged - { - IList _itemsSource; - - public CollectionView CollectionView { get; set; } - - protected ItemAdaptor(IEnumerable items) - { - SetItemsSource(items); - } - - public event EventHandler ItemSelected; - - public virtual void SendItemSelected(int index) - { - ItemSelected?.Invoke(this, new SelectedItemChangedEventArgs(this[index], index)); - } - - public virtual void UpdateViewState(EvasObject view, ViewHolderState state) - { - } - - public void RequestItemSelected(object item) - { - if (CollectionView != null) - { - CollectionView.SelectedItemIndex = _itemsSource.IndexOf(item); - } - } - - protected void SetItemsSource(IEnumerable items) - { - switch (items) - { - case IList list: - _itemsSource = list; - _observableCollection = list as INotifyCollectionChanged; - break; - case IEnumerable generic: - _itemsSource = new List(generic); - break; - case IEnumerable _: - _itemsSource = new List(); - foreach (var item in items) - { - _itemsSource.Add(item); - } - break; - } - } - - public object this[int index] - { - get - { - return _itemsSource[index]; - } - } - - public int Count => _itemsSource.Count; - - INotifyCollectionChanged _observableCollection; - event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged - { - add - { - if (_observableCollection != null) - { - _observableCollection.CollectionChanged += value; - } - } - remove - { - if (_observableCollection != null) - { - _observableCollection.CollectionChanged -= value; - } - } - } - - public int GetItemIndex(object item) - { - return _itemsSource.IndexOf(item); - } - - public virtual object GetViewCategory(int index) - { - return this; - } - - public abstract EvasObject CreateNativeView(EvasObject parent); - - public abstract EvasObject CreateNativeView(int index, EvasObject parent); - - public abstract EvasObject GetHeaderView(EvasObject parent); - - public abstract EvasObject GetFooterView(EvasObject parent); - - public abstract void RemoveNativeView(EvasObject native); - - public abstract void SetBinding(EvasObject view, int index); - public abstract void UnBinding(EvasObject view); - - public abstract ESize MeasureItem(int widthConstraint, int heightConstraint); - - public abstract ESize MeasureItem(int index, int widthConstraint, int heightConstraint); - - public abstract ESize MeasureHeader(int widthConstraint, int heightConstraint); - - public abstract ESize MeasureFooter(int widthConstraint, int heightConstraint); - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/LinearLayoutManager.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/LinearLayoutManager.cs deleted file mode 100644 index d5e32d2b9bb4..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/LinearLayoutManager.cs +++ /dev/null @@ -1,610 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using ElmSharp; -using ERect = ElmSharp.Rect; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class LinearLayoutManager : ICollectionViewLayoutManager - { - ESize _allocatedSize; - bool _isLayouting; - ERect _last; - Dictionary _realizedItem = new Dictionary(); - List _itemSizes; - List _cached; - List _accumulatedItemSizes; - - bool _hasUnevenRows; - int _baseItemSize; - - ESize _headerSize; - EvasObject _header; - ESize _footerSize; - EvasObject _footer; - - public LinearLayoutManager(bool isHorizontal) : this(isHorizontal, ItemSizingStrategy.MeasureFirstItem) { } - - public LinearLayoutManager(bool isHorizontal, ItemSizingStrategy sizingStrategy) : this(isHorizontal, sizingStrategy, 0) { } - - public LinearLayoutManager(bool isHorizontal, ItemSizingStrategy sizingStrategy, int itemSpacing) - { - IsHorizontal = isHorizontal; - _hasUnevenRows = sizingStrategy == ItemSizingStrategy.MeasureAllItems; - ItemSpacing = itemSpacing; - } - - public bool IsHorizontal { get; } - - public int ItemSpacing { get; } - - public ICollectionViewController CollectionView { get; set; } - - public void SizeAllocated(ESize size) - { - _scrollCanvasSize = new ESize(0, 0); - _allocatedSize = size; - InitializeMeasureCache(); - } - - ESize _scrollCanvasSize; - - public ESize GetScrollCanvasSize() - { - if (CollectionView.Count == 0 || _allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) - { - return _allocatedSize; - } - - if (_scrollCanvasSize.Width > 0 && _scrollCanvasSize.Height > 0) - return _scrollCanvasSize; - - int totalItemSize = 0; - - if (_hasUnevenRows) - { - totalItemSize = _accumulatedItemSizes[_accumulatedItemSizes.Count - 1] + FooterSizeWithSpacing; - } - else - { - totalItemSize = (BaseItemSize + ItemSpacing) * CollectionView.Count - ItemSpacing + ItemStartPoint + FooterSizeWithSpacing; - } - - if (IsHorizontal) - { - _scrollCanvasSize = new ESize(totalItemSize, _allocatedSize.Height); - } - else - { - _scrollCanvasSize = new ESize(_allocatedSize.Width, totalItemSize); - } - - return _scrollCanvasSize; - } - - int BaseItemSize - { - get - { - if (_baseItemSize == 0) - { - if (_allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) - return 0; - - var itemBound = CollectionView.GetItemSize(ItemWidthConstraint, ItemHeightConstraint); - _baseItemSize = IsHorizontal ? itemBound.Width : itemBound.Height; - } - return _baseItemSize; - } - } - - // It is a rule, if you want to fit with a content natural size, constraint should be infinity - int ItemWidthConstraint => IsHorizontal ? int.MaxValue : _allocatedSize.Width; - int ItemHeightConstraint => IsHorizontal ? _allocatedSize.Height : int.MaxValue; - - int FooterSize => IsHorizontal ? _footerSize.Width : _footerSize.Height; - int HeaderSize => IsHorizontal ? _headerSize.Width : _headerSize.Height; - int ItemStartPoint - { - get - { - var startPoint = HeaderSize; - if (startPoint > 0) - { - startPoint += ItemSpacing; - } - return startPoint; - } - } - - int FooterSizeWithSpacing - { - get - { - var size = FooterSize; - if (size > 0) - { - size += ItemSpacing; - } - return size; - } - } - - bool ShouldRearrange(ERect viewport) - { - if (_isLayouting) - return false; - if (_last.Size != viewport.Size) - return true; - - var diff = IsHorizontal ? Math.Abs(_last.X - viewport.X) : Math.Abs(_last.Y - viewport.Y); - if (diff > BaseItemSize) - return true; - - return false; - } - - public void LayoutItems(ERect bound, bool force) - { - if (_allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) - return; - - // TODO : need to optimization. it was frequently called with similar bound value. - if (!ShouldRearrange(bound) && !force) - { - return; - } - - _isLayouting = true; - _last = bound; - - int startIndex = Math.Max(GetStartIndex(bound) - 1, 0); - int endIndex = Math.Min(GetEndIndex(bound) + 1, CollectionView.Count - 1); - - foreach (var index in _realizedItem.Keys.ToList()) - { - if (index < startIndex || index > endIndex) - { - CollectionView.UnrealizeView(_realizedItem[index].View); - _realizedItem.Remove(index); - } - } - - var parent = CollectionView.ParentPosition; - for (int i = startIndex; i <= endIndex; i++) - { - EvasObject itemView = null; - if (!_realizedItem.ContainsKey(i)) - { - var view = CollectionView.RealizeView(i); - _realizedItem[i] = new RealizedItem - { - View = view, - Index = i, - }; - itemView = view; - } - else - { - itemView = _realizedItem[i].View; - } - var itemBound = GetItemBound(i); - itemBound.X += parent.X; - itemBound.Y += parent.Y; - itemView.Geometry = itemBound; - } - _isLayouting = false; - } - - public void ItemInserted(int inserted) - { - var items = _realizedItem.Keys.OrderByDescending(key => key); - foreach (var index in items) - { - if (index >= inserted) - { - _realizedItem[index + 1] = _realizedItem[index]; - } - } - if (_realizedItem.ContainsKey(inserted)) - { - _realizedItem.Remove(inserted); - } - else - { - var last = items.LastOrDefault(); - if (last >= inserted) - { - _realizedItem.Remove(last); - } - } - - UpdateInsertedSize(inserted); - - _scrollCanvasSize = new ESize(0, 0); - } - - public void ItemRemoved(int removed) - { - if (_realizedItem.ContainsKey(removed)) - { - CollectionView.UnrealizeView(_realizedItem[removed].View); - _realizedItem.Remove(removed); - } - - var items = _realizedItem.Keys.OrderBy(key => key); - foreach (var index in items) - { - if (index > removed) - { - _realizedItem[index - 1] = _realizedItem[index]; - } - } - - var last = items.LastOrDefault(); - if (last > removed) - { - _realizedItem.Remove(last); - } - - UpdateRemovedSize(removed); - - _scrollCanvasSize = new ESize(0, 0); - } - - public void ItemUpdated(int index) - { - if (_realizedItem.ContainsKey(index)) - { - var bound = _realizedItem[index].View.Geometry; - CollectionView.UnrealizeView(_realizedItem[index].View); - var view = CollectionView.RealizeView(index); - _realizedItem[index].View = view; - view.Geometry = bound; - } - } - - public ERect GetItemBound(int index) - { - int itemSize = 0; - int startPoint = 0; - - if (!_hasUnevenRows) - { - itemSize = BaseItemSize; - startPoint = ItemStartPoint + (itemSize + ItemSpacing) * index; - } - else if (index >= _itemSizes.Count) - { - return new ERect(0, 0, 0, 0); - } - else if (_cached[index]) - { - itemSize = _itemSizes[index]; - startPoint = _accumulatedItemSizes[index] - itemSize; - } - else - { - var measured = CollectionView.GetItemSize(index, ItemWidthConstraint, ItemHeightConstraint); - itemSize = IsHorizontal ? measured.Width : measured.Height; - - if (itemSize != _itemSizes[index]) - { - UpdateAccumulatedItemSize(index, itemSize - _itemSizes[index]); - _itemSizes[index] = itemSize; - - CollectionView.ContentSizeUpdated(); - } - startPoint = _accumulatedItemSizes[index] - itemSize; - _cached[index] = true; - } - - return IsHorizontal ? - new ERect(startPoint, 0, itemSize, _allocatedSize.Height) : - new ERect(0, startPoint, _allocatedSize.Width, itemSize); - } - - public void Reset() - { - foreach (var realizedItem in _realizedItem.Values.ToList()) - { - CollectionView.UnrealizeView(realizedItem.View); - } - _realizedItem.Clear(); - _scrollCanvasSize = new ESize(0, 0); - } - - public void ItemSourceUpdated() - { - InitializeMeasureCache(); - } - - public void ItemMeasureInvalidated(int index) - { - if (_hasUnevenRows) - { - if (_cached.Count > index) - _cached[index] = false; - - if (_realizedItem.ContainsKey(index)) - { - CollectionView.RequestLayoutItems(); - } - } - else if (index == 0) - { - // Reset item size to measure updated size - InitializeMeasureCache(); - CollectionView.RequestLayoutItems(); - } - } - - public int GetVisibleItemIndex(int x, int y) - { - int coordinate = IsHorizontal ? x : y; - int canvasSize = IsHorizontal ? _scrollCanvasSize.Width : _scrollCanvasSize.Height; - - if (coordinate < 0) - return 0; - if (canvasSize < coordinate) - return CollectionView.Count - 1; - - if (!_hasUnevenRows) - { - return Math.Min(Math.Max(0, (coordinate - ItemStartPoint) / (BaseItemSize + ItemSpacing)), CollectionView.Count - 1); - } - else - { - var index = _accumulatedItemSizes.FindIndex(current => coordinate <= current); - if (index == -1) - index = CollectionView.Count - 1; - return index; - } - } - - public int GetScrollBlockSize() - { - return BaseItemSize + ItemSpacing; - } - - public void SetHeader(EvasObject header, ESize size) - { - bool contentSizeChanged = false; - if (IsHorizontal) - { - if (_headerSize.Width != size.Width) - contentSizeChanged = true; - } - else - { - if (_headerSize.Height != size.Height) - contentSizeChanged = true; - } - - _header = header; - _headerSize = size; - - if (contentSizeChanged) - { - InitializeMeasureCache(); - CollectionView.ContentSizeUpdated(); - } - - var position = CollectionView.ParentPosition; - if (_header != null) - { - var bound = new ERect(position.X, position.Y, _headerSize.Width, _headerSize.Height); - if (IsHorizontal) - { - bound.Height = _allocatedSize.Height; - } - else - { - bound.Width = _allocatedSize.Width; - } - _header.Geometry = bound; - } - } - - public void SetFooter(EvasObject footer, ESize size) - { - bool contentSizeChanged = false; - if (IsHorizontal) - { - if (_footerSize.Width != size.Width) - contentSizeChanged = true; - } - else - { - if (_footerSize.Height != size.Height) - contentSizeChanged = true; - } - - _footer = footer; - _footerSize = size; - - if (contentSizeChanged) - { - InitializeMeasureCache(); - CollectionView.ContentSizeUpdated(); - } - - UpdateFooterPosition(); - } - - void UpdateFooterPosition() - { - if (_footer == null) - return; - - var position = CollectionView.ParentPosition; - if (IsHorizontal) - { - position.X += (GetScrollCanvasSize().Width - _footerSize.Width); - } - else - { - position.Y += (GetScrollCanvasSize().Height - _footerSize.Height); - } - - var bound = new ERect(position.X, position.Y, _footerSize.Width, _footerSize.Height); - if (IsHorizontal) - { - bound.Height = _allocatedSize.Height; - } - else - { - bound.Width = _allocatedSize.Width; - } - _footer.Geometry = bound; - } - - void InitializeMeasureCache() - { - _baseItemSize = 0; - _scrollCanvasSize = new ESize(0, 0); - - if (!_hasUnevenRows) - return; - - if (_allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) - return; - - int n = CollectionView.Count; - _itemSizes = new List(); - _cached = new List(); - _accumulatedItemSizes = new List(); - - for (int i = 0; i < n; i++) - { - _cached.Add(false); - _itemSizes.Add(BaseItemSize); - _accumulatedItemSizes.Add((i > 0 ? (_accumulatedItemSizes[i - 1] + ItemSpacing) : ItemStartPoint) + _itemSizes[i]); - } - } - - int GetStartIndex(ERect bound, int itemSize) - { - return (ViewPortStartPoint(bound) - ItemStartPoint) / itemSize; - } - - int GetStartIndex(ERect bound) - { - if (!_hasUnevenRows) - { - return GetStartIndex(bound, BaseItemSize + ItemSpacing); - } - - return FindFirstGreaterOrEqualTo(_accumulatedItemSizes, ViewPortStartPoint(bound)); - } - - int GetEndIndex(ERect bound, int itemSize) - { - return (int)Math.Ceiling(ViewPortEndPoint(bound) / (double)itemSize) - 1; - } - - int GetEndIndex(ERect bound) - { - if (!_hasUnevenRows) - { - return GetEndIndex(bound, BaseItemSize + ItemSpacing); - } - - return FindFirstGreaterOrEqualTo(_accumulatedItemSizes, ViewPortEndPoint(bound)); - } - - int ViewPortStartPoint(ERect viewPort) - { - return IsHorizontal ? viewPort.X : viewPort.Y; - } - - int ViewPortEndPoint(ERect viewPort) - { - return ViewPortStartPoint(viewPort) + ViewPortSize(viewPort); - } - - int ViewPortSize(ERect viewPort) - { - return IsHorizontal ? viewPort.Width : viewPort.Height; - } - - void UpdateAccumulatedItemSize(int index, int diff) - { - for (int i = index; i < _accumulatedItemSizes.Count; i++) - { - _accumulatedItemSizes[i] += diff; - } - - if (_scrollCanvasSize.Width > 0 && _scrollCanvasSize.Height > 0) - { - - if (IsHorizontal) - { - _scrollCanvasSize.Width += diff; - } - else - { - _scrollCanvasSize.Height += diff; - } - } - UpdateFooterPosition(); - } - - void UpdateRemovedSize(int removed) - { - if (!_hasUnevenRows) - return; - var removedSize = _itemSizes[removed]; - _itemSizes.RemoveAt(removed); - UpdateAccumulatedItemSize(removed, -removedSize); - _accumulatedItemSizes.RemoveAt(removed); - _cached.RemoveAt(removed); - } - - void UpdateInsertedSize(int inserted) - { - if (!_hasUnevenRows) - return; - - _cached.Insert(inserted, false); - _itemSizes.Insert(inserted, BaseItemSize); - _accumulatedItemSizes.Insert(inserted, 0); - _accumulatedItemSizes[inserted] = inserted > 0 ? _accumulatedItemSizes[inserted - 1] : ItemStartPoint; - UpdateAccumulatedItemSize(inserted, BaseItemSize); - } - - static int FindFirstGreaterOrEqualTo(IList data, int value) - { - if (data.Count == 0) - return 0; - - int start = 0; - int end = data.Count - 1; - while (start < end) - { - int mid = (start + end) / 2; - if (data[mid] < value) - { - start = mid + 1; - } - else - { - end = mid - 1; - } - } - if (data[start] < value) - { - start++; - } - return start; - } - - class RealizedItem - { - public ViewHolder View { get; set; } - public int Index { get; set; } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/RecyclerPool.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/RecyclerPool.cs deleted file mode 100644 index 293170810e92..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/RecyclerPool.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - class RecyclerPool - { - LinkedList _pool = new LinkedList(); - - public void Clear(ItemAdaptor adaptor) - { - foreach (var item in _pool) - { - adaptor.RemoveNativeView(item); - } - _pool.Clear(); - } - - public void AddRecyclerView(ViewHolder view) - { - _pool.AddLast(view); - } - - public ViewHolder GetRecyclerView(object category) - { - var holder = _pool.Where(d => d.ViewCategory == category).FirstOrDefault(); - if (holder != null) - _pool.Remove(holder); - return holder; - } - - public ViewHolder GetRecyclerView() - { - if (_pool.First != null) - { - var fisrt = _pool.First; - _pool.RemoveFirst(); - return fisrt.Value; - } - return null; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ViewHolder.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/ViewHolder.cs deleted file mode 100644 index b921bcb258ee..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ViewHolder.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using ElmSharp; -using EColor = ElmSharp.Color; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - - public enum ViewHolderState - { - Normal, - Selected, - Focused, - } - - public class ViewHolder : Box - { - Button _focusArea; - EvasObject _content; - ViewHolderState _state; - bool _isSelected; - bool _isFocused; - bool _focusable; - - public ViewHolder(EvasObject parent) : base(parent) - { - Initialize(parent); - } - - public object ViewCategory { get; set; } - - [Obsolete("FocusedColor is obsolete. Use VisualStateManager")] - public EColor FocusedColor { get; set; } - - [Obsolete("SelectedColor is obsolete. Use VisualStateManager")] - public EColor SelectedColor { get; set; } - - public EvasObject Content - { - get - { - return _content; - } - set - { - if (_content != null) - { - UnPack(_content); - } - _content = value; - if (_content != null) - { - PackEnd(_content); - _content.StackBelow(_focusArea); - } - } - } - - public bool AllowItemFocus - { - get => _focusable; - set - { - _focusable = value; - if (!value && _focusArea.IsFocused) - { - _focusArea.SetFocus(false); - } - _focusArea.AllowFocus(_focusable); - } - } - - public ViewHolderState State - { - get { return _state; } - set - { - if (value == ViewHolderState.Normal) - _isSelected = false; - else if (value == ViewHolderState.Selected) - _isSelected = true; - - _state = _isFocused ? ViewHolderState.Focused : (_isSelected ? ViewHolderState.Selected : ViewHolderState.Normal); - - UpdateState(); - } - } - - public event EventHandler RequestSelected; - - public event EventHandler StateUpdated; - - public void ResetState() - { - State = ViewHolderState.Normal; - } - - protected void Initialize(EvasObject parent) - { - SetLayoutCallback(OnLayout); - - _focusArea = new Button(parent); - _focusArea.Color = EColor.Transparent; - _focusArea.BackgroundColor = EColor.Transparent; - _focusArea.SetEffectColor(EColor.Transparent); - _focusArea.Clicked += OnClicked; - _focusArea.Focused += OnFocused; - _focusArea.Unfocused += OnUnfocused; - _focusArea.KeyUp += OnKeyUp; - _focusArea.RepeatEvents = true; - _focusArea.Show(); - _focusArea.AllowFocus(_focusable); - - PackEnd(_focusArea); - Show(); - } - - protected virtual void OnFocused(object sender, EventArgs e) - { - UpdateFocusState(); - } - - protected virtual void OnUnfocused(object sender, EventArgs e) - { - UpdateFocusState(); - } - - protected virtual void OnClicked(object sender, EventArgs e) - { - RequestSelected?.Invoke(this, EventArgs.Empty); - } - - protected virtual void OnLayout() - { - _focusArea.Geometry = Geometry; - if (_content != null) - { - _content.Geometry = Geometry; - } - } - - protected virtual void UpdateState() - { - if (State == ViewHolderState.Selected) - _isSelected = true; - else if (State == ViewHolderState.Normal) - _isSelected = false; - else if (State == ViewHolderState.Focused) - RaiseTop(); - - StateUpdated?.Invoke(this, EventArgs.Empty); - } - - void UpdateFocusState() - { - if (_focusArea.IsFocused) - { - _isFocused = true; - State = ViewHolderState.Focused; - } - else - { - _isFocused = false; - State = _isSelected ? ViewHolderState.Selected : ViewHolderState.Normal; - } - } - - void OnKeyUp(object sender, EvasKeyEventArgs e) - { - if (e.KeyName == "Enter" && _focusArea.IsFocused) - { - RequestSelected?.Invoke(this, EventArgs.Empty); - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/DateChangedEventArgs.cs b/src/Compatibility/Core/src/Tizen/Native/DateChangedEventArgs.cs deleted file mode 100644 index 104a7fc16efa..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/DateChangedEventArgs.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Event arguments for event. - /// - public class DateChangedEventArgs : EventArgs - { - /// - /// The date that the user entered. - /// - public DateTime NewDate { get; } - - /// - /// Creates a new object that represents a change to . - /// - /// Current date of . - public DateChangedEventArgs(DateTime newDate) - { - NewDate = newDate; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/DateTimePicker.cs b/src/Compatibility/Core/src/Tizen/Native/DateTimePicker.cs deleted file mode 100644 index 96e003342dfd..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/DateTimePicker.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public enum DateTimePickerMode - { - Date, - Time - } - - public class DateTimePicker : DateTimeSelector - { - const string TimeFormat = "%d/%b/%Y %I:%M %p"; - const string TimeLayoutStyle = "time_layout"; - - const string DateFormat = "%d/%b/%Y"; - const string DateLayoutStyle = "date_layout"; - - DateTimePickerMode _mode = DateTimePickerMode.Date; - - public DateTimePicker(EvasObject parent) : base(parent) - { - UpdateMode(); - } - - protected DateTimePicker() : base() - { - } - - public DateTimePickerMode Mode - { - get { return _mode; } - set - { - if (_mode != value) - { - _mode = value; - UpdateMode(); - } - } - } - - protected virtual void UpdateMode() - { - if (Mode == DateTimePickerMode.Date) - { - Style = DateLayoutStyle; - Format = DateFormat; - } - else - { - Style = TimeLayoutStyle; - Format = TimeFormat; - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/DateTimePickerDialog.cs b/src/Compatibility/Core/src/Tizen/Native/DateTimePickerDialog.cs deleted file mode 100644 index 03234ecf48ae..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/DateTimePickerDialog.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; -using Microsoft.Maui.Devices; -using ElmSharp; -using EButton = ElmSharp.Button; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class DateTimePickerDialog : Dialog, IDateTimeDialog - { - EvasObject _parent; - DateTimePicker _picker; - - /// - /// Creates a dialog window. - /// - public DateTimePickerDialog(EvasObject parent) : base(parent) - { - _parent = parent; - Initialize(); - } - - /// - /// Gets or sets picker style - /// - public DateTimePickerMode Mode - { - get => _picker.Mode; - set => _picker.Mode = value; - } - - /// - /// Gets or sets the upper boundary of the DateTime field. - /// - public DateTime MaximumDateTime - { - get => _picker.MaximumDateTime; - set => _picker.MaximumDateTime = value; - } - - /// - /// Gets or sets the lower boundary of the DateTime field. - /// - public DateTime MinimumDateTime - { - get => _picker.MinimumDateTime; - set => _picker.MinimumDateTime = value; - } - - /// - /// Gets or sets the current value of the DateTime field. - /// - public DateTime DateTime - { - get => _picker.DateTime; - set => _picker.DateTime = value; - } - - /// - /// Occurs when the date of this dialog has changed. - /// - public event EventHandler DateTimeChanged; - - /// - /// Occurs when the picker dialog has opened. - /// - public event EventHandler PickerOpened; - - /// - /// Occurs when the picker dialog has closed. - /// - public event EventHandler PickerClosed; - - void Initialize() - { - _picker = new DateTimePicker(_parent); - _picker.Show(); - Content = _picker; - - //TODO need to add internationalization support - PositiveButton = new EButton(_parent) { Text = "Set" }; - PositiveButton.Clicked += (s, e) => - { - Confirm(); - }; - - //TODO need to add internationalization support - NegativeButton = new EButton(_parent) { Text = "Cancel" }; - NegativeButton.Clicked += (s, e) => - { - Hide(); - PickerClosed?.Invoke(this, EventArgs.Empty); - }; - BackButtonPressed += (object s, EventArgs e) => - { - Hide(); - PickerClosed?.Invoke(this, EventArgs.Empty); - }; - - ShowAnimationFinished += (object s, EventArgs e) => - { - PickerOpened?.Invoke(this, EventArgs.Empty); - }; - - // TODO This is Tizen TV Limitation. - // UX is defined and the focus move processing is complete, it should be removed(After Tizen 5.0) - if (DeviceInfo.Idiom == DeviceIdiom.TV) - { - KeyDown += (s, e) => - { - if (e.KeyName == "Return") - { - if (_picker != null && _picker.IsFocused) - { - Confirm(); - e.Flags |= EvasEventFlag.OnHold; - } - } - }; - } - } - - void Confirm() - { - DateTimeChanged?.Invoke(this, new DateChangedEventArgs(_picker.DateTime)); - Hide(); - PickerClosed?.Invoke(this, EventArgs.Empty); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Dialog.cs b/src/Compatibility/Core/src/Tizen/Native/Dialog.cs deleted file mode 100644 index 10c4f292cf9c..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Dialog.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System; -using Microsoft.Maui.Devices; -using ElmSharp; -using EButton = ElmSharp.Button; -using EColor = ElmSharp.Color; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - - /// - /// Enumerates the three valid positions of a dialog button. - /// - public enum ButtonPosition - { - Positive, - Neutral, - Negative - } - - /// - /// Base class for Dialogs. - /// A dialog is a small window that prompts the user to make a decision or enter additional information. - /// - public class Dialog : Popup - { - EButton _positiveButton; - EButton _neutralButton; - EButton _negativeButton; - EvasObject _content; - string _title; - string _message; - EColor _titleColor = EColor.Default; - - /// - /// Creates a dialog window. - /// - public static Dialog CreateDialog(EvasObject parent, bool hasAcceptButton = false) - { - if (DeviceInfo.Idiom == DeviceIdiom.Watch) - { - return new Watch.WatchDialog(Forms.NativeParent, hasAcceptButton); - } - else - { - return new Dialog(Forms.NativeParent); - } - } - - /// - /// Creates a dialog window that uses the default dialog theme. - /// - public Dialog(EvasObject parent) : base(parent) - { - Initialize(); - } - - /// - /// Occurs whenever the dialog is first displayed. - /// - public event EventHandler DialogShown; - - /// - /// Gets or sets the title of the dialog - /// - public string Title - { - get - { - return _title; - } - set - { - if (_title != value) - { - _title = value; - ApplyTitle(value); - } - } - } - - public EColor TitleColor - { - get - { - return _titleColor; - } - set - { - if (_titleColor != value) - { - _titleColor = value; - ApplyTitleColor(value); - } - } - } - - /// - /// Gets or sets the message to display in the dialog - /// - public string Message - { - get - { - return _message; - } - set - { - if (_message != value) - { - _message = value; - ApplyMessage(value); - } - } - } - - /// - /// Gets or sets the content to display in that dialog. - /// - public EvasObject Content - { - get - { - return _content; - } - set - { - if (_content != value) - { - _content = value; - ApplyContent(value); - } - } - } - - /// - /// Gets or sets the positive button used in the dialog - /// - public EButton PositiveButton - { - get - { - return _positiveButton; - } - set - { - if (_positiveButton != value) - { - _positiveButton = value; - ApplyButton(ButtonPosition.Positive, value); - } - } - } - - /// - /// Gets or sets the neutral button used in the dialog - /// - public EButton NeutralButton - { - get - { - return _neutralButton; - } - set - { - if (_neutralButton != value) - { - _neutralButton = value; - ApplyButton(ButtonPosition.Neutral, value); - } - } - } - - /// - /// Gets or sets the negative button used in the dialog - /// - public EButton NegativeButton - { - get - { - return _negativeButton; - } - set - { - if (_negativeButton != value) - { - _negativeButton = value; - ApplyButton(ButtonPosition.Negative, value); - } - } - } - - /// - /// Starts the dialog and displays it on screen. - /// - public new void Show() - { - base.Show(); - DialogShown?.Invoke(this, EventArgs.Empty); - } - - /// - /// Handles the disposing of a dialog widget. - /// - protected override void OnUnrealize() - { - _content?.Unrealize(); - _positiveButton?.Unrealize(); - _neutralButton?.Unrealize(); - _negativeButton?.Unrealize(); - ApplyButton(ButtonPosition.Positive, null); - ApplyButton(ButtonPosition.Neutral, null); - ApplyButton(ButtonPosition.Negative, null); - ApplyContent(null); - - base.OnUnrealize(); - } - - /// - /// Called when the dialog is shown. - /// - /// When shown, the dialog will register itself for the back key press event handling. - protected virtual void OnShown() - { - } - - /// - /// Called when the dialog is dismissed. - /// - /// When dismissed, the dialog will unregister itself from the back key press event handling. - protected virtual void OnDismissed() - { - } - - /// - /// Changes the dialog title. - /// - /// New dialog title. - protected virtual void ApplyTitle(string title) - { - this.SetTitleTextPart(title); - } - - protected virtual void ApplyTitleColor(EColor color) - { - this.SetTitleColor(color); - } - - /// - /// Puts the button in one of the three available slots. - /// - /// The slot to be occupied by the button expressed as a - /// The new button. - protected virtual void ApplyButton(ButtonPosition position, EButton button) - { - if (button != null) - { - button.SetPopupStyle(); - } - - switch (position) - { - case ButtonPosition.Positive: - this.SetButton3Part(button, true); - break; - - case ButtonPosition.Neutral: - this.SetButton2Part(button, true); - break; - - default: - this.SetButton1Part(button, true); - break; - } - } - - /// - /// Updates the content of the dialog. - /// - /// New dialog content. - protected virtual void ApplyContent(EvasObject content) - { - this.SetContentPart(content, true); - } - - protected virtual void ApplyMessage(string message) - { - base.Text = message; - } - - /// - /// Handles the initialization process. - /// - /// Creates handlers for vital events - void Initialize() - { - // Adds a handler for the Dismissed event. - // In effect, unregisters this instance from being affected by the hardware back key presses. - Dismissed += (s, e) => - { - OnDismissed(); - }; - - // Adds a handler for the Shown event. - // In effect, registers this instance to be affected by the hardware back key presses. - DialogShown += (s, e) => - { - OnShown(); - }; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/EditfieldEntry.cs b/src/Compatibility/Core/src/Tizen/Native/EditfieldEntry.cs deleted file mode 100644 index b66ab8f5831c..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/EditfieldEntry.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using Microsoft.Maui.Devices; -using ElmSharp; -using EColor = ElmSharp.Color; -using ELayout = ElmSharp.Layout; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class EditfieldEntry : Native.Entry - { - Button _clearButton; - ELayout _editfieldLayout; - bool _enableClearButton; - int _heightPadding = 0; - - public EditfieldEntry(EvasObject parent) : base(parent) - { - } - - public EditfieldEntry(EvasObject parent, string style) : base(parent) - { - if (!string.IsNullOrEmpty(style) && _editfieldLayout is FormsLayout formsLayout) - formsLayout.SetTheme(formsLayout.ThemeClass, formsLayout.ThemeGroup, style); - } - - public bool IsTextBlockFocused { get; private set; } - - public override EColor BackgroundColor - { - get - { - return _editfieldLayout.BackgroundColor; - } - set - { - _editfieldLayout.BackgroundColor = value; - } - } - - public bool EnableClearButton - { - get => _enableClearButton; - set - { - _enableClearButton = value; - UpdateEnableClearButton(); - } - } - - public EColor ClearButtonColor - { - get => _clearButton.GetIconColor(); - set => _clearButton.SetIconColor(value); - } - - public void SetFocusOnTextBlock(bool isFocused) - { - SetFocus(isFocused); - IsTextBlockFocused = isFocused; - - if (isFocused) - OnTextBlockFocused(); - else - OnTextBlcokUnfocused(); - } - - public override ElmSharp.Size Measure(int availableWidth, int availableHeight) - { - var textBlockSize = base.Measure(availableWidth, availableHeight); - - // Calculate the minimum size by adding the width of a TextBlock and an Editfield. - textBlockSize.Width += _editfieldLayout.MinimumWidth; - - // If the height of a TextBlock is shorter than Editfield, use the minimun height of the Editfield. - // Or add the height of the EditField to the TextBlock - if (textBlockSize.Height < _editfieldLayout.MinimumHeight) - { - if (DeviceInfo.Idiom == DeviceIdiom.TV || DeviceInfo.Idiom == DeviceIdiom.Watch) - { - textBlockSize.Height = _editfieldLayout.MinimumHeight; - } - else - { - // Since the minimum height of EditFieldLayout too large, adjust it to an appropriate height. - var adjustedMinHeight = _editfieldLayout.MinimumHeight - (_editfieldLayout.MinimumHeight - _heightPadding) / 2; - textBlockSize.Height = textBlockSize.Height < adjustedMinHeight ? adjustedMinHeight : _editfieldLayout.MinimumHeight; - } - } - else - { - textBlockSize.Height += _heightPadding; - } - - return textBlockSize; - } - - protected override IntPtr CreateHandle(EvasObject parent) - { - var handle = base.CreateHandle(parent); - _editfieldLayout = CreateEditFieldLayout(parent); - - // If true, It means, there is no extra layout on the widget handle - // We need to set RealHandle, becuase we replace Handle to Layout - if (RealHandle == IntPtr.Zero) - { - RealHandle = handle; - } - Handle = handle; - - _editfieldLayout.SetContentPart(this); - _heightPadding = _editfieldLayout.GetContentPartEdjeObject().Geometry.Height; - return _editfieldLayout; - } - - protected override void OnTextChanged(string oldValue, string newValue) - { - base.OnTextChanged(oldValue, newValue); - if (EnableClearButton && _editfieldLayout is EditFieldEntryLayout layout) - { - layout.SendButtonActionSignal(!string.IsNullOrEmpty(newValue)); - } - } - - protected virtual ELayout CreateEditFieldLayout(EvasObject parent) - { - var layout = new EditFieldEntryLayout(parent, EditFieldEntryLayout.Styles.SingleLine); - layout.AllowFocus(true); - layout.Unfocused += (s, e) => - { - SetFocusOnTextBlock(false); - layout.SendFocusStateSignal(false); - OnEntryLayoutUnfocused(); - }; - layout.Focused += (s, e) => - { - layout.SendFocusStateSignal(true); - OnEntryLayoutFocused(); - }; - - layout.KeyDown += (s, e) => - { - if (e.KeyName == "Return") - { - if (!IsTextBlockFocused) - { - SetFocusOnTextBlock(true); - e.Flags |= EvasEventFlag.OnHold; - } - } - }; - Clicked += (s, e) => SetFocusOnTextBlock(true); - - Focused += (s, e) => - { - layout.RaiseTop(); - layout.SendFocusStateSignal(true); - }; - - Unfocused += (s, e) => - { - layout.SendFocusStateSignal(false); - }; - - return layout; - } - - protected virtual void UpdateEnableClearButton() - { - if (_editfieldLayout is EditFieldEntryLayout layout) - { - if (EnableClearButton) - { - _clearButton = (Button)new Button(_editfieldLayout).SetEditFieldClearStyle(); - _clearButton.AllowFocus(false); - _clearButton.Clicked += OnClearButtonClicked; - - layout.SetButtonPart(_clearButton); - layout.SendFocusStateSignal(true); - } - else - { - layout.SetButtonPart(null); - _clearButton = null; - } - } - } - - void OnClearButtonClicked(object sender, EventArgs e) - { - Text = string.Empty; - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/Entry.cs b/src/Compatibility/Core/src/Tizen/Native/Entry.cs deleted file mode 100644 index 20f336d71d88..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Entry.cs +++ /dev/null @@ -1,520 +0,0 @@ -using System; -using ElmSharp; -using EColor = ElmSharp.Color; -using EEntry = ElmSharp.Entry; -using ESize = ElmSharp.Size; - -#if __MATERIAL__ -using Tizen.NET.MaterialComponents; -#endif - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ -#if __MATERIAL__ - public class MaterialEntry : MTextField, IMeasurable, IBatchable, IEntry - { - const int TextFieldMinimumHeight = 115; - - public MaterialEntry(EvasObject parent) : base(parent) - { - Initialize(); - } - -#else - /// - /// Extends the Entry control, providing basic formatting features, - /// i.e. font color, size, placeholder. - /// - public class Entry : EEntry, IMeasurable, IBatchable, IEntry - { - /// - /// Initializes a new instance of the class. - /// - /// Parent evas object. - public Entry(EvasObject parent) : base(parent) - { - Initialize(); - } -#endif - - const int VariationNormal = 0; - const int VariationSignedAndDecimal = 3; - - /// - /// Holds the formatted text of the entry. - /// - readonly Span _span = new Span(); - - /// - /// Holds the formatted text of the placeholder. - /// - readonly Span _placeholderSpan = new Span(); - - /// - /// Helps to detect whether the text change was initiated by the user - /// or via the Text property. - /// - int _changedByUserCallbackDepth; - - /// - /// The type of the keyboard used by the entry. - /// - Keyboard _keyboard; - - /// - /// Occurs when the text has changed. - /// - public event EventHandler TextChanged; - - /// - /// Occurs when the text block get focused. - /// - public event EventHandler TextBlockFocused; - - /// - /// Occurs when the text block loses focus - /// - public event EventHandler TextBlockUnfocused; - - /// - /// Occurs when the layout of entry get focused. - /// - public event EventHandler EntryLayoutFocused; - - /// - /// Occurs when the layout of entry loses focus - /// - public event EventHandler EntryLayoutUnfocused; - - /// - /// Gets or sets the text. - /// - /// The text. - public override string Text - { - get - { - return _span.Text; - } - - set - { - - if (value != _span.Text) - { - var old = _span.Text; - _span.Text = value; - ApplyTextAndStyle(); - Application.Current.Dispatcher.DispatchDelayed(TimeSpan.FromTicks(1), () => OnTextChanged(old, value)); - } - } - } - - /// - /// Gets or sets the color of the text. - /// - /// The color of the text. -#if __MATERIAL__ - public new EColor TextColor -#else - public EColor TextColor -#endif - { - get - { - return _span.ForegroundColor; - } - - set - { - if (!_span.ForegroundColor.Equals(value)) - { - _span.ForegroundColor = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the font family of the text and the placeholder. - /// - /// The font family of the text and the placeholder. - public string FontFamily - { - get - { - return _span.FontFamily; - } - - set - { - if (value != _span.FontFamily) - { - _span.FontFamily = value; - ApplyTextAndStyle(); - - _placeholderSpan.FontFamily = value; - ApplyPlaceholderAndStyle(); - } - } - } - - /// - /// Gets or sets the font attributes of the text and the placeholder. - /// - /// The font attributes of the text and the placeholder. - public FontAttributes FontAttributes - { - get - { - return _span.FontAttributes; - } - - set - { - if (value != _span.FontAttributes) - { - _span.FontAttributes = value; - ApplyTextAndStyle(); - - _placeholderSpan.FontAttributes = value; - ApplyPlaceholderAndStyle(); - } - } - } - - - /// - /// Gets or sets the size of the font of both text and placeholder. - /// - /// The size of the font of both text and placeholder. - public double FontSize - { - get - { - return _span.FontSize; - } - - set - { - if (value != _span.FontSize) - { - _span.FontSize = value; - ApplyTextAndStyle(); - - _placeholderSpan.FontSize = value; - ApplyPlaceholderAndStyle(); - } - } - } - - /// - /// Gets or sets the font weight for the text. - /// - /// The weight of the font. - public string FontWeight - { - get - { - return _span.FontWeight; - } - - set - { - if (value != _span.FontWeight) - { - _span.FontWeight = value; - ApplyTextAndStyle(); - - _placeholderSpan.FontWeight = value; - ApplyPlaceholderAndStyle(); - } - } - } - - /// - /// Gets or sets the horizontal text alignment of both text and placeholder. - /// - /// The horizontal text alignment of both text and placeholder. - public TextAlignment HorizontalTextAlignment - { - get - { - return _span.HorizontalTextAlignment; - } - - set - { - if (value != _span.HorizontalTextAlignment) - { - _span.HorizontalTextAlignment = value; - ApplyTextAndStyle(); - - _placeholderSpan.HorizontalTextAlignment = value; - ApplyPlaceholderAndStyle(); - } - } - } - - /// - /// Gets or sets the keyboard type used by the entry. - /// - /// The keyboard type. - public Keyboard Keyboard - { - get - { - return _keyboard; - } - - set - { - if (value != _keyboard) - { - ApplyKeyboard(value); - } - } - } - - /// - /// Gets or sets the placeholder's text. - /// - /// The placeholder's text. - public string Placeholder - { - get - { - return _placeholderSpan.Text; - } - - set - { - if (value != _placeholderSpan.Text) - { - _placeholderSpan.Text = value; - ApplyPlaceholderAndStyle(); - } - } - } - - /// - /// Gets or sets the color of the placeholder's text. - /// - /// The color of the placeholder's text. - public EColor PlaceholderColor - { - get - { - return _placeholderSpan.ForegroundColor; - } - - set - { - if (!_placeholderSpan.ForegroundColor.Equals(value)) - { - _placeholderSpan.ForegroundColor = value; - ApplyPlaceholderAndStyle(); - } - } - } - - /// - /// Implementation of the IMeasurable.Measure() method. - /// - public virtual ESize Measure(int availableWidth, int availableHeight) - { - var originalSize = Geometry; - // resize the control using the whole available width - Resize(availableWidth, originalSize.Height); - - ESize rawSize; - ESize formattedSize; - - // if there's no text, but there's a placeholder, use it for measurements - if (string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Placeholder)) - { - rawSize = this.GetPlaceHolderTextBlockNativeSize(); - formattedSize = this.GetPlaceHolderTextBlockFormattedSize(); - } - else - { - // there's text in the entry, use it instead - rawSize = this.GetTextBlockNativeSize(); - formattedSize = this.GetTextBlockFormattedSize(); - } - - // restore the original size - Resize(originalSize.Width, originalSize.Height); - - // Set bottom padding for lower case letters that have segments below the bottom line of text (g, j, p, q, y). - var verticalPadding = (int)Math.Ceiling(0.05 * FontSize); - var horizontalPadding = (int)Math.Ceiling(0.2 * FontSize); - rawSize.Height += verticalPadding; - formattedSize.Height += verticalPadding; - formattedSize.Width += horizontalPadding; - - ESize size; - - // if the raw text width is larger than available width, we use the available width, - // while height is set to the smallest height value - if (rawSize.Width > availableWidth) - { - size.Width = availableWidth; - size.Height = Math.Min(formattedSize.Height, Math.Max(rawSize.Height, availableHeight)); - } - else - { - // width is fine, return the formatted text size - size = formattedSize; - } - -#if __MATERIAL__ - // for adapting material style, - // the height of the entry should be bigger than minimun size defined by Tizen.NET.Material.Components - if (size.Height < TextFieldMinimumHeight) - { - size.Height = TextFieldMinimumHeight; - } -#endif - return size; - - } - - protected virtual void OnTextBlockFocused() - { - TextBlockFocused?.Invoke(this, EventArgs.Empty); - } - - protected virtual void OnTextBlcokUnfocused() - { - TextBlockUnfocused?.Invoke(this, EventArgs.Empty); - } - - protected virtual void OnEntryLayoutFocused() - { - EntryLayoutFocused?.Invoke(this, EventArgs.Empty); - } - - protected virtual void OnEntryLayoutUnfocused() - { - EntryLayoutUnfocused?.Invoke(this, EventArgs.Empty); - } - - protected virtual void OnTextChanged(string oldValue, string newValue) - { - TextChanged?.Invoke(this, new TextChangedEventArgs(oldValue, newValue)); - } - - void Initialize() - { - Scrollable = true; - - ChangedByUser += (s, e) => - { - _changedByUserCallbackDepth++; - - Text = GetInternalText(); - - _changedByUserCallbackDepth--; - }; - - ApplyKeyboard(Keyboard.Normal); - } - - void IBatchable.OnBatchCommitted() - { - ApplyTextAndStyle(); - } - - /// - /// Applies entry's text and its style. - /// - void ApplyTextAndStyle() - { - if (!this.IsBatched()) - { - SetInternalTextAndStyle(_span.GetDecoratedText(), _span.GetStyle()); - } - } - - /// - /// Sets entry's internal text and its style. - /// - /// Formatted text, supports HTML tags. - /// Style applied to the formattedText. - void SetInternalTextAndStyle(string formattedText, string textStyle) - { - if (_changedByUserCallbackDepth == 0) - { - base.Text = formattedText; - base.TextStyle = textStyle; - } - } - - /// - /// Gets the internal text representation of the entry. - /// - /// The internal text representation. - string GetInternalText() - { - return EEntry.ConvertMarkupToUtf8(base.Text); - } - - /// - /// Applies the keyboard type to be used by the entry. - /// - /// Keyboard type to be used. - void ApplyKeyboard(Keyboard keyboard) - { - _keyboard = keyboard; - SetInternalKeyboard(keyboard); - } - - /// - /// Configures the ElmSharp.Entry with specified keyboard type and displays - /// the keyboard automatically unless the provided type is Keyboard.None. - /// - /// Keyboard type to be used. - void SetInternalKeyboard(Keyboard keyboard) - { - if (keyboard == Keyboard.None) - { - SetInputPanelEnabled(false); - } - else if (Keyboard == Keyboard.Numeric) - { - SetInputPanelEnabled(true); - SetInputPanelLayout(InputPanelLayout.NumberOnly); - // InputPanelVariation is used to allow using deciaml point. - InputPanelVariation = VariationSignedAndDecimal; - } - else - { - SetInputPanelEnabled(true); - SetInputPanelLayout((InputPanelLayout)keyboard); - InputPanelVariation = VariationNormal; - } - } - - /// - /// Applies placeholders's text and its style. - /// - void ApplyPlaceholderAndStyle() - { - SetInternalPlaceholderAndStyle(_placeholderSpan.GetMarkupText()); - } - - /// - /// Sets placeholder's internal text and style. - /// - /// Markup text to be used as a placeholder. - protected virtual void SetInternalPlaceholderAndStyle(string markupText) - { -#if __MATERIAL__ - base.Label = markupText; -#else - this.SetPlaceHolderTextPart(markupText ?? ""); -#endif - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/EvasBox.cs b/src/Compatibility/Core/src/Tizen/Native/EvasBox.cs deleted file mode 100644 index a183c669d29b..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/EvasBox.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using ElmSharp; -using EColor = ElmSharp.Color; -using ERectangle = ElmSharp.Rectangle; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class EvasBox : Container - { - Interop.CanvasBoxLayoutCallback _layoutCallback; - Lazy _rectangle; - - public event EventHandler LayoutUpdated; - - public EvasBox(EvasObject parent) : base(parent) - { - _rectangle = new Lazy(() => - { - var rectangle = new ERectangle(this) { AlignmentX = -1, AlignmentY = -1, WeightX = 1, WeightY = 1 }; - Interop.evas_object_box_insert_at(Handle, rectangle, 0); - rectangle.Lower(); - rectangle.Show(); - return rectangle; - }); - - SetLayoutCallback(() => { NotifyOnLayout(); }); - } - - public override EColor BackgroundColor - { - get - { - return _rectangle.Value.Color; - } - set - { - _rectangle.Value.Color = value.IsDefault ? EColor.Transparent : value; - } - } - - public void PackEnd(EvasObject content) - { - Interop.evas_object_box_append(Handle, content); - AddChild(content); - } - - public bool UnPack(EvasObject content) - { - var ret = Interop.evas_object_box_remove(Handle, content); - if (ret) - RemoveChild(content); - return ret; - } - - public bool UnPackAll() - { - var ret = Interop.evas_object_box_remove_all(Handle, true); - if (ret) - { - ClearChildren(); - if (_rectangle.IsValueCreated) - { - Interop.evas_object_box_append(Handle, _rectangle.Value); - } - } - return ret; - } - - public void SetLayoutCallback(Action action) - { - _layoutCallback = (obj, priv, data) => - { - if (_rectangle.IsValueCreated) - { - _rectangle.Value.Geometry = Geometry; - } - action(); - }; - Interop.evas_object_box_layout_set(Handle, _layoutCallback, IntPtr.Zero, null); - } - - protected override IntPtr CreateHandle(EvasObject parent) - { - return Interop.evas_object_box_add(Interop.evas_object_evas_get(parent.Handle)); - } - - void NotifyOnLayout() - { - if (null != LayoutUpdated) - { - LayoutUpdated(this, new LayoutEventArgs() { Geometry = Geometry }); - } - } - - class Interop - { - public const string LibEvas = "libevas.so.1"; - - public delegate void CanvasBoxLayoutCallback(IntPtr obj, IntPtr priv, IntPtr userData); - - public delegate void CanvasBoxDataFreeCallback(IntPtr data); - - [DllImport(LibEvas)] - internal static extern IntPtr evas_object_box_add(IntPtr evas); - - [DllImport(LibEvas)] - internal static extern IntPtr evas_object_evas_get(IntPtr obj); - - [DllImport(LibEvas)] - internal static extern void evas_object_box_append(IntPtr obj, IntPtr child); - - [DllImport(LibEvas)] - internal static extern void evas_object_box_insert_at(IntPtr obj, IntPtr child, int pos); - - [DllImport(LibEvas)] - [return: MarshalAs(UnmanagedType.U1)] - internal static extern bool evas_object_box_remove(IntPtr obj, IntPtr child); - - [DllImport(LibEvas)] - [return: MarshalAs(UnmanagedType.U1)] - internal static extern bool evas_object_box_remove_all(IntPtr obj, bool clear); - - [DllImport(LibEvas)] - internal static extern void evas_object_box_layout_set(IntPtr obj, CanvasBoxLayoutCallback cb, IntPtr data, CanvasBoxDataFreeCallback dataFreeCb); - - [DllImport(LibEvas)] - internal static extern void evas_object_box_layout_set(IntPtr obj, CanvasBoxLayoutCallback cb, IntPtr data, IntPtr dataFreeCb); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/EvasFormsCanvas.cs b/src/Compatibility/Core/src/Tizen/Native/EvasFormsCanvas.cs deleted file mode 100644 index aaafc6347e16..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/EvasFormsCanvas.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Specialized; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class EvasFormsCanvas : EvasBox, IContainable - { - public EvasFormsCanvas(EvasObject parent) : base(parent) - { - Initilize(); - } - - readonly ObservableCollection _children = new ObservableCollection(); - - public new IList Children - { - get - { - return _children; - } - } - - protected override void OnUnrealize() - { - foreach (var child in _children) - { - child.Unrealize(); - } - - base.OnUnrealize(); - } - - void Initilize() - { - _children.CollectionChanged += (o, e) => - { - if (e.Action == NotifyCollectionChangedAction.Add) - { - foreach (var v in e.NewItems) - { - var view = v as EvasObject; - if (null != view) - { - OnAdd(view); - } - } - } - else if (e.Action == NotifyCollectionChangedAction.Remove) - { - foreach (var v in e.OldItems) - { - var view = v as EvasObject; - if (null != view) - { - OnRemove(view); - } - } - } - else if (e.Action == NotifyCollectionChangedAction.Reset) - { - OnRemoveAll(); - } - }; - } - - void OnAdd(EvasObject view) - { - PackEnd(view); - } - - void OnRemove(EvasObject view) - { - UnPack(view); - } - - void OnRemoveAll() - { - UnPackAll(); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/FlyoutPage.cs b/src/Compatibility/Core/src/Tizen/Native/FlyoutPage.cs deleted file mode 100644 index 7f8a732d76a1..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/FlyoutPage.cs +++ /dev/null @@ -1,505 +0,0 @@ -using System; -using ElmSharp; -using Microsoft.Maui.Devices; -using Microsoft.Maui.Controls.Internals; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// The native widget which provides Xamarin.FlyoutPage features. - /// - public class FlyoutPage : Box - { - /// - /// The default flyout layout behavior (a.k.a mode). - /// - static readonly FlyoutLayoutBehavior s_defaultFlyoutLayoutBehavior = (DeviceInfo.Idiom == DeviceIdiom.Phone || DeviceInfo.Idiom == DeviceIdiom.Watch) ? FlyoutLayoutBehavior.Popover : FlyoutLayoutBehavior.SplitOnLandscape; - - /// - /// The Flyout native container. - /// - readonly Canvas _flyoutCanvas; - - /// - /// The Detail native container. - /// - readonly Canvas _detailCanvas; - - /// - /// The container for _flyoutCanvas and _detailCanvas used in split mode. - /// - readonly Panes _splitPane; - - /// - /// The container for _flyoutCanvas used in popover mode. - /// - readonly Panel _drawer; - - /// - /// The property value. - /// - FlyoutLayoutBehavior _flyoutLayoutBehavior = s_defaultFlyoutLayoutBehavior; - - /// - /// The actual FlyoutPage mode - either split or popover. It depends on _flyoutLayoutBehavior and screen orientation. - /// - FlyoutLayoutBehavior _internalFlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover; - - /// - /// The property value. - /// - EvasObject _flyout; - - /// - /// The property value. - /// - EvasObject _detail; - - /// - /// The main widget - either or , depending on the mode. - /// - EvasObject _mainWidget; - - /// - /// The property value. - /// - bool _isGestureEnabled = true; - - /// - /// The portion of the screen that the Flyout takes in Split mode. - /// - double _splitRatio = 0.35; - - /// - /// The portion of the screen that the Flyout takes in Popover mode. - /// - double _popoverRatio = 0.8; - - /// - /// Initializes a new instance of the class. - /// - /// Parent evas object. - public FlyoutPage(EvasObject parent) : base(parent) - { - LayoutUpdated += (s, e) => - { - UpdateChildCanvasGeometry(); - }; - - // create the controls which will hold the flyout and detail pages - _flyoutCanvas = new Canvas(this); - _flyoutCanvas.SetAlignment(-1.0, -1.0); // fill - _flyoutCanvas.SetWeight(1.0, 1.0); // expand - _flyoutCanvas.LayoutUpdated += (sender, e) => - { - UpdatePageGeometry(_flyout); - }; - - _detailCanvas = new Canvas(this); - _detailCanvas.SetAlignment(-1.0, -1.0); // fill - _detailCanvas.SetWeight(1.0, 1.0); // expand - _detailCanvas.LayoutUpdated += (sender, e) => - { - UpdatePageGeometry(_detail); - }; - - _splitPane = new Panes(this) - { - AlignmentX = -1, - AlignmentY = -1, - WeightX = 1, - WeightY = 1, - IsFixed = true, - IsHorizontal = false, - Proportion = _splitRatio, - }; - - _drawer = new Panel(Forms.NativeParent); - _drawer.SetScrollable(_isGestureEnabled); - _drawer.SetScrollableArea(1.0); - _drawer.Direction = PanelDirection.Left; - _drawer.Toggled += (object sender, EventArgs e) => - { - UpdateFocusPolicy(); - IsPresentedChanged?.Invoke(this, new IsPresentedChangedEventArgs(_drawer.IsOpen)); - }; - - ConfigureLayout(); - - // in case of the screen rotation we may need to update the choice between split - // and popover behaviors and reconfigure the layout - DeviceDisplay.MainDisplayInfoChanged += (s, e) => - { - UpdateFlyoutLayoutBehavior(); - }; - } - - /// - /// Occurs when the Flyout is shown or hidden. - /// - public event EventHandler IsPresentedChanged; - - /// - /// Occurs when the IsPresentChangeable was changed. - /// - public event EventHandler UpdateIsPresentChangeable; - - /// - /// Gets or sets the FlyoutPage behavior. - /// - /// The behavior of the FlyoutPage requested by the user. - public FlyoutLayoutBehavior FlyoutLayoutBehavior - { - get - { - return _flyoutLayoutBehavior; - } - - set - { - _flyoutLayoutBehavior = value; - UpdateFlyoutLayoutBehavior(); - } - } - - /// - /// Gets the FlyoutPage was splited - /// - public bool IsSplit => _internalFlyoutLayoutBehavior == FlyoutLayoutBehavior.Split; - - /// - /// Gets or sets the content of the Flyout. - /// - /// The Flyout. - public EvasObject Flyout - { - get - { - return _flyout; - } - - set - { - if (_flyout != value) - { - _flyout = value; - UpdatePageGeometry(_flyout); - _flyoutCanvas.Children.Clear(); - _flyoutCanvas.Children.Add(_flyout); - if (!IsSplit) - UpdateFocusPolicy(); - } - } - } - - /// - /// Gets or sets the content of the DetailPage. - /// - /// The DetailPage. - public EvasObject Detail - { - get - { - return _detail; - } - - set - { - if (_detail != value) - { - _detail = value; - UpdatePageGeometry(_detail); - _detailCanvas.Children.Clear(); - _detailCanvas.Children.Add(_detail); - if (!IsSplit) - UpdateFocusPolicy(); - } - } - } - - /// - /// Gets or sets a value indicating whether the Flyout is shown. - /// - /// true if the Flyout is presented. - public bool IsPresented - { - get - { - return _drawer.IsOpen; - } - - set - { - if (_drawer.IsOpen != value) - { - _drawer.IsOpen = value; - } - } - } - - /// - /// Gets or sets a value indicating whether a FlyoutPage allows showing FlyoutPage with swipe gesture. - /// - /// true if the FlyoutPage can be revealed with a gesture. - public bool IsGestureEnabled - { - get - { - return _isGestureEnabled; - } - - set - { - if (_isGestureEnabled != value) - { - _isGestureEnabled = value; - // Fixme - // Elementary panel was not support to change scrollable property on runtime - // Please uncomment when EFL was updated - //_drawer.SetScrollable(_isGestureEnabled); - } - } - } - - /// - /// Gets or Sets the portion of the screen that the FlyoutPage takes in split mode. - /// - /// The portion. - public double SplitRatio - { - get - { - return _splitRatio; - } - set - { - if (_splitRatio != value) - { - _splitRatio = value; - _splitPane.Proportion = _splitRatio; - } - } - - } - - /// - /// Gets or sets the portion of the screen that the FlyoutPage takes in Popover mode. - /// - /// The portion. - public double PopoverRatio - { - get - { - return _popoverRatio; - } - set - { - if (_popoverRatio != value) - { - _popoverRatio = value; - UpdateChildCanvasGeometry(); - } - } - } - - /// - /// Provides destruction for native element and contained elements. - /// - protected override void OnUnrealize() - { - // Views that are not belong to view tree should be unrealized. - if (IsSplit) - { - _drawer.Unrealize(); - } - else - { - _splitPane.Unrealize(); - } - base.OnUnrealize(); - } - - /// - /// Updates the geometry of the selected page. - /// - /// Flyout or Detail page to be updated. - void UpdatePageGeometry(EvasObject page) - { - if (page != null) - { - if (_flyout == page) - { - // update the geometry of the flyout page - page.Geometry = _flyoutCanvas.Geometry; - } - else if (_detail == page) - { - // update the geometry of the detail page - page.Geometry = _detailCanvas.Geometry; - } - } - } - - /// - /// Updates according to set by the user and current screen orientation. - /// - void UpdateFlyoutLayoutBehavior() - { - var behavior = (_flyoutLayoutBehavior == FlyoutLayoutBehavior.Default) ? s_defaultFlyoutLayoutBehavior : _flyoutLayoutBehavior; - - // Screen orientation affects those 2 behaviors - if (behavior == FlyoutLayoutBehavior.SplitOnLandscape || behavior == FlyoutLayoutBehavior.SplitOnPortrait) - { - var orientation = DeviceDisplay.MainDisplayInfo.Orientation; - - if ((orientation.IsLandscape() && behavior == FlyoutLayoutBehavior.SplitOnLandscape) || (orientation.IsPortrait() && behavior == FlyoutLayoutBehavior.SplitOnPortrait)) - { - behavior = FlyoutLayoutBehavior.Split; - } - else - { - behavior = FlyoutLayoutBehavior.Popover; - } - } - - if (behavior != _internalFlyoutLayoutBehavior) - { - _internalFlyoutLayoutBehavior = behavior; - ConfigureLayout(); - } - } - - /// - /// Composes the structure of all the necessary widgets. - /// - void ConfigureLayout() - { - _drawer.SetContent(null, true); - _drawer.Hide(); - - _splitPane.SetLeftPart(null, true); - _splitPane.SetRightPart(null, true); - _splitPane.Hide(); - - UnPackAll(); - - // the structure for split mode and for popover mode looks differently - if (IsSplit) - { - _splitPane.SetLeftPart(_flyoutCanvas, true); - _splitPane.SetRightPart(_detailCanvas, true); - _splitPane.Show(); - _mainWidget = _splitPane; - PackEnd(_splitPane); - - IsPresented = true; - UpdateIsPresentChangeable?.Invoke(this, new UpdateIsPresentChangeableEventArgs(false)); - UpdateFocusPolicy(true); - } - else - { - _drawer.SetContent(_flyoutCanvas, true); - _drawer.Show(); - _mainWidget = _detailCanvas; - PackEnd(_detailCanvas); - PackEnd(_drawer); - - _drawer.IsOpen = IsPresented; - UpdateIsPresentChangeable?.Invoke(this, new UpdateIsPresentChangeableEventArgs(true)); - UpdateFocusPolicy(); - } - - _flyoutCanvas.Show(); - _detailCanvas.Show(); - - // even though child was changed, Layout callback was not called, so i manually call layout function. - // Layout callback was filter out when geometry was not changed in Native.Box - UpdateChildCanvasGeometry(); - } - - void UpdateChildCanvasGeometry() - { - var bound = Geometry; - // main widget should fill the area of the FlyoutPage - if (_mainWidget != null) - { - _mainWidget.Geometry = bound; - } - - bound.Width = (int)((_popoverRatio * bound.Width)); - _drawer.Geometry = bound; - // When a _drawer.IsOpen was false, Content of _drawer area is not allocated. So, need to manaully set the content area - if (!IsSplit) - _flyoutCanvas.Geometry = bound; - } - - /// - /// Force update the focus management - /// - void UpdateFocusPolicy(bool forceAllowFocusAll = false) - { - var flyout = _flyout as Widget; - var detail = _detail as Widget; - - if (forceAllowFocusAll) - { - if (flyout != null) - flyout.AllowTreeFocus = true; - if (detail != null) - detail.AllowTreeFocus = true; - return; - } - - if (_drawer.IsOpen) - { - if (detail != null) - { - detail.AllowTreeFocus = false; - } - if (flyout != null) - { - flyout.AllowTreeFocus = true; - flyout.SetFocus(true); - } - } - else - { - if (flyout != null) - { - flyout.AllowTreeFocus = false; - } - if (detail != null) - { - detail.AllowTreeFocus = true; - detail.SetFocus(true); - } - } - } - } - - public class IsPresentedChangedEventArgs : EventArgs - { - public IsPresentedChangedEventArgs(bool isPresent) - { - IsPresent = isPresent; - } - - /// - /// Value of IsPresent - /// - public bool IsPresent { get; private set; } - } - - public class UpdateIsPresentChangeableEventArgs : EventArgs - { - public UpdateIsPresentChangeableEventArgs(bool canChange) - { - CanChange = canChange; - } - - /// - /// Value of changeable - /// - public bool CanChange { get; private set; } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/FormattedString.cs b/src/Compatibility/Core/src/Tizen/Native/FormattedString.cs deleted file mode 100644 index 23177d7d1186..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/FormattedString.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Represents a text with attributes applied to some parts. - /// - /// - /// Formatted string consists of spans that represent text segments with various attributes applied. - /// - public class FormattedString - { - /// - /// A flag indicating whether the instance contains just a plain string without any formatting. - /// - /// - /// true if the instance contains an unformatted string. - /// - readonly bool _just_string; - - /// - /// Holds the unformatted string. - /// - /// - /// The contents of this field are accurate if and only if the _just_string flag is set. - /// - readonly string _string; - - /// - /// Holds the collection of span elements. - /// - /// - /// Span elements are basically chunks of text with uniform formatting. - /// - readonly ObservableCollection _spans; - - /// - /// Returns the collection of span elements. - /// - public IList Spans { get { return _spans; } } - - /// - /// Creates a new FormattedString instance with an empty string. - /// - public FormattedString() - { - _just_string = false; - _spans = new ObservableCollection(); - } - - /// - /// Creates a new FormattedString instance based on given str. - /// - /// - /// A string used to make a new FormattedString instance. - /// - public FormattedString(string str) - { - _just_string = true; - _string = str; - } - - /// - /// Returns the plain text of the FormattedString as an unformatted string. - /// - /// - /// The text content of the FormattedString without any format applied. - /// - public override string ToString() - { - if (_just_string) - { - return _string; - } - else - { - return string.Concat(from span in this.Spans select span.Text); - } - } - - /// - /// Returns the markup text representation of the FormattedString instance. - /// - /// The string containing a markup text. - internal string ToMarkupString() - { - if (_just_string) - { - return _string; - } - else - { - return string.Concat(from span in Spans select span.GetMarkupText()); - } - } - - /// - /// Casts the FormattedString to a string. - /// - /// The FormattedString instance which will be used for the conversion. - public static explicit operator string(FormattedString formatted) - { - return formatted.ToString(); - } - - /// - /// Casts the string to a FormattedString. - /// - /// The text which will be put in a new FormattedString instance. - public static implicit operator FormattedString(string text) - { - return new FormattedString(text); - } - - /// - /// Casts the Span to a FormattedString. - /// - /// The span which will be used for the conversion. - public static implicit operator FormattedString(Span span) - { - return new FormattedString() - { - Spans = { span } - }; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/FormsLayout.cs b/src/Compatibility/Core/src/Tizen/Native/FormsLayout.cs deleted file mode 100644 index 423e48c1ff03..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/FormsLayout.cs +++ /dev/null @@ -1,128 +0,0 @@ -using ElmSharp; - -using ELayout = ElmSharp.Layout; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class FormsLayout : ELayout - { - public string ThemeClass { get; private set; } - public string ThemeGroup { get; private set; } - public string ThemeStyle { get; private set; } - - public FormsLayout(EvasObject parent) : base(parent) - { - } - - public new void SetTheme(string klass, string group, string style) - { - base.SetTheme(klass, group, style); - ThemeClass = klass; - ThemeGroup = group; - ThemeStyle = style; - } - } - - public class ApplicationLayout : FormsLayout - { - public class Styles - { - public const string Default = "default"; - } - - public class Parts - { - public const string Content = "elm.swallow.content"; - public const string Background = "elm.swallow.bg"; - } - - public ApplicationLayout(EvasObject parent, string style = Styles.Default) : base(parent) - { - SetTheme("layout", "application", style); - } - - public bool SetContentPart(EvasObject content, bool preserveOldContent = false) - { - return SetPartContent(Parts.Content, content, preserveOldContent); - } - - public bool SetBackgroundPart(EvasObject content, bool preserveOldContent = false) - { - return SetPartContent(Parts.Background, content, preserveOldContent); - } - } - - public class WidgetLayout : FormsLayout - { - public class Styles - { - public const string Default = "default"; - } - - public WidgetLayout(EvasObject parent, string style = Styles.Default) : base(parent) - { - SetTheme("layout", "elm_widget", style); - } - } - - public class EntryLayout : FormsLayout - { - public class Styles - { - public const string Default = "default"; - } - - public class Parts - { - public const string Content = "elm.swallow.content"; - } - - public EntryLayout(EvasObject parent, string style = Styles.Default) : base(parent) - { - SetTheme("layout", "entry", style); - } - } - - public class EditFieldEntryLayout : FormsLayout - { - public class Styles - { - public const string SingleLine = "singleline"; - public const string MulitLine = "multiline"; - } - - public class Parts - { - public const string Button = "elm.swallow.button"; - } - - public class Signals - { - public const string FocusedState = "elm,state,focused"; - public const string UnFocusedState = "elm,state,unfocused"; - public const string ShowButtonAction = "elm,action,show,button"; - public const string HideButtonAction = "elm,action,hide,button"; - } - - public EditFieldEntryLayout(EvasObject parent, string style) : base(parent) - { - SetTheme("layout", "editfield", style); - } - - public bool SetButtonPart(EvasObject content, bool preserveOldContent = false) - { - return SetPartContent(Parts.Button, content, preserveOldContent); - } - - public void SendButtonActionSignal(bool isVisible) - { - SignalEmit(isVisible ? Signals.ShowButtonAction : Signals.HideButtonAction, ""); - } - - public void SendFocusStateSignal(bool isFocus) - { - SignalEmit(isFocus ? Signals.FocusedState : Signals.UnFocusedState, ""); - } - - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/IBatchable.cs b/src/Compatibility/Core/src/Tizen/Native/IBatchable.cs deleted file mode 100644 index a79df34062ff..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/IBatchable.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - internal interface IBatchable - { - void OnBatchCommitted(); - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/IButton.cs b/src/Compatibility/Core/src/Tizen/Native/IButton.cs deleted file mode 100644 index c8a0208b6309..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/IButton.cs +++ /dev/null @@ -1,24 +0,0 @@ -using EColor = ElmSharp.Color; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public interface IButton - { - string Text { get; set; } - - double FontSize { get; set; } - - FontAttributes FontAttributes { get; set; } - - string FontFamily { get; set; } - - EColor TextColor { get; set; } - - Image Image { get; set; } - - ESize Measure(int availableWidth, int availableHeight); - - void UpdateStyle(string style); - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/IContainable.cs b/src/Compatibility/Core/src/Tizen/Native/IContainable.cs deleted file mode 100644 index a157546a092f..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/IContainable.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Interface defining methods for managing elements of the container. - /// - /// The type of element that can be added to the container. - public interface IContainable - { - /// - /// The children collection of an element. - /// - IList Children { get; } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/IDateTimeDialog.cs b/src/Compatibility/Core/src/Tizen/Native/IDateTimeDialog.cs deleted file mode 100644 index 0a3f35682ca7..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/IDateTimeDialog.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public interface IDateTimeDialog - { - string Title { get; set; } - DateTimePickerMode Mode { get; set; } - DateTime MaximumDateTime { get; set; } - DateTime MinimumDateTime { get; set; } - DateTime DateTime { get; set; } - - event EventHandler DateTimeChanged; - event EventHandler PickerOpened; - event EventHandler PickerClosed; - - void Show(); - void Hide(); - void Unrealize(); - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/IEntry.cs b/src/Compatibility/Core/src/Tizen/Native/IEntry.cs deleted file mode 100644 index ecb3ee22fbc7..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/IEntry.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using EColor = ElmSharp.Color; - - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public interface IEntry - { - double FontSize { get; set; } - - FontAttributes FontAttributes { get; set; } - - string FontFamily { get; set; } - - EColor TextColor { get; set; } - - TextAlignment HorizontalTextAlignment { get; set; } - - string Placeholder { get; set; } - - EColor PlaceholderColor { get; set; } - - string FontWeight { get; set; } - - Keyboard Keyboard { get; set; } - - event EventHandler TextChanged; - - event EventHandler TextBlockFocused; - - event EventHandler TextBlockUnfocused; - - event EventHandler EntryLayoutFocused; - - event EventHandler EntryLayoutUnfocused; - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/IMeasurable.cs b/src/Compatibility/Core/src/Tizen/Native/IMeasurable.cs deleted file mode 100644 index 8d4f922e40e5..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/IMeasurable.cs +++ /dev/null @@ -1,20 +0,0 @@ -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Interface of the controls which can measure their size taking into - /// account the available area. - /// - public interface IMeasurable - { - /// - /// Measures the size of the control in order to fit it into the - /// available area. - /// - /// Available width. - /// Available height. - /// Size of the control that fits the available area. - ESize Measure(int availableWidth, int availableHeight); - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/ITableView.cs b/src/Compatibility/Core/src/Tizen/Native/ITableView.cs deleted file mode 100644 index b67ae0479e43..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/ITableView.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - interface ITableView - { - void ApplyTableRoot(TableRoot root); - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/ITextable.cs b/src/Compatibility/Core/src/Tizen/Native/ITextable.cs deleted file mode 100644 index 2a82c3ed1c11..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/ITextable.cs +++ /dev/null @@ -1,68 +0,0 @@ -using EColor = ElmSharp.Color; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Interface defining properties of formattable text. - /// - public interface ITextable - { - /// - /// Get or sets the formatted text. - /// - FormattedString FormattedText { get; set; } - - /// - /// Gets or sets the text. - /// - string Text { get; set; } - - /// - /// Gets or sets the color for the text. - /// - EColor TextColor { get; set; } - - /// - /// Gets or sets the background color for the text. - /// - EColor TextBackgroundColor { get; set; } - - /// - /// Gets or sets the font family for the text. - /// - string FontFamily { get; set; } - - /// - /// Gets or sets the font attributes for the text. - /// See for information about FontAttributes. - /// - FontAttributes FontAttributes { get; set; } - - /// - /// Gets or sets the font size for the text. - /// - double FontSize { get; set; } - - /// - /// Gets or sets the horizontal alignment mode for the text. - /// See for information about TextAlignment. - /// - TextAlignment HorizontalTextAlignment { get; set; } - - /// - /// Gets or sets the vertical alignment mode for the text. - /// See for information about TextAlignment. - /// - TextAlignment VerticalTextAlignment { get; set; } - - /// - /// Gets or sets the value that indicates whether the text has underline. - /// - bool Underline { get; set; } - - /// - /// Gets or sets the value that indicates whether the text has strike line though it. - /// - bool Strikethrough { get; set; } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Image.cs b/src/Compatibility/Core/src/Tizen/Native/Image.cs deleted file mode 100644 index 66385d3d7a06..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Image.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Threading.Tasks; -using ElmSharp; -using EImage = ElmSharp.Image; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Extends the ElmSharp.Image class with functionality useful to renderer. - /// - public class Image : EImage, IMeasurable - { - /// - /// Initializes a new instance of the class. - /// - /// The parent EvasObject. - public Image(EvasObject parent) : base(parent) - { - } - - /// - /// Implements the interface. - /// - /// Available width. - /// Available height. - public ESize Measure(int availableWidth, int availableHeight) - { - var imageSize = ObjectSize; - var size = new ESize() - { - Width = imageSize.Width, - Height = imageSize.Height, - }; - - if (0 != availableWidth && 0 != availableHeight - && (imageSize.Width > availableWidth || imageSize.Height > availableHeight)) - { - // when available size is limited and insufficient for the image ... - double imageRatio = (double)imageSize.Width / (double)imageSize.Height; - double availableRatio = (double)availableWidth / (double)availableHeight; - // depending on the relation between availableRatio and imageRatio, copy the availableWidth or availableHeight - // and calculate the size which preserves the image ratio, but does not exceed the available size - size.Width = availableRatio > imageRatio ? imageSize.Width * availableHeight / imageSize.Height : availableWidth; - size.Height = availableRatio > imageRatio ? availableHeight : imageSize.Height * availableWidth / imageSize.Width; - } - - return size; - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/Keyboard.cs b/src/Compatibility/Core/src/Tizen/Native/Keyboard.cs deleted file mode 100644 index 4c502c943f57..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Keyboard.cs +++ /dev/null @@ -1,89 +0,0 @@ -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Keyboard layout type on entry control. - /// - public enum Keyboard - { - /// - /// Disable Keyboard - /// - None = -1, - - /// - /// Keyboard layout type default. - /// - Normal, - - /// - /// Keyboard layout type number. - /// - Number, - - /// - /// Keyboard layout type email. - /// - Email, - - /// - /// Keyboard layout type url. - /// - Url, - - /// - /// Keyboard layout type phone. - /// - PhoneNumber, - - /// - /// Keyboard layout type ip. - /// - Ip, - - /// - /// Keyboard layout type month. - /// - Month, - - /// - /// Keyboard layout type number. - /// - NumberOnly, - - /// - /// Keyboard layout type error type. Do not use it directly! - /// - Invalid, - - /// - /// Keyboard layout type hexadecimal. - /// - Hex, - - /// - /// Keyboard layout type terminal type, esc, alt, ctrl, etc. - /// - Terminal, - - /// - /// Keyboard layout type password. - /// - Password, - - /// - /// Keyboard layout type date and time. - /// - DateTime, - - /// - /// Keyboard layout type emoticons. - /// - Emoticon, - - /// - /// Keyboard layout type numeric. - /// - Numeric = Emoticon + 2017, - } -} - diff --git a/src/Compatibility/Core/src/Tizen/Native/Label.cs b/src/Compatibility/Core/src/Tizen/Native/Label.cs deleted file mode 100644 index b18c7b8d2c4a..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Label.cs +++ /dev/null @@ -1,419 +0,0 @@ -using System; -using ElmSharp; -using EColor = ElmSharp.Color; -using ELabel = ElmSharp.Label; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// The Label class extends ElmSharp.Label to be better suited for Xamarin renderers. - /// Mainly the formatted text support. - /// - public class Label : ELabel, ITextable, IMeasurable, IBatchable - { - /// - /// The _span holds the content of the label. - /// - readonly Span _span = new Span(); - - /// - /// Initializes a new instance of the class. - /// - /// Parent evas object. - public Label(EvasObject parent) : base(parent) - { - } - - /// - /// Get or sets the formatted text. - /// - /// Setting FormattedText changes the value of the Text property. - /// The formatted text. - public FormattedString FormattedText - { - get - { - return _span.FormattedText; - } - - set - { - if (value != _span.FormattedText) - { - _span.FormattedText = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the text. - /// - /// Setting Text overwrites the value of the FormattedText property too. - /// The content of the label. - public override string Text - { - get - { - return _span.Text; - } - - set - { - if (value != _span.Text) - { - _span.Text = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the color of the formatted text. - /// - /// The color of the text. - public EColor TextColor - { - get - { - return _span.ForegroundColor; - } - - set - { - if (!_span.ForegroundColor.Equals(value)) - { - _span.ForegroundColor = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the background color for the text. - /// - /// The color of the label's background. - public EColor TextBackgroundColor - { - get - { - return _span.BackgroundColor; - } - - set - { - if (!_span.BackgroundColor.Equals(value)) - { - _span.BackgroundColor = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the font family for the text. - /// - /// The font family. - public string FontFamily - { - get - { - return _span.FontFamily; - } - - set - { - if (value != _span.FontFamily) - { - _span.FontFamily = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the font attributes. - /// - /// The font attributes. - public FontAttributes FontAttributes - { - get - { - return _span.FontAttributes; - } - - set - { - if (value != _span.FontAttributes) - { - _span.FontAttributes = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the font size for the text. - /// - /// The size of the font. - public double FontSize - { - get - { - return _span.FontSize; - } - - set - { - if (value != _span.FontSize) - { - _span.FontSize = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the line height. - /// - public double LineHeight - { - get - { - return _span.LineHeight; - } - set - { - if (value != _span.LineHeight) - { - _span.LineHeight = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the font weight for the text. - /// - /// The weight of the font. - public string FontWeight - { - get - { - return _span.FontWeight; - } - - set - { - if (value != _span.FontWeight) - { - _span.FontWeight = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the line wrap option. - /// - /// The line break mode. - public LineBreakMode LineBreakMode - { - get - { - return _span.LineBreakMode; - } - - set - { - if (value != _span.LineBreakMode) - { - _span.LineBreakMode = value; - switch (value) - { - case LineBreakMode.NoWrap: - LineWrapType = WrapType.None; - IsEllipsis = false; - break; - case LineBreakMode.CharacterWrap: - LineWrapType = WrapType.Char; - IsEllipsis = false; - break; - case LineBreakMode.WordWrap: - LineWrapType = WrapType.Word; - IsEllipsis = false; - break; - case LineBreakMode.MixedWrap: - LineWrapType = WrapType.Mixed; - IsEllipsis = false; - break; - default: - LineWrapType = WrapType.None; - IsEllipsis = true; - break; - } - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the horizontal text alignment. - /// - /// The horizontal text alignment. - public TextAlignment HorizontalTextAlignment - { - get - { - return _span.HorizontalTextAlignment; - } - - set - { - if (value != _span.HorizontalTextAlignment) - { - _span.HorizontalTextAlignment = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the vertical text alignment. - /// - /// The vertical text alignment. - public TextAlignment VerticalTextAlignment - { - // README: It only work on Tizen 4.0 - get - { - double valign = this.GetVerticalTextAlignment(); - if (valign == 0.0) - { - return TextAlignment.Start; - } - else if (valign == 0.5) - { - return TextAlignment.Center; - } - else if (valign == 1.0) - { - return TextAlignment.End; - } - else - { - return TextAlignment.Auto; - } - } - set - { - double valign = 0; - switch (value) - { - case TextAlignment.Auto: - valign = -1; - break; - case TextAlignment.None: - case TextAlignment.Start: - valign = 0; - break; - case TextAlignment.Center: - valign = 0.5; - break; - case TextAlignment.End: - valign = 1.0; - break; - } - this.SetVerticalTextAlignment(valign); - } - } - - /// - /// Gets or sets the value that indicates whether the text is underlined. - /// - /// true if the text is underlined. - public bool Underline - { - get - { - return _span.Underline; - } - - set - { - if (value != _span.Underline) - { - _span.Underline = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Gets or sets the value that indicates whether the text is striked out. - /// - /// true if the text is striked out. - public bool Strikethrough - { - get - { - return _span.Strikethrough; - } - - set - { - if (value != _span.Strikethrough) - { - _span.Strikethrough = value; - ApplyTextAndStyle(); - } - } - } - - /// - /// Implements to provide a desired size of the label. - /// - /// Available width. - /// Available height. - /// Size of the control that fits the available area. - public ESize Measure(int availableWidth, int availableHeight) - { - var size = Geometry; - - Resize(availableWidth, size.Height); - - var formattedSize = this.GetTextBlockFormattedSize(); - Resize(size.Width, size.Height); - - // Set bottom padding for lower case letters that have segments below the bottom line of text (g, j, p, q, y). - var verticalPadding = (int)Math.Ceiling(0.05 * FontSize); - formattedSize.Height += verticalPadding; - - // This is the EFL team's guide. - // For wrap to work properly, the label must be 1 pixel larger than the size of the formatted text. - formattedSize.Width += 1; - - return formattedSize; - } - - void IBatchable.OnBatchCommitted() - { - ApplyTextAndStyle(); - } - - void ApplyTextAndStyle() - { - if (!this.IsBatched()) - { - SetInternalTextAndStyle(_span.GetDecoratedText(), _span.GetStyle()); - } - } - - void SetInternalTextAndStyle(string formattedText, string textStyle) - { - base.Text = formattedText; - TextStyle = textStyle; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/LayoutEventArgs.cs b/src/Compatibility/Core/src/Tizen/Native/LayoutEventArgs.cs deleted file mode 100644 index a88655190918..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/LayoutEventArgs.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using ERect = ElmSharp.Rect; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Holds information about size of the area which can be used for layout. - /// - public class LayoutEventArgs : EventArgs - { - /// - /// Geometry of the layout area, absolute coordinate - /// - public ERect Geometry - { - get; - internal set; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/LineBreakMode.cs b/src/Compatibility/Core/src/Tizen/Native/LineBreakMode.cs deleted file mode 100644 index 064344863d0d..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/LineBreakMode.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Enumerates values that describe options for line braking. - /// - public enum LineBreakMode - { - /// - /// Follow base LineBreakMode. - /// - None, - - /// - /// Do not wrap text. - /// - NoWrap, - - /// - /// Wrap at character boundaries. - /// - CharacterWrap, - - /// - /// Wrap at word boundaries. - /// - WordWrap, - - /// - /// Tries to wrap at word boundaries, and then wrap at a character boundary if the word is too long. - /// - MixedWrap, - - /// - /// Truncate the head of text. - /// - HeadTruncation, - - /// - /// Truncate the middle of text. This may be done, for example, by replacing it with an ellipsis. - /// - MiddleTruncation, - - /// - /// Truncate the tail of text. - /// - TailTruncation, - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/ListView.cs b/src/Compatibility/Core/src/Tizen/Native/ListView.cs deleted file mode 100644 index 2f373f5bc1f7..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/ListView.cs +++ /dev/null @@ -1,700 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using ElmSharp; -using Microsoft.Maui.Controls.Internals; -using EColor = ElmSharp.Color; -using ERect = ElmSharp.Rect; -using EScroller = ElmSharp.Scroller; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - // Type alias which identifies list of cells whose data model was transformed by Xamarin. - using GroupList = TemplatedItemsList, Cell>; - - /// - /// Native ListView implementation for Xamarin renderer - /// - /// - /// This internally uses GenList class. - /// One should note that it is optimized for displaying many elements which may be - /// unavailable at first. This means that only currently visible elements will be constructed. - /// Whenever element disappears from visible space its content is destroyed for time being. - /// This is carried out by so called Cell Handlers. - /// - [Obsolete] - public class ListView : GenList - { - /// - /// ItemContext helper class. This represents the association between Microsoft.Maui.Controls.Compatibility.Cell and - /// native elements. It also stores useful context for them. - /// - public class ItemContext - { - public ItemContext() - { - Item = null; - Cell = null; - Renderer = null; - ListOfSubItems = null; - } - - public GenItem Item; - public Cell Cell; - public bool IsGroupItem; - public CellRenderer Renderer; - internal TemplatedItemsList, Cell> ListOfSubItems; - } - - public class HeaderFooterItemContext : ItemContext - { - public VisualElement Element; - } - - class ScrollerExtension : EScroller - { - public ScrollerExtension(GenList scrollableLayout) : base(scrollableLayout) - { - } - - protected override IntPtr CreateHandle(EvasObject parent) - { - return parent.RealHandle; - } - } - - /// - /// The item context list for each added element. - /// - readonly List _itemContextList = new List(); - - /// - /// Registered cell handlers. - /// - protected readonly IDictionary _cellRendererCache = new Dictionary(); - - /// - /// Registered group handlers. - /// - protected readonly IDictionary _groupCellRendererCache = new Dictionary(); - - /// - /// The header element. - /// - VisualElement _headerElement; - - - /// - /// The footer element. - /// - VisualElement _footerElement; - - /// - /// The item class for header and footer. - /// - GenItemClass _headerFooterItemClass = null; - - /// - /// The object to handle scroller properties. - /// - protected virtual EScroller Scroller { get; set; } - - protected HeaderFooterItemContext HeaderItemContext { get; set; } - - protected HeaderFooterItemContext FooterItemContext { get; set; } - - /// - /// Gets or sets a value indicating whether this instance has grouping enabled. - /// - /// true if this instance has grouping enabled. - public bool IsGroupingEnabled { get; set; } - - /// - /// Gets the current region in the content object that is visible through the Scroller. - /// - public virtual ERect CurrentRegion => Scroller?.CurrentRegion ?? new ERect(); - - /// - /// Sets or gets the value of VerticalScrollBarVisibility - /// - public virtual ScrollBarVisiblePolicy VerticalScrollBarVisibility - { - get - { - return Scroller?.VerticalScrollBarVisiblePolicy ?? ScrollBarVisiblePolicy.Auto; - } - set - { - if (Scroller != null) - Scroller.VerticalScrollBarVisiblePolicy = value; - } - } - - /// - /// Sets or gets the value of HorizontalScrollBarVisibility - /// - public virtual ScrollBarVisiblePolicy HorizontalScrollBarVisibility - { - get - { - return Scroller?.HorizontalScrollBarVisiblePolicy ?? ScrollBarVisiblePolicy.Auto; - } - set - { - if (Scroller != null) - Scroller.HorizontalScrollBarVisiblePolicy = value; - } - } - - public EColor BottomLineColor { get; set; } - - /// - /// Occurs when the ListView has scrolled. - /// - public event EventHandler Scrolled; - - /// - /// Constructor of ListView native control. - /// - /// ElmSharp object which is parent of particular list view - public ListView(EvasObject parent) - : base(parent) - { - Scroller = new ScrollerExtension(this); - Scroller.Scrolled += OnScrolled; - } - - protected ListView() - { - } - - /// - /// Gets the item context based on Cell item. - /// - /// The item context. - /// Cell for which context should be found. - internal ItemContext GetItemContext(Cell cell) - { - if (cell == null) - { - return null; - } - else - { - return _itemContextList.Find(X => X.Cell == cell); - } - } - - /// - /// Sets the HasUnevenRows property. - /// - /// If true, the list will allow uneven sizes for its rows. - public void SetHasUnevenRows(bool hasUnevenRows) - { - Homogeneous = !hasUnevenRows; - UpdateRealizedItems(); - } - - /// - /// Adds elements to the list and defines its presentation based on Cell type. - /// - /// IEnumerable on Cell collection. - /// Cell before which new items will be placed. - /// Null value may also be passed as this parameter, which results in appending new items to the end. - /// - public virtual void AddSource(IEnumerable source, Cell beforeCell = null) - { - foreach (var data in source) - { - GroupList groupList = data as GroupList; - if (groupList != null) - { - AddGroupItem(groupList, beforeCell); - foreach (var item in groupList) - { - AddItem(item, groupList.HeaderContent); - } - } - else - { - AddItem(data as Cell, null, beforeCell); - } - } - } - - /// - /// Deletes all items from a given group. - /// - /// Group of items to be deleted. - internal void ResetGroup(GroupList group) - { - var items = _itemContextList.FindAll(x => x.ListOfSubItems == group && x.Cell != group.HeaderContent); - foreach (var item in items) - { - item.Item?.Delete(); - } - } - - /// - /// Adds items to the group. - /// - /// Group to which elements will be added. - /// New list items to be added. - /// A reference to the Cell already existing in a ListView. - /// Newly added cells will be put just before this cell. - public void AddItemsToGroup(IEnumerable itemGroup, IEnumerable newItems, Cell cellBefore = null) - { - ItemContext groupCtx = GetItemContext((itemGroup as GroupList)?.HeaderContent); - if (groupCtx != null) - { - foreach (var item in newItems) - { - AddItem(item as Cell, groupCtx.Cell, cellBefore); - } - } - } - - /// - /// Removes the specified cells. - /// - /// Cells to be removed. - public void Remove(IEnumerable cells) - { - foreach (var data in cells) - { - var group = data as GroupList; - if (group != null) - { - ItemContext groupCtx = GetItemContext(group.HeaderContent); - Remove(groupCtx.ListOfSubItems); - groupCtx.Item.Delete(); - } - else - { - ItemContext itemCtx = GetItemContext(data as Cell); - itemCtx?.Item?.Delete(); - } - } - } - - /// - /// Scrolls the list to a specified cell. - /// - /// - /// Different scrolling behaviors are also possible. The element may be positioned in the center, - /// top or bottom of the visible part of the list depending on the value of the position parameter. - /// - /// Cell which will be displayed after scrolling . - /// This will defines scroll to behavior based on ScrollToPosition values. - /// If true, scrolling will be animated. Otherwise the cell will be moved instantaneously. - public void ApplyScrollTo(Cell cell, ScrollToPosition position, bool animated) - { - GenListItem item = GetItemContext(cell)?.Item as GenListItem; - if (item != null) - this.ScrollTo(item, position.ToNative(), animated); - } - - /// - /// Selects the specified cell. - /// - /// Cell to be selected. - public void ApplySelectedItem(Cell cell) - { - GenListItem item = GetItemContext(cell)?.Item as GenListItem; - if (item != null) - item.IsSelected = true; - } - - /// - /// Sets the header. - /// - /// Header of the list. - public virtual void SetHeader(VisualElement header) - { - _headerElement = header; - UpdateHeader(); - } - - protected virtual void UpdateHeader() - { - if (GetHeader() == null) - { - if (HasHeaderContext()) - { - RemoveHeaderItemContext(); - } - return; - } - - var headerTemplate = GetHeaderFooterItemClass(); - if (!HasHeaderContext()) - { - InitializeHeaderItemContext(headerTemplate); - } - else - { - HeaderItemContext.Element = GetHeader(); - (HeaderItemContext.Item as GenListItem).UpdateItemClass(headerTemplate, HeaderItemContext); - } - } - - protected void InitializeHeaderItemContext(GenItemClass headerTemplate) - { - var context = new HeaderFooterItemContext(); - context.Element = GetHeader(); - if (FirstItem != null) - { - context.Item = InsertBefore(headerTemplate, context, FirstItem); - } - else - { - context.Item = Append(headerTemplate, context); - } - context.Item.SelectionMode = GenItemSelectionMode.None; - context.Item.Deleted += OnHeaderItemDeleted; - HeaderItemContext = context; - } - - void OnHeaderItemDeleted(object sender, EventArgs e) - { - HeaderItemContext = null; - } - - /// - /// Sets the footer. - /// - /// Footer of the list. - public virtual void SetFooter(VisualElement footer) - { - _footerElement = footer; - UpdateFooter(); - } - - protected virtual void UpdateFooter() - { - if (GetFooter() == null) - { - if (HasFooterContext()) - { - RemoveFooterItemContext(); - } - return; - } - - var footerTemplate = GetHeaderFooterItemClass(); - if (!HasFooterContext()) - { - InitializeFooterItemContext(footerTemplate); - } - else - { - FooterItemContext.Element = GetFooter(); - (HeaderItemContext.Item as GenListItem).UpdateItemClass(footerTemplate, HeaderItemContext); - } - } - - protected void InitializeFooterItemContext(GenItemClass footerTemplate) - { - var context = new HeaderFooterItemContext(); - context.Element = GetFooter(); - context.Item = Append(footerTemplate, context); - context.Item.SelectionMode = GenItemSelectionMode.None; - context.Item.Deleted += OnFooterItemDeleted; - FooterItemContext = context; - } - - void OnFooterItemDeleted(object sender, EventArgs e) - { - FooterItemContext = null; - } - - protected void RemoveHeaderItemContext() - { - HeaderItemContext?.Item?.Delete(); - HeaderItemContext = null; - } - - protected void RemoveFooterItemContext() - { - FooterItemContext?.Item?.Delete(); - FooterItemContext = null; - } - - public bool HasHeaderContext() - { - return HeaderItemContext != null; - } - - public bool HasFooterContext() - { - return FooterItemContext != null; - } - - /// - /// Gets the header. - /// - /// The header. - public VisualElement GetHeader() - { - return _headerElement; - } - - /// - /// Gets the footer. - /// - /// The footer. - public VisualElement GetFooter() - { - return _footerElement; - } - - protected virtual void OnScrolled(object sender, EventArgs e) - { - Scrolled?.Invoke(this, EventArgs.Empty); - } - - /// - /// Called every time an object gets realized. - /// - /// Sender of the event. - /// GenListItemEventArgs. - void OnItemAppear(object sender, GenListItemEventArgs evt) - { - ItemContext itemContext = (evt.Item.Data as ItemContext); - - if (itemContext != null && itemContext.Cell != null) - { - itemContext.Cell.SendSignalToItem(evt.Item); - if (BottomLineColor.IsDefault) - { - evt.Item.DeleteBottomlineColor(); - } - else - { - evt.Item.SetBottomlineColor(BottomLineColor); - } - (itemContext.Cell as ICellController).SendAppearing(); - } - } - - /// - /// Called every time an object gets unrealized. - /// - /// Sender of the event. - /// GenListItemEventArgs. - void OnItemDisappear(object sender, GenListItemEventArgs evt) - { - ItemContext itemContext = (evt.Item.Data as ItemContext); - if (itemContext != null && itemContext.Cell != null) - { - (itemContext.Cell as ICellController).SendDisappearing(); - itemContext.Renderer?.SendUnrealizedCell(itemContext.Cell); - } - } - - protected override void OnRealized() - { - base.OnRealized(); - ItemRealized += OnItemAppear; - ItemUnrealized += OnItemDisappear; - } - - /// - /// A convenience shorthand method for derivate classes. - /// - /// Cell to be added. - protected void AddCell(Cell cell) - { - AddItem(cell); - } - - /// - /// Gets the cell renderer for given cell type. - /// - /// The cell handler. - /// Cell to be added. - /// If true, then group handlers will be included in the lookup as well. - protected virtual CellRenderer GetCellRenderer(Cell cell, bool isGroup = false) - { - Type type = cell.GetType(); - var cache = isGroup ? _groupCellRendererCache : _cellRendererCache; - if (cache.ContainsKey(type)) - { - var cacheCellRenderer = cache[type]; - cacheCellRenderer.SendCreatedCell(cell, isGroup); - return cacheCellRenderer; - } - - CellRenderer renderer = null; - renderer = Forms.GetHandler(type); - - if (renderer == null) - { - Log.Error("Cell type is not handled: {0}", cell.GetType()); - throw new ArgumentException("Unsupported cell type"); - } - - renderer.SetGroupMode(isGroup); - renderer.SendCreatedCell(cell, isGroup); - return cache[type] = renderer; - } - - /// - /// Adds the group item. Group item is actually of class GroupList because - /// group item has sub items (can be zero) which needs to be added. - /// If beforeCell is not null, new group will be added just before it. - /// - /// Group to be added. - /// Before cell. - void AddGroupItem(GroupList groupList, Cell beforeCell = null) - { - Cell groupCell = groupList.HeaderContent; - CellRenderer groupRenderer = GetCellRenderer(groupCell, true); - - ItemContext groupItemContext = new ItemContext(); - groupItemContext.Cell = groupCell; - groupItemContext.Renderer = groupRenderer; - groupItemContext.IsGroupItem = true; - groupItemContext.ListOfSubItems = groupList; - _itemContextList.Add(groupItemContext); - - if (beforeCell != null) - { - GenListItem beforeItem = GetItemContext(beforeCell)?.Item as GenListItem; - groupItemContext.Item = InsertBefore(groupRenderer.Class, groupItemContext, beforeItem, GenListItemType.Group); - } - else - { - groupItemContext.Item = Append(groupRenderer.Class, groupItemContext, GenListItemType.Group); - } - - groupItemContext.Item.SelectionMode = GenItemSelectionMode.None; - groupItemContext.Item.IsEnabled = groupCell.IsEnabled; - groupItemContext.Item.Deleted += ItemDeletedHandler; - - } - - /// - /// Adds the item. - /// - /// Cell to be added. - /// Group to which the new item should belong. - /// If the value of groupCell is not null, the new item will be put into the requested group. - /// The cell before which the new item should be placed. - /// If the value of beforeCell is not null, the new item will be placed just before the requested cell. - void AddItem(Cell cell, Cell groupCell = null, Cell beforeCell = null) - { - CellRenderer renderer = GetCellRenderer(cell); - GenListItem parentItem = null; - - ItemContext itemContext = new ItemContext(); - itemContext.Cell = cell; - itemContext.Renderer = renderer; - _itemContextList.Add(itemContext); - - if (IsGroupingEnabled && groupCell != null) - { - var groupContext = GetItemContext(groupCell); - itemContext.ListOfSubItems = groupContext.ListOfSubItems; - parentItem = groupContext.Item as GenListItem; - } - - if (beforeCell != null) - { - GenListItem beforeItem = GetItemContext(beforeCell)?.Item as GenListItem; - itemContext.Item = InsertBefore(renderer.Class, itemContext, beforeItem, GenListItemType.Normal, parentItem); - } - else if (HasFooterContext()) - { - itemContext.Item = InsertBefore(renderer.Class, itemContext, FooterItemContext.Item as GenListItem, GenListItemType.Normal, parentItem); - } - else - { - itemContext.Item = Append(renderer.Class, itemContext, GenListItemType.Normal, parentItem); - } - - itemContext.Item.SelectionMode = GenItemSelectionMode.Always; - itemContext.Item.IsEnabled = cell.IsEnabled; - itemContext.Item.Deleted += ItemDeletedHandler; - - cell.PropertyChanged += OnCellPropertyChanged; - (cell as ICellController).ForceUpdateSizeRequested += OnForceUpdateSizeRequested; - } - - /// - /// Handles item deleted event. - /// - /// Sender of the event. - /// Empty argument. - void ItemDeletedHandler(object sender, EventArgs e) - { - ItemContext itemContext = (sender as GenListItem).Data as ItemContext; - if (itemContext.Cell != null) - { - itemContext.Cell.PropertyChanged -= OnCellPropertyChanged; - (itemContext.Cell as ICellController).ForceUpdateSizeRequested -= OnForceUpdateSizeRequested; - } - _itemContextList.Remove(itemContext); - } - - /// - /// Invoked whenever the properties of data model change. - /// - /// Sender of the event. - /// PropertyChangedEventArgs. - /// - /// The purpose of this method is to propagate these changes to the presentation layer. - /// - void OnCellPropertyChanged(object sender, PropertyChangedEventArgs e) - { - var cell = sender as Cell; - var context = GetItemContext(cell); - context.Renderer.SendCellPropertyChanged(cell, context.Item, e.PropertyName); - } - - void OnForceUpdateSizeRequested(object sender, EventArgs e) - { - var cell = sender as Cell; - var itemContext = GetItemContext(cell); - if (itemContext.Item != null) - itemContext.Item.Update(); - } - - /// - /// Gets the item class used for header and footer cells. - /// - /// The header and footer item class. - protected GenItemClass GetHeaderFooterItemClass() - { - if (_headerFooterItemClass == null) - { - _headerFooterItemClass = new GenItemClass(ThemeConstants.GenItemClass.Styles.Full) - { - GetContentHandler = (data, part) => - { - var context = data as HeaderFooterItemContext; - if (context == null || context.Element == null) - return null; - - var renderer = Platform.GetOrCreateRenderer(context.Element); - if (context.Element.MinimumHeightRequest == -1) - { - SizeRequest request = context.Element.Measure(double.PositiveInfinity, double.PositiveInfinity); - renderer.NativeView.MinimumHeight = Forms.ConvertToScaledPixel(request.Request.Height); - } - else - { - renderer.NativeView.MinimumHeight = Forms.ConvertToScaledPixel(context.Element.MinimumHeightRequest); - } - - (renderer as ILayoutRenderer)?.RegisterOnLayoutUpdated(); - - return renderer.NativeView; - } - }; - } - return _headerFooterItemClass; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/ObservableCollection.cs b/src/Compatibility/Core/src/Tizen/Native/ObservableCollection.cs deleted file mode 100644 index 958e898f4e9b..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/ObservableCollection.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Specialized; -using System.Linq; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. - /// - /// The type of elements in the collection. - internal class ObservableCollection : System.Collections.ObjectModel.ObservableCollection - { - /// - /// Removes all items from the collection. - /// - /// - /// Fisrt remove all items, send CollectionChanged event with Remove Action - /// Second call ClearItems of base - /// - protected override void ClearItems() - { - var oldItems = Items.ToList(); - Items.Clear(); - using (BlockReentrancy()) - { - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItems)); - } - base.ClearItems(); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Page.cs b/src/Compatibility/Core/src/Tizen/Native/Page.cs deleted file mode 100644 index b5dbed747eda..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Page.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// A basic page which can hold a single view. - /// - public class Page : Background, IContainable - { - /// - /// The name of the part to be used when setting content. - /// - [Obsolete("ContentPartName is obsolete. Please use the ThemeConstants.Background.Parts.Overlay instead.")] - public const string ContentPartName = ThemeConstants.Background.Parts.Overlay; - - /// - /// Exposes the Children property, mapping it to the _canvas' Children property. - /// - public new IList Children => Forms.UseFastLayout ? EvasFormsCanvas?.Children : Canvas?.Children; - - /// - /// The canvas, used as a container for other objects. - /// - /// - /// The canvas holds all the Views that the ContentPage is composed of. - /// - internal Container _canvas; - - EvasFormsCanvas EvasFormsCanvas => _canvas as EvasFormsCanvas; - - Canvas Canvas => _canvas as Canvas; - - /// - /// Initializes a new instance of the ContentPage class. - /// - public Page(EvasObject parent) : base(parent) - { - if (Forms.UseFastLayout) - _canvas = new EvasFormsCanvas(this); - else - _canvas = new Canvas(this); - this.SetOverlayPart(_canvas); - } - - /// - /// Allows custom handling of events emitted when the layout has been updated. - /// - public event EventHandler LayoutUpdated - { - add - { - if (Forms.UseFastLayout) - EvasFormsCanvas.LayoutUpdated += value; - else - Canvas.LayoutUpdated += value; - - } - remove - { - if (Forms.UseFastLayout) - EvasFormsCanvas.LayoutUpdated -= value; - else - Canvas.LayoutUpdated -= value; - } - } - - /// - /// Handles the disposing of a ContentPage - /// - /// - /// Takes the proper care of discarding the canvas, then calls the base method. - /// - protected override void OnUnrealize() - { - _canvas.Unrealize(); - base.OnUnrealize(); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/RoundRectangle.cs b/src/Compatibility/Core/src/Tizen/Native/RoundRectangle.cs deleted file mode 100644 index ee8a65389b86..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/RoundRectangle.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Collections.Generic; -using ElmSharp; -using EPolygon = ElmSharp.Polygon; -using ERect = ElmSharp.Rect; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class RoundRectangle : EPolygon - { - readonly int[] _radius = new int[4]; - public RoundRectangle(EvasObject parent) : base(parent) - { - } - - public int X { get; set; } - public int Y { get; set; } - - public int Width { get; set; } - public int Height { get; set; } - - public void SetRadius(int r) - { - SetRadius(r, r, r, r); - } - - public void SetRadius(int topLeft, int topRight, int bottomLeft, int bottomRight) - { - _radius[0] = topLeft; - _radius[1] = topRight; - _radius[2] = bottomLeft; - _radius[3] = bottomRight; - } - - public IReadOnlyList GetRadius() - { - return _radius; - } - - public void Draw() - { - DrawPoints(); - } - - public void Draw(ERect bound) - { - X = bound.X; - Y = bound.Y; - Width = bound.Width; - Height = bound.Height; - Draw(); - // It is workaround for fix geometry issue - // A polygon make a margin of 1 pixel at the outermost point - Geometry = bound; - } - - - protected virtual void DrawPoints() - { - int[] radius = new int[4]; - int maxR = Math.Min(Width / 2, Height / 2); - radius[0] = Math.Min(_radius[0], maxR); - radius[1] = Math.Min(_radius[1], maxR); - radius[2] = Math.Min(_radius[2], maxR); - radius[3] = Math.Min(_radius[3], maxR); - - ClearPoints(); - for (int i = 0; i <= radius[0]; i++) - { - int x = i; - int dx = radius[0] - x; - int y = radius[0] - (int)Math.Sqrt((radius[0] * radius[0]) - (dx * dx)); - AddRelativePoint(x, y); - } - - AddRelativePoint(Width - radius[1], 0); - - for (int i = Width - radius[1]; i <= Width; i++) - { - int x = i; - int dx = radius[1] - (Width - x); - int y = radius[1] - (int)Math.Sqrt((radius[1] * radius[1]) - (dx * dx)); - AddRelativePoint(x, y); - } - - AddRelativePoint(Width, Height - radius[3]); - - for (int i = Width; i >= Width - radius[3]; i--) - { - int x = i; - int dx = radius[3] - (Width - x); - int y = Height - radius[3] + (int)Math.Sqrt((radius[3] * radius[3]) - (dx * dx)); - AddRelativePoint(x, y); - } - - AddRelativePoint(radius[2], Height); - - for (int i = radius[2]; i >= 0; i--) - { - int x = i; - int dx = radius[2] - x; - int y = Height - radius[2] + (int)Math.Sqrt((radius[2] * radius[2]) - (dx * dx)); - AddRelativePoint(x, y); - } - } - - protected void AddRelativePoint(int x, int y) - { - AddPoint(X + x, Y + y); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Scroller.cs b/src/Compatibility/Core/src/Tizen/Native/Scroller.cs deleted file mode 100644 index 4bf9079b9eeb..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Scroller.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Threading.Tasks; -using ElmSharp; -using ERect = ElmSharp.Rect; -using EScroller = ElmSharp.Scroller; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class Scroller : EScroller - { - TaskCompletionSource _animationTaskComplateSource; - bool _isAnimation = false; - - public Scroller(EvasObject parent) : base(parent) - { - } - - protected Scroller() - { - } - - protected override void OnRealized() - { - base.OnRealized(); - new SmartEvent(this, RealHandle, ThemeConstants.Scroller.Signals.StartScrollAnimation).On += (s, e) => _isAnimation = true; - new SmartEvent(this, RealHandle, ThemeConstants.Scroller.Signals.StopScrollAnimation).On += (s, e) => - { - if (_animationTaskComplateSource != null) - { - _animationTaskComplateSource.TrySetResult(true); - } - _isAnimation = false; - }; - } - - void CheckTaskCompletionSource() - { - if (_animationTaskComplateSource != null) - { - if (_animationTaskComplateSource.Task.Status == TaskStatus.Running) - { - _animationTaskComplateSource.TrySetCanceled(); - } - } - _animationTaskComplateSource = new TaskCompletionSource(); - } - - public Task ScrollToAsync(int horizontalPageIndex, int verticalPageIndex, bool animated) - { - CheckTaskCompletionSource(); - ScrollTo(horizontalPageIndex, verticalPageIndex, animated); - return animated && _isAnimation ? _animationTaskComplateSource.Task : Task.CompletedTask; - } - - public Task ScrollToAsync(ERect rect, bool animated) - { - CheckTaskCompletionSource(); - ScrollTo(rect, animated); - return animated && _isAnimation ? _animationTaskComplateSource.Task : Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/SearchBar.cs b/src/Compatibility/Core/src/Tizen/Native/SearchBar.cs deleted file mode 100644 index c0259c563d5f..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/SearchBar.cs +++ /dev/null @@ -1,18 +0,0 @@ -using ElmSharp; -using EColor = ElmSharp.Color; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class SearchBar : Native.EditfieldEntry - { - public SearchBar(EvasObject parent) : base(parent) - { - EnableClearButton = true; - } - - public void SetClearButtonColor(EColor color) - { - ClearButtonColor = color; - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/Span.cs b/src/Compatibility/Core/src/Tizen/Native/Span.cs deleted file mode 100644 index 2b663171c96b..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Span.cs +++ /dev/null @@ -1,288 +0,0 @@ -using System; -using System.Text; -using EColor = ElmSharp.Color; -using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Represent a text with attributes applied. - /// - public class Span - { - string _text; - - /// - /// Gets or sets the formatted text. - /// - public FormattedString FormattedText { get; set; } - - /// - /// Gets or sets the text. - /// - /// - /// Setting Text to a non-null value will set the FormattedText property to null. - /// - public string Text - { - get - { - if (FormattedText != null) - { - return FormattedText.ToString(); - } - else - { - return _text; - } - } - set - { - if (value == null) - { - value = ""; - } - else - { - FormattedText = null; - } - _text = value; - } - } - - /// - /// Gets or sets the color for the text. - /// - public EColor ForegroundColor { get; set; } - - /// - /// Gets or sets the background color for the text. - /// - public EColor BackgroundColor { get; set; } - - /// - /// Gets or sets the font family for the text. - /// - public string FontFamily { get; set; } - - /// - /// Gets or sets the font attributes for the text. - /// See for information about FontAttributes. - /// - public FontAttributes FontAttributes { get; set; } - - /// - /// Gets or sets the font size for the text. - /// - public double FontSize { get; set; } - - /// - /// Gets or sets the font weight for the text. - /// - public string FontWeight { get; set; } - - /// - /// Gets or sets the line height. - /// - public double LineHeight { get; set; } - - /// - /// Gets or sets the line break mode for the text. - /// See for information about LineBreakMode. - /// - public LineBreakMode LineBreakMode { get; set; } - - /// - /// Gets or sets the horizontal alignment mode for the text. - /// See for information about TextAlignment. - /// - public TextAlignment HorizontalTextAlignment { get; set; } - - /// - /// Gets or sets the value that indicates whether the text has underline. - /// - public bool Underline { get; set; } - - /// - /// Gets or sets the value that indicates whether the text has strike line though it. - /// - public bool Strikethrough { get; set; } - - /// - /// Create a new Span instance with default attributes. - /// - public Span() - { - Text = ""; - FontFamily = ""; - FontSize = -1; - FontWeight = Specific.FontWeight.None; - FontAttributes = FontAttributes.None; - ForegroundColor = EColor.Default; - BackgroundColor = EColor.Default; - HorizontalTextAlignment = TextAlignment.None; - LineBreakMode = LineBreakMode.None; - Underline = false; - Strikethrough = false; - LineHeight = -1.0d; - } - - /// - /// This method return marked up text - /// - internal string GetMarkupText() - { - StringBuilder sb = new StringBuilder(); - sb.Append(""); - sb.Append(GetDecoratedText()); - sb.Append(""); - return sb.ToString(); - } - - /// - /// This method return text decorated with markup if FormattedText is set or plain text otherwise. - /// - public string GetDecoratedText() - { - if (FormattedText != null) - { - return FormattedText.ToMarkupString(); - } - else - { - return ConvertTags(Text); - } - } - - StringBuilder PrepareFormattingString(StringBuilder _formattingString) - { - if (!ForegroundColor.IsDefault) - { - _formattingString.AppendFormat("color={0} ", ForegroundColor.ToHex()); - } - - if (!BackgroundColor.IsDefault) - { - _formattingString.AppendFormat("backing_color={0} backing=on ", BackgroundColor.ToHex()); - } - - if (!string.IsNullOrEmpty(FontFamily)) - { - _formattingString.AppendFormat("font={0} ", FontFamily); - } - - if (FontSize != -1) - { - _formattingString.AppendFormat("font_size={0} ", Forms.ConvertToEflFontPoint(FontSize)); - } - - if ((FontAttributes & FontAttributes.Bold) != 0) - { - _formattingString.Append("font_weight=Bold "); - } - else - { - // FontWeight is only available in case of FontAttributes.Bold is not used. - if (FontWeight != Specific.FontWeight.None) - { - _formattingString.AppendFormat("font_weight={0} ", FontWeight); - } - } - - if ((FontAttributes & FontAttributes.Italic) != 0) - { - _formattingString.Append("font_style=italic "); - } - - if (Underline) - { - _formattingString.AppendFormat("underline=on underline_color={0} ", - ForegroundColor.IsDefault ? ThemeConstants.Span.ColorClass.DefaultUnderLineColor.ToHex() : ForegroundColor.ToHex()); - } - - if (Strikethrough) - { - _formattingString.AppendFormat("strikethrough=on strikethrough_color={0} ", - ForegroundColor.IsDefault ? ThemeConstants.Span.ColorClass.DefaultUnderLineColor.ToHex() : ForegroundColor.ToHex()); - } - - switch (HorizontalTextAlignment) - { - case TextAlignment.Auto: - _formattingString.Append("align=auto "); - break; - - case TextAlignment.Start: - _formattingString.Append("align=left "); - break; - - case TextAlignment.End: - _formattingString.Append("align=right "); - break; - - case TextAlignment.Center: - _formattingString.Append("align=center "); - break; - - case TextAlignment.None: - break; - } - - if (LineHeight != -1.0d) - { - _formattingString.Append($"linerelsize={(int)(LineHeight * 100)}%"); - } - - switch (LineBreakMode) - { - case LineBreakMode.HeadTruncation: - _formattingString.Append("ellipsis=0.0"); - break; - - case LineBreakMode.MiddleTruncation: - _formattingString.Append("ellipsis=0.5"); - break; - - case LineBreakMode.TailTruncation: - _formattingString.Append("ellipsis=1.0"); - break; - case LineBreakMode.None: - break; - } - - return _formattingString; - } - - string ConvertTags(string text) - { - return text.Replace("&", "&", StringComparison.Ordinal) - .Replace("<", "<", StringComparison.Ordinal) - .Replace(">", ">", StringComparison.Ordinal) - .Replace(Environment.NewLine, "
", StringComparison.Ordinal); - } - - public string GetStyle() - { - StringBuilder sb = new StringBuilder(); - - sb.Append("DEFAULT='"); - - PrepareFormattingString(sb); - - sb.Append("'"); - - return sb.ToString(); - } - - /// - /// Converts string value to Span. - /// - /// The string text - public static implicit operator Span(string text) - { - return new Span { Text = text }; - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/TableView.cs b/src/Compatibility/Core/src/Tizen/Native/TableView.cs deleted file mode 100644 index 3b9621bf0bbb..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/TableView.cs +++ /dev/null @@ -1,71 +0,0 @@ -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Extends the ListView class to provide TableView class implementation. - /// - [System.Obsolete] - public class TableView : ListView, ITableView - { - - static readonly SectionCellRenderer _sectionCellRenderer = new SectionCellRenderer(); - /// - /// Initializes a new instance of the TableView class. - /// - public TableView(EvasObject parent) - : base(parent) - { - } - - /// - /// Sets the root of the table. - /// - /// TableRoot, which is parent to one or more TableSections. - public void ApplyTableRoot(TableRoot root) - { - Clear(); - foreach (TableSection ts in root) - { - if (!string.IsNullOrEmpty(ts.Title)) - AddSectionTitle(ts.Title, ts.TextColor); - AddSource(ts); - } - } - - protected override CellRenderer GetCellRenderer(Cell cell, bool isGroup = false) - { - if (cell.GetType() == typeof(SectionCell)) - { - return _sectionCellRenderer; - } - return base.GetCellRenderer(cell, isGroup); - } - - /// - /// Sets the section title. - /// - void AddSectionTitle(string title, Graphics.Color textColor) - { - Cell cell = new SectionCell() - { - Text = title, - TextColor = textColor - }; - AddCell(cell); - } - - internal class SectionCellRenderer : TextCellRenderer - { - public SectionCellRenderer() : this(ThemeConstants.GenItemClass.Styles.GroupIndex) - { - } - - protected SectionCellRenderer(string style) : base(style) { } - } - class SectionCell : TextCell - { - } - } -} - diff --git a/src/Compatibility/Core/src/Tizen/Native/TextAlignment.cs b/src/Compatibility/Core/src/Tizen/Native/TextAlignment.cs deleted file mode 100644 index 8aec01734169..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/TextAlignment.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// Enumerates values that describe alignemnt of text. - /// - public enum TextAlignment - { - /// - /// Follow base TextAlignment - /// - None, - - /// - /// Aligns horizontal text according to language. Top aligned for vertical text. - /// - Auto, - /// - /// Left and top aligned for horizontal and vertical text, respectively. - /// - Start, - /// - /// Right and bottom aligned for horizontal and vertical text, respectively. - /// - End, - /// - /// Center-aligned text. - /// - Center, - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/TextHelper.cs b/src/Compatibility/Core/src/Tizen/Native/TextHelper.cs deleted file mode 100644 index 6093d8ea87d8..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/TextHelper.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using ElmSharp; -using ELayout = ElmSharp.Layout; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - /// - /// The Text Helper contains functions that assist in working with text-able objects. - /// - public static class TextHelper - { - /// - /// Gets the size of raw text block. - /// - /// The with text part. - /// Returns the size of raw text block. - public static ESize GetRawTextBlockSize(EvasObject textable) - { - return GetElmTextPart(textable)?.TextBlockNativeSize ?? new ESize(0, 0); - } - - /// - /// Gets the size of formatted text block. - /// - /// The with text part. - /// Returns the size of formatted text block. - public static ESize GetFormattedTextBlockSize(EvasObject textable) - { - return GetElmTextPart(textable)?.TextBlockFormattedSize ?? new ESize(0, 0); - } - - /// - /// Gets the ELM text part of evas object. - /// - /// The with text part. - /// Requested instance. - /// Throws exception when parameter isn't text-able object or doesn't have ELM text part. - static EdjeTextPartObject GetElmTextPart(EvasObject textable) - { - ELayout widget = textable as ELayout; - if (widget == null) - { - Log.Error("textable should be ElmSharp.Layout"); - } - EdjeTextPartObject textPart = widget?.EdjeObject[ThemeConstants.Common.Parts.Text]; - if (textPart == null) - { - Log.Error("There is no elm.text part"); - } - return textPart; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/TitleViewPage.cs b/src/Compatibility/Core/src/Tizen/Native/TitleViewPage.cs deleted file mode 100644 index 3697632d90e7..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/TitleViewPage.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - [Obsolete] - public class TitleViewPage : Native.Box - { - Native.Page _page = null; - View _titleView = null; - bool _hasNavigationBar = true; - - public TitleViewPage(EvasObject parent, Microsoft.Maui.Controls.Page page, View titleView) : base(parent) - { - _page = Platform.GetOrCreateRenderer(page).NativeView as Native.Page; - _titleView = titleView; - if (_titleView != null) - { - var renderer = Platform.GetOrCreateRenderer(_titleView); - (renderer as ILayoutRenderer)?.RegisterOnLayoutUpdated(); - - this.PackEnd(renderer.NativeView); - } - this.PackEnd(_page); - this.LayoutUpdated += OnLayoutUpdated; - } - - public bool HasNavigationBar - { - get - { - return _hasNavigationBar; - } - set - { - if (_hasNavigationBar != value) - { - _hasNavigationBar = value; - UpdatPageLayout(this, new LayoutEventArgs() { Geometry = this.Geometry }); - } - - } - } - - void OnLayoutUpdated(object sender, LayoutEventArgs e) - { - UpdatPageLayout(sender, e); - } - - void UpdatPageLayout(object sender, LayoutEventArgs e) - { - double dHeight = _titleView.Measure(Forms.ConvertToScaledDP(e.Geometry.Width), Forms.ConvertToScaledDP(e.Geometry.Height)).Request.Height; - int height = 0; - if (_hasNavigationBar) - { - height = Forms.ConvertToScaledPixel(dHeight); - } - - var renderer = Platform.GetOrCreateRenderer(_titleView); - renderer.NativeView.Move(e.Geometry.X, e.Geometry.Y); - renderer.NativeView.Resize(e.Geometry.Width, height); - - _page.Move(e.Geometry.X, e.Geometry.Y + height); - _page.Resize(e.Geometry.Width, e.Geometry.Height - height); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/ToolbarItemButton.cs b/src/Compatibility/Core/src/Tizen/Native/ToolbarItemButton.cs deleted file mode 100644 index fd82e45019f2..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/ToolbarItemButton.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; -using System.ComponentModel; -using ElmSharp.Accessible; -using EColor = ElmSharp.Color; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class ToolbarItemButton : Button - { - ToolbarItem _item; - string _defaultAccessibilityName; - string _defaultAccessibilityDescription; - bool? _defaultIsAccessibilityElement; - - public ToolbarItemButton(ToolbarItem item) : base(Forms.NativeParent) - { - _item = item; - BackgroundColor = EColor.Transparent; - - Clicked += OnClicked; - Deleted += OnDeleted; - _item.PropertyChanged += OnToolbarItemPropertyChanged; - - UpdateText(); - UpdateIsEnabled(); - UpdateIcon(); - SetAccessibilityName(true); - SetAccessibilityDescription(true); - SetIsAccessibilityElement(true); - SetLabeledBy(true); - } - - void OnDeleted(object sender, EventArgs e) - { - Clicked -= OnClicked; - Deleted -= OnDeleted; - _item.PropertyChanged -= OnToolbarItemPropertyChanged; - } - - void OnClicked(object sender, EventArgs e) - { - ((IMenuItemController)_item).Activate(); - } - - void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == ToolbarItem.TextProperty.PropertyName) - { - UpdateText(); - } - else if (e.PropertyName == ToolbarItem.IsEnabledProperty.PropertyName) - { - UpdateIsEnabled(); - } - else if (e.PropertyName == ToolbarItem.IconImageSourceProperty.PropertyName) - { - UpdateIcon(); - } - else if (e.PropertyName == AutomationProperties.NameProperty.PropertyName) - { - SetAccessibilityName(false); - } - else if (e.PropertyName == AutomationProperties.HelpTextProperty.PropertyName) - { - SetAccessibilityDescription(false); - } - else if (e.PropertyName == AutomationProperties.IsInAccessibleTreeProperty.PropertyName) - { - SetIsAccessibilityElement(false); - } - else if (e.PropertyName == AutomationProperties.LabeledByProperty.PropertyName) - { - SetLabeledBy(false); - } - } - - void UpdateText() - { - UpdateStyle(); - Text = _item.Text; - } - - void UpdateIsEnabled() - { - IsEnabled = _item.IsEnabled; - } - - void UpdateIcon() - { - if (_item.IconImageSource.IsNullOrEmpty()) - { - //On 5.0, the part content should be removed before the style is changed, otherwise, EFL does not remove the part content. - Image = null; - UpdateStyle(); - } - else - { - // In reverse, the style should be set before setting the part content. - UpdateStyle(); - Native.Image iconImage = new Native.Image(Forms.NativeParent); - _ = iconImage.LoadFromImageSourceAsync(_item.IconImageSource); - Image = iconImage; - } - } - - void UpdateStyle() - { - if (_item.IconImageSource.IsNullOrEmpty()) - { - if (string.IsNullOrEmpty(_item.Text)) - { - // We assumed the default toolbar icon is "naviframe/drawer" if there are no icon and text. - this.SetNavigationDrawerStyle(); - } - else - { - if (_item.Order == ToolbarItemOrder.Primary) - this.SetNavigationTitleRightStyle(); - else - this.SetNavigationTitleLeftStyle(); - } - } - else - { - this.SetDefaultStyle(); - } - } - - void SetAccessibilityName(bool initialize) - { - if (initialize && (string)_item.GetValue(AutomationProperties.NameProperty) == (default(string))) - return; - - var accessibleObject = this as IAccessibleObject; - if (accessibleObject != null) - { - _defaultAccessibilityName = accessibleObject.SetAccessibilityName(_item, _defaultAccessibilityName); - } - } - - void SetAccessibilityDescription(bool initialize) - { - if (initialize && (string)_item.GetValue(AutomationProperties.HelpTextProperty) == (default(string))) - return; - - var accessibleObject = this as IAccessibleObject; - if (accessibleObject != null) - { - _defaultAccessibilityDescription = accessibleObject.SetAccessibilityDescription(_item, _defaultAccessibilityDescription); - } - } - - void SetIsAccessibilityElement(bool initialize) - { - if (initialize && (bool?)_item.GetValue(AutomationProperties.IsInAccessibleTreeProperty) == default(bool?)) - return; - - var accessibleObject = this as IAccessibleObject; - if (accessibleObject != null) - { - _defaultIsAccessibilityElement = accessibleObject.SetIsAccessibilityElement(_item, _defaultIsAccessibilityElement); - } - } - - void SetLabeledBy(bool initialize) - { - if (initialize && (VisualElement)_item.GetValue(AutomationProperties.LabeledByProperty) == default(VisualElement)) - return; - - var accessibleObject = this as IAccessibleObject; - if (accessibleObject != null) - { - accessibleObject.SetLabeledBy(_item); - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/FormsMoreOptionItem.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/FormsMoreOptionItem.cs deleted file mode 100644 index 84a69fb5a665..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/FormsMoreOptionItem.cs +++ /dev/null @@ -1,9 +0,0 @@ -using ElmSharp.Wearable; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - public class FormsMoreOptionItem : MoreOptionItem - { - public ToolbarItem ToolbarItem { get; set; } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/FormsWatchLayout.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/FormsWatchLayout.cs deleted file mode 100644 index 9d2e9972cccc..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/FormsWatchLayout.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Microsoft.Maui.Devices; -using ElmSharp; -using EColor = ElmSharp.Color; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - public class FormsWatchLayout : FormsLayout - { - public FormsWatchLayout(EvasObject parent) : base(parent) - { - if (DeviceInfo.Idiom != DeviceIdiom.Watch) - Log.Error($"{0} is only supported on TargetIdiom.Watch : {1}", this, DeviceInfo.Idiom); - } - } - - public class DateTimeLayout : FormsWatchLayout - { - public class Styles - { - public const string Default = "datetime"; - } - - public class Parts - { - public const string ButtomButton = "elm.swallow.btn"; - } - - public DateTimeLayout(EvasObject parent, string style = Styles.Default) : base(parent) - { - SetTheme("layout", "circle", style); - } - - public bool SetBottomButtonPart(EvasObject content, bool preserveOldContent = false) - { - return SetPartContent(Parts.ButtomButton, content, preserveOldContent); - } - } - - public class PopupLayout : FormsWatchLayout - { - public class Parts - { - public const string Button1 = "button1"; - public const string Button2 = "button2"; - public const string Title = "elm.text.title"; - public const string Content = "elm.swallow.content"; - - public class Colors - { - public const string Title = "text_title"; - } - } - - public class Styles - { - public const string Circle = "content/circle"; - public const string Buttons2 = "content/circle/buttons2"; - } - - - public PopupLayout(EvasObject parent, string style) : base(parent) - { - SetTheme("layout", "popup", style); - } - - public bool SetTitleText(string title) - { - return SetPartText(Parts.Title, title); - } - - public void SetTitleColor(EColor color) - { - SetPartColor(Parts.Colors.Title, color); - } - } - - public class PopupClassBaseGroupLayout : FormsWatchLayout - { - public class Styles - { - public const string Circle = "circle"; - } - - public class Parts - { - public const string ActionArea = "elm.swallow.action_area"; - } - - public PopupClassBaseGroupLayout(EvasObject parent) : base(parent) - { - SetTheme("popup", "base", Styles.Circle); - } - } - - public class PopupClass2ButtonGroupLayout : FormsWatchLayout - { - public class Styles - { - public const string Circle = "popup/circle"; - } - - public class Parts - { - public const string Content = "elm.swallow.content"; - } - - public PopupClass2ButtonGroupLayout(EvasObject parent) : base(parent) - { - SetTheme("popup", "buttons2", Styles.Circle); - } - } - -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchButton.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchButton.cs deleted file mode 100644 index 6bde527a75fa..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchButton.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using ElmSharp; -using Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific; -using ESize = ElmSharp.Size; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - public class WatchButton : Button, IMeasurable - { - public WatchButton(EvasObject parent) : base(parent) - { - } - - public override ESize Measure(int availableWidth, int availableHeight) - { - if (Style == ButtonStyle.Default) - { - //Should gurantee the finger size (40) - MinimumWidth = MinimumWidth < 40 ? 40 : MinimumWidth; - if (Image != null) - MinimumWidth += Image.Geometry.Width; - var rawSize = this.GetTextBlockNativeSize(); - return new ESize(rawSize.Width + MinimumWidth, Math.Max(MinimumHeight, rawSize.Height)); - } - else - { - return new ESize(MinimumWidth, MinimumHeight); - } - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePicker.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePicker.cs deleted file mode 100644 index 40d5c2396dc7..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePicker.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using ElmSharp; -using ElmSharp.Wearable; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - public class WatchDateTimePicker : CircleDateTimeSelector, IRotaryInteraction - { - DateTimePickerMode _mode; - - public IRotaryActionWidget RotaryWidget => this; - - public WatchDateTimePicker(EvasObject parent, CircleSurface surface) : base(parent, surface) - { - UpdateMode(); - } - - public DateTimePickerMode Mode - { - get - { - return _mode; - } - set - { - if (_mode != value) - { - _mode = value; - UpdateMode(); - } - } - } - - protected virtual void UpdateMode() - { - if (_mode == DateTimePickerMode.Date) - { - Style = ThemeConstants.CircleDateTimeSelector.Styles.CircleDatePicker; - Format = "%d/%b/%Y"; - } - else - { - Style = ThemeConstants.CircleDateTimeSelector.Styles.CircleTimePicker; - Format = "%d/%b/%Y %I:%M %p"; - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePickerDialog.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePickerDialog.cs deleted file mode 100644 index 891b0a6129a4..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePickerDialog.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System; -using ElmSharp; -using ElmSharp.Wearable; -using EButton = ElmSharp.Button; -using ELayout = ElmSharp.Layout; -using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Application; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - public class WatchDateTimePickerDialog : Popup, IDateTimeDialog - { - ELayout _surfaceLayout; - DateTimeLayout _datetimeLayout; - CircleSurface _surface; - EButton _doneButton; - Box _container; - string _title; - WatchDateTimePicker _picker; - - public WatchDateTimePickerDialog(EvasObject parent) : base(parent) - { - this.SetWatchCircleStyle(); - AlignmentX = -1; - AlignmentY = -1; - WeightX = 1.0; - WeightY = 1.0; - - _container = new Box(parent) { AlignmentX = -1, AlignmentY = -1, WeightX = 1, WeightY = 1 }; - _container.BackgroundColor = ElmSharp.Color.Blue; - _container.SetLayoutCallback(OnContainerLayout); - - _datetimeLayout = new DateTimeLayout(parent); - _surfaceLayout = new ELayout(parent); - - _container.PackEnd(_datetimeLayout); - _container.PackEnd(_surfaceLayout); - - _surface = new CircleSurface(_surfaceLayout); - - _picker = new WatchDateTimePicker(parent, _surface); - _picker.Show(); - _datetimeLayout.SetContent(_picker); - - _doneButton = new Button(parent) - { - Text = "Set", - }; - _doneButton.SetBottomStyle(); - _datetimeLayout.SetBottomButtonPart(_doneButton); - _doneButton.Clicked += OnDoneClicked; - - ActivateRotaryInteraction(); - - _datetimeLayout.Show(); - _surfaceLayout.Show(); - _container.Show(); - - SetContent(_container); - ShowAnimationFinished += OnShowAnimationFinished; - BackButtonPressed += OnBackButtonPressed; - } - - public string Title - { - get => _title; - set - { - _title = value; - _datetimeLayout.SetTextPart(_title); - } - } - - public DateTimePickerMode Mode - { - get => _picker.Mode; - set => _picker.Mode = value; - } - - public DateTime MaximumDateTime - { - get => _picker.MaximumDateTime; - set => _picker.MaximumDateTime = value; - } - - public DateTime MinimumDateTime - { - get => _picker.MinimumDateTime; - set => _picker.MinimumDateTime = value; - } - - public DateTime DateTime - { - get => _picker.DateTime; - set => _picker.DateTime = value; - } - - public event EventHandler DateTimeChanged; - public event EventHandler PickerOpened; - public event EventHandler PickerClosed; - - protected virtual void ActivateRotaryInteraction() - { - if (_picker is IRotaryInteraction ri) - { - if (Specific.GetUseBezelInteraction(Application.Current)) - { - ri.RotaryWidget.Activate(); - } - } - } - - void OnContainerLayout() - { - _surfaceLayout.Geometry = _container.Geometry; - _datetimeLayout.Geometry = _container.Geometry; - } - - void OnDoneClicked(object sender, EventArgs e) - { - DateTimeChanged?.Invoke(this, new DateChangedEventArgs(_picker.DateTime)); - Hide(); - PickerClosed?.Invoke(this, EventArgs.Empty); - } - - void OnBackButtonPressed(object sender, EventArgs e) - { - Hide(); - PickerClosed?.Invoke(this, EventArgs.Empty); - } - - void OnShowAnimationFinished(object sender, EventArgs e) - { - PickerOpened?.Invoke(this, EventArgs.Empty); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDialog.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDialog.cs deleted file mode 100644 index d839aa023ee8..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDialog.cs +++ /dev/null @@ -1,86 +0,0 @@ -using ElmSharp; -using EButton = ElmSharp.Button; -using EColor = ElmSharp.Color; -using ELayout = ElmSharp.Layout; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - public class WatchDialog : Dialog - { - ELayout _popupLayout; - bool _hasAcceptButton = false; - - /// - /// Creates a dialog window for watch - /// - public WatchDialog(EvasObject parent, bool hasAcceptButton) : base(parent) - { - this.SetWatchCircleStyle(); - _hasAcceptButton = hasAcceptButton; - _popupLayout = new PopupLayout(this, hasAcceptButton ? PopupLayout.Styles.Buttons2 : PopupLayout.Styles.Circle) - { - AlignmentX = -1, - AlignmentY = -1, - WeightX = 1, - WeightY = 1 - }; - _popupLayout.Show(); - SetContent(_popupLayout); - } - - protected override void ApplyButton(ButtonPosition position, EButton button) - { - - switch (position) - { - case ButtonPosition.Neutral: - this.SetButton2Part(button.SetWatchPopupRightStyle()); - break; - - case ButtonPosition.Negative: - if (_hasAcceptButton) - { - button.BackgroundColor = EColor.Default; - this.SetButton1Part(button.SetWatchPopupLeftStyle()); - } - else - { - button.BackgroundColor = new EColor(0, 47, 66, 255); - this.SetButton1Part(button.SetBottomStyle()); - } - break; - - case ButtonPosition.Positive: - default: - // Due to ux limiation, nothing to do - break; - } - } - - protected override void ApplyContent(EvasObject content) - { - _popupLayout.SetContent(content); - } - - protected override void ApplyTitle(string title) - { - if (_popupLayout is PopupLayout layout) - { - layout.SetTitleText(title); - } - } - - protected override void ApplyTitleColor(EColor color) - { - if (_popupLayout is PopupLayout layout) - { - layout.SetTitleColor(color); - } - } - - protected override void ApplyMessage(string message) - { - _popupLayout.SetTextPart(message); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchListView.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchListView.cs deleted file mode 100644 index c0a365e0a77f..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchListView.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Collections; -using ElmSharp; -using ElmSharp.Wearable; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - [Obsolete] - public class WatchListView : Native.ListView, IRotaryActionWidget, IRotaryInteraction - { - CircleGenList _circleGenList; - CircleSurface _surface; - - public IntPtr CircleHandle => _circleGenList.CircleHandle; - - public CircleGenList CircleGenList => _circleGenList; - - public CircleSurface CircleSurface => _surface; - - public IRotaryActionWidget RotaryWidget { get => this; } - - GenItemClass _paddingItemClass; - protected GenItemClass PaddingItemTemplate => _paddingItemClass ?? (_paddingItemClass = new PaddingItemClass()); - - public override ScrollBarVisiblePolicy VerticalScrollBarVisibility - { - get => _circleGenList.VerticalScrollBarVisiblePolicy; - set => _circleGenList.VerticalScrollBarVisiblePolicy = value; - } - - public WatchListView(EvasObject parent, CircleSurface surface) - { - _surface = surface; - Realize(parent); - - Scroller = new CircleScrollerExtension(this); - Scroller.Scrolled += OnScrolled; - } - - protected override void UpdateHeader() - { - if (GetHeader() != null) - { - base.UpdateHeader(); - } - else - { - var paddingTemplate = PaddingItemTemplate; - if (!HasHeaderContext()) - { - InitializeHeaderItemContext(PaddingItemTemplate); - } - else - { - (HeaderItemContext.Item as GenListItem).UpdateItemClass(paddingTemplate, HeaderItemContext); - } - HeaderItemContext.Element = null; - } - } - - protected override void UpdateFooter() - { - if (GetFooter() != null) - { - base.UpdateFooter(); - } - else - { - var paddingTemplate = PaddingItemTemplate; - if (!HasFooterContext()) - { - InitializeFooterItemContext(PaddingItemTemplate); - } - else - { - (FooterItemContext.Item as GenListItem).UpdateItemClass(paddingTemplate, FooterItemContext); - } - FooterItemContext.Element = null; - } - } - - - protected override IntPtr CreateHandle(EvasObject parent) - { - _circleGenList = new CircleGenList(parent, _surface); - RealHandle = _circleGenList.RealHandle; - return _circleGenList.Handle; - } - - class PaddingItemClass : GenItemClass - { - public PaddingItemClass() : base(ThemeConstants.GenItemClass.Styles.Watch.Padding) - { - } - } - - class CircleScrollerExtension : CircleScroller - { - WatchListView _list; - - public override IntPtr CircleHandle => _list.CircleHandle; - - public CircleScrollerExtension(WatchListView parent) : base(parent, parent.CircleSurface) - { - _list = parent; - } - - protected override IntPtr CreateHandle(EvasObject parent) - { - return parent.RealHandle; - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchScroller.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchScroller.cs deleted file mode 100644 index b832a900f2e4..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchScroller.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using ElmSharp; -using ElmSharp.Wearable; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - public class WatchScroller : Native.Scroller, IRotaryActionWidget, IRotaryInteraction - { - CircleScroller _circleScroller; - CircleSurface _surface; - - public IntPtr CircleHandle => _circleScroller.CircleHandle; - - public CircleSurface CircleSurface => _surface; - - public CircleScroller CircleScroller => _circleScroller; - - public IRotaryActionWidget RotaryWidget { get => this; } - - public WatchScroller(EvasObject parent, CircleSurface surface) - { - _surface = surface; - Realize(parent); - - VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible; - HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible; - } - - public override ScrollBarVisiblePolicy VerticalScrollBarVisiblePolicy - { - get => _circleScroller.VerticalScrollBarVisiblePolicy; - set => _circleScroller.VerticalScrollBarVisiblePolicy = value; - } - - public override ScrollBarVisiblePolicy HorizontalScrollBarVisiblePolicy - { - get => _circleScroller.HorizontalScrollBarVisiblePolicy; - set => _circleScroller.HorizontalScrollBarVisiblePolicy = value; - } - - protected override IntPtr CreateHandle(EvasObject parent) - { - _circleScroller = new CircleScroller(parent, _surface); - RealHandle = _circleScroller.RealHandle; - return _circleScroller.Handle; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchSpinner.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchSpinner.cs deleted file mode 100644 index 9cd011812a1c..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchSpinner.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using ElmSharp; -using ElmSharp.Wearable; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - public class WatchSpinner : CircleSpinner, IRotaryInteraction - { - SmartEvent _wheelAppeared, _wheelDisappeared; - - public event EventHandler WheelAppeared; - - public event EventHandler WheelDisappeared; - - public IRotaryActionWidget RotaryWidget { get => this; } - - public WatchSpinner(EvasObject parent, CircleSurface surface) : base(parent, surface) - { - Style = ThemeConstants.CircleSpinner.Styles.Circle; - _wheelAppeared = new SmartEvent(this, ThemeConstants.CircleSpinner.Signals.ShowList); - _wheelDisappeared = new SmartEvent(this, ThemeConstants.CircleSpinner.Signals.HideList); - - _wheelAppeared.On += (s, e) => WheelAppeared?.Invoke(this, EventArgs.Empty); - _wheelDisappeared.On += (s, e) => WheelDisappeared?.Invoke(this, EventArgs.Empty); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchTableView.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchTableView.cs deleted file mode 100644 index 65ff1e120f6b..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchTableView.cs +++ /dev/null @@ -1,66 +0,0 @@ -using ElmSharp; -using ElmSharp.Wearable; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch -{ - [System.Obsolete] - public class WatchTableView : WatchListView, ITableView - { - static readonly SectionCellRenderer _sectionCellRenderer = new SectionCellRenderer(); - - public WatchTableView(EvasObject parent, CircleSurface surface) : base(parent, surface) - { - } - - public void ApplyTableRoot(TableRoot root) - { - Clear(); - var cls = new PaddingItemClass(); - Append(cls, null); - foreach (TableSection ts in root) - { - if (!string.IsNullOrEmpty(ts.Title)) - AddSectionTitle(ts.Title, ts.TextColor); - AddSource(ts); - } - Append(cls, null); - } - - protected override CellRenderer GetCellRenderer(Cell cell, bool isGroup = false) - { - if (cell.GetType() == typeof(SectionCell)) - { - return _sectionCellRenderer; - } - return base.GetCellRenderer(cell, isGroup); - } - - void AddSectionTitle(string title, Graphics.Color textColor) - { - Cell cell = new SectionCell() - { - Text = title, - TextColor = textColor - }; - AddCell(cell); - } - - internal class SectionCellRenderer : TextCellRenderer - { - public SectionCellRenderer() : this(ThemeConstants.GenItemClass.Styles.GroupIndex) - { - } - protected SectionCellRenderer(string style) : base(style) { } - } - class SectionCell : TextCell - { - } - - class PaddingItemClass : GenItemClass - { - public PaddingItemClass() : base(ThemeConstants.GenItemClass.Styles.Watch.Padding) - { - } - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/WebViewContainer.cs b/src/Compatibility/Core/src/Tizen/Native/WebViewContainer.cs deleted file mode 100644 index 5ac6f676fd79..000000000000 --- a/src/Compatibility/Core/src/Tizen/Native/WebViewContainer.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using ElmSharp; -using TWebView = Tizen.WebView.WebView; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native -{ - public class WebViewContainer : WidgetLayout - { - public TWebView WebView { get; } - - public WebViewContainer(EvasObject parent) : base(parent) - { - WebView = new TWebView(parent); - SetContent(WebView); - AllowFocus(true); - Focused += OnFocused; - Unfocused += OnUnfocused; - } - - void OnFocused(object sender, EventArgs e) - { - WebView.SetFocus(true); - } - - void OnUnfocused(object sender, EventArgs e) - { - WebView.SetFocus(false); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/NativeBindingService.cs b/src/Compatibility/Core/src/Tizen/NativeBindingService.cs index c5f4b2cb5fbf..d575dbf30615 100644 --- a/src/Compatibility/Core/src/Tizen/NativeBindingService.cs +++ b/src/Compatibility/Core/src/Tizen/NativeBindingService.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.Maui.Controls.Xaml.Internals; -using EObject = ElmSharp.EvasObject; +using NView = Tizen.NUI.BaseComponents.View; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -11,7 +11,7 @@ class NativeBindingService : INativeBindingService public bool TrySetBinding(object target, string propertyName, BindingBase binding) { Hosting.MauiAppBuilderExtensions.CheckForCompatibility(); - var view = target as EObject; + var view = target as NView; if (view == null) return false; if (target.GetType().GetProperty(propertyName)?.GetMethod == null) @@ -23,7 +23,7 @@ public bool TrySetBinding(object target, string propertyName, BindingBase bindin public bool TrySetBinding(object target, BindableProperty property, BindingBase binding) { Hosting.MauiAppBuilderExtensions.CheckForCompatibility(); - var view = target as EObject; + var view = target as NView; if (view == null) return false; view.SetBinding(property, binding); @@ -33,7 +33,7 @@ public bool TrySetBinding(object target, BindableProperty property, BindingBase public bool TrySetValue(object target, BindableProperty property, object value) { Hosting.MauiAppBuilderExtensions.CheckForCompatibility(); - var view = target as EObject; + var view = target as NView; if (view == null) return false; view.SetValue(property, value); diff --git a/src/Compatibility/Core/src/Tizen/NativeValueConverterService.cs b/src/Compatibility/Core/src/Tizen/NativeValueConverterService.cs index 274b9cf5a5f7..392604340fc8 100644 --- a/src/Compatibility/Core/src/Tizen/NativeValueConverterService.cs +++ b/src/Compatibility/Core/src/Tizen/NativeValueConverterService.cs @@ -1,7 +1,7 @@ using System; using Microsoft.Maui.Controls.Xaml.Internals; -using EObject = ElmSharp.EvasObject; +using NUI = Tizen.NUI.BaseComponents.View; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -11,9 +11,9 @@ public bool ConvertTo(object value, Type toType, out object nativeValue) { Hosting.MauiAppBuilderExtensions.CheckForCompatibility(); nativeValue = null; - if ((value is EObject) && toType.IsAssignableFrom(typeof(View))) + if ((value is NUI) && toType.IsAssignableFrom(typeof(View))) { - nativeValue = ((EObject)value).ToView(); + nativeValue = ((NUI)value).ToView(); return true; } return false; diff --git a/src/Compatibility/Core/src/Tizen/NativeViewWrapper.cs b/src/Compatibility/Core/src/Tizen/NativeViewWrapper.cs index 3aee74595085..ec1d7e5e0ad3 100644 --- a/src/Compatibility/Core/src/Tizen/NativeViewWrapper.cs +++ b/src/Compatibility/Core/src/Tizen/NativeViewWrapper.cs @@ -1,23 +1,23 @@ -using ElmSharp; -using ESize = ElmSharp.Size; +using Microsoft.Maui.Graphics; +using NView = Tizen.NUI.BaseComponents.View; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { - public delegate ESize? MeasureDelegate(NativeViewWrapperRenderer renderer, int availableWidth, int availableHeight); + public delegate Size? MeasureDelegate(NativeViewWrapperRenderer renderer, int availableWidth, int availableHeight); #pragma warning disable CS0618 // Type or member is obsolete public class NativeViewWrapper : View #pragma warning disable CS0618 // Type or member is obsolete { - public NativeViewWrapper(EvasObject obj, MeasureDelegate measureDelegate = null) + public NativeViewWrapper(NView obj, MeasureDelegate measureDelegate = null) { - EvasObject = obj; + NativeView = obj; MeasureDelegate = measureDelegate; obj.TransferBindablePropertiesToWrapper(this); } - public EvasObject EvasObject + public NView NativeView { get; private set; @@ -29,7 +29,7 @@ protected override void OnBindingContextChanged() { // TODO: we should provide a delegate to obtain children of a Container object, // however currently there is no way to get the list of children - EvasObject.SetBindingContext(BindingContext); + NativeView.SetBindingContext(BindingContext); base.OnBindingContextChanged(); } } diff --git a/src/Compatibility/Core/src/Tizen/PanGestureHandler.cs b/src/Compatibility/Core/src/Tizen/PanGestureHandler.cs deleted file mode 100644 index 8a3213fa1fc9..000000000000 --- a/src/Compatibility/Core/src/Tizen/PanGestureHandler.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.ComponentModel; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [Obsolete] - public class PanGestureHandler : GestureHandler - { - int _currentPanGestureId; - - public PanGestureHandler(IGestureRecognizer recognizer) : base(recognizer) - { - } - - public override GestureLayer.GestureType Type - { - get - { - return GestureLayer.GestureType.Momentum; - } - } - - protected override void OnStarted(View sender, object data) - { - _currentPanGestureId++; - (Recognizer as IPanGestureController)?.SendPanStarted(sender, _currentPanGestureId); - } - - protected override void OnMoved(View sender, object data) - { - var lineData = (GestureLayer.MomentumData)data; - (Recognizer as IPanGestureController)?.SendPan(sender, Forms.ConvertToScaledDP(lineData.X2 - lineData.X1), Forms.ConvertToScaledDP(lineData.Y2 - lineData.Y1), _currentPanGestureId); - } - - protected override void OnCompleted(View sender, object data) - { - (Recognizer as IPanGestureController)?.SendPanCompleted(sender, _currentPanGestureId); - } - - protected override void OnCanceled(View sender, object data) - { - (Recognizer as IPanGestureController)?.SendPanCanceled(sender, _currentPanGestureId); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/PinchGestureHandler.cs b/src/Compatibility/Core/src/Tizen/PinchGestureHandler.cs deleted file mode 100644 index a5888f2935c0..000000000000 --- a/src/Compatibility/Core/src/Tizen/PinchGestureHandler.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.ComponentModel; -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [Obsolete] - public class PinchGestureHandler : GestureHandler - { - Graphics.Point _currentScalePoint; - int _previousPinchRadius; - double _originalPinchScale; - - public PinchGestureHandler(IGestureRecognizer recognizer) : base(recognizer) - { - } - - public override GestureLayer.GestureType Type - { - get - { - return GestureLayer.GestureType.Zoom; - } - } - - protected override void OnStarted(View sender, object data) - { - var geometry = Platform.GetRenderer(sender).NativeView.Geometry; - var zoomData = (GestureLayer.ZoomData)data; - _currentScalePoint = new Graphics.Point((zoomData.X - geometry.X) / (double)geometry.Width, (zoomData.Y - geometry.Y) / (double)geometry.Height); - _originalPinchScale = sender.Scale; - _previousPinchRadius = zoomData.Radius; - (Recognizer as IPinchGestureController)?.SendPinchStarted(sender, _currentScalePoint); - } - - protected override void OnMoved(View sender, object data) - { - var zoomData = (GestureLayer.ZoomData)data; - if (_previousPinchRadius <= 0) - _previousPinchRadius = 1; - // functionality limitation: _currentScalePoint is not updated - (Recognizer as IPinchGestureController)?.SendPinch(sender, - 1 + _originalPinchScale * (zoomData.Radius - _previousPinchRadius) / _previousPinchRadius, - _currentScalePoint - ); - _previousPinchRadius = zoomData.Radius; - } - - protected override void OnCompleted(View sender, object data) - { - (Recognizer as IPinchGestureController)?.SendPinchEnded(sender); - } - - protected override void OnCanceled(View sender, object data) - { - (Recognizer as IPinchGestureController)?.SendPinchCanceled(sender); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Platform.cs b/src/Compatibility/Core/src/Tizen/Platform.cs index 0ef8670bf924..5a3f001d0411 100644 --- a/src/Compatibility/Core/src/Tizen/Platform.cs +++ b/src/Compatibility/Core/src/Tizen/Platform.cs @@ -4,9 +4,9 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; -using ElmSharp; using Microsoft.Maui.Controls.Internals; -using Microsoft.Maui.Handlers; +using Tizen.UIExtensions.NUI; +using NView = Tizen.NUI.BaseComponents.View; [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Material")] @@ -88,10 +88,6 @@ internal static IVisualElementRenderer CreateRenderer(VisualElement element) renderer = ver; else if (handler is IPlatformViewHandler vh) { - if (element.Parent is IView view && view.Handler is IPlatformViewHandler nvh) - { - vh.SetParent(nvh); - } renderer = new HandlerToRendererShim(vh); element.Handler = handler; } @@ -100,14 +96,9 @@ internal static IVisualElementRenderer CreateRenderer(VisualElement element) return renderer; } - internal static ITizenPlatform CreatePlatform(EvasObject parent) + internal static ITizenPlatform CreatePlatform() { - if (Forms.PlatformType == PlatformType.Lightweight) - { - return new LightweightPlatform(parent); - } - - return new DefaultPlatform(parent); + return new DefaultPlatform(); } public static SizeRequest GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint) @@ -130,16 +121,9 @@ public interface ITizenPlatform : IDisposable { void SetPage(Page page); bool SendBackButtonPressed(); - EvasObject GetRootNativeView(); - bool HasAlpha { get; set; } - event EventHandler RootNativeViewChanged; - bool PageIsChildOfPlatform(Page page); - } + NView GetRootNativeView(); - public class RootNativeViewChangedEventArgs : EventArgs - { - public RootNativeViewChangedEventArgs(EvasObject view) => RootNativeView = view; - public EvasObject RootNativeView { get; private set; } + bool PageIsChildOfPlatform(Page page); } [Obsolete] @@ -147,28 +131,20 @@ public class DefaultPlatform : BindableObject, ITizenPlatform, INavigation { NavigationModel _navModel = new NavigationModel(); bool _disposed; - readonly Naviframe _internalNaviframe; + readonly NavigationStack _viewStack; readonly PopupManager _popupManager; - readonly HashSet _alerts = new HashSet(); + readonly Dictionary _pageMap = new Dictionary(); -#pragma warning disable 0067 - public event EventHandler RootNativeViewChanged; -#pragma warning restore 0067 - internal DefaultPlatform(EvasObject parent) + internal DefaultPlatform() { - Forms.NativeParent = parent; - - _internalNaviframe = new Naviframe(Forms.NativeParent) + _viewStack = new NavigationStack { - PreserveContentOnPop = true, - DefaultBackButtonEnabled = false, + BackgroundColor = global::Tizen.NUI.Color.White, + WidthResizePolicy = global::Tizen.NUI.ResizePolicyType.FillToParent, + HeightResizePolicy = global::Tizen.NUI.ResizePolicyType.FillToParent, }; - _internalNaviframe.SetAlignment(-1, -1); - _internalNaviframe.SetWeight(1.0, 1.0); - _internalNaviframe.Show(); - _internalNaviframe.AnimationFinished += NaviAnimationFinished; if (Forms.UseMessagingCenter) { @@ -183,11 +159,19 @@ internal DefaultPlatform(EvasObject parent) public Page Page { get; private set; } - public bool HasAlpha { get; set; } + Page CurrentPage + { + get + { + if (_viewStack.Top != null && _pageMap.ContainsKey(_viewStack.Top)) + { + return _pageMap[_viewStack.Top]; + } + return null; + } + } - Task CurrentModalNavigationTask { get; set; } - TaskCompletionSource CurrentTaskCompletionSource { get; set; } - IPageController CurrentPageController => _navModel.CurrentPage as IPageController; + IPageController CurrentPageController => CurrentPage; IReadOnlyList INavigation.ModalStack => _navModel.Modals.ToList(); IReadOnlyList INavigation.NavigationStack => new List(); @@ -201,69 +185,44 @@ public void SetPage(Page newRoot) { if (Page != null) { - var copyOfStack = new List(_internalNaviframe.NavigationStack); - for (var i = 0; i < copyOfStack.Count; i++) - { - copyOfStack[i].Delete(); - } - foreach (Page page in _navModel.Roots) + foreach (var child in _viewStack.Children.ToList()) { - var renderer = Platform.GetRenderer(page); - renderer?.Dispose(); + child.Dispose(); } - _navModel = new NavigationModel(); + _viewStack.Clear(); + _pageMap.Clear(); } + _navModel = new NavigationModel(); if (newRoot == null) return; + Page = newRoot; _navModel.Push(newRoot, null); - Page = newRoot; + ((Application)Page.RealParent).NavigationProxy.Inner = this; IVisualElementRenderer pageRenderer = Platform.CreateRenderer(Page); - var naviItem = _internalNaviframe.Push(pageRenderer.NativeView); - naviItem.TitleBarVisible = false; + _pageMap[pageRenderer.NativeView] = newRoot; + _viewStack.Push(pageRenderer.NativeView, false); - // Make naviitem transparent if parent window is transparent. - // Make sure that this is only for _navModel._naviTree. (not for _navModel._modalStack) - // In addtion, the style of naviItem is only decided before the naviItem pushed into Naviframe. (not on-demand). - if (HasAlpha) - { - naviItem.Style = "default/transparent"; - } - - ((Application)Page.RealParent).NavigationProxy.Inner = this; - - Application.Current.Dispatcher.DispatchDelayed(TimeSpan.Zero, () => CurrentPageController?.SendAppearing()); + Device.BeginInvokeOnMainThread(() => CurrentPageController?.SendAppearing()); } public bool SendBackButtonPressed() { - bool handled = false; - if (_navModel.CurrentPage != null) - { - if (CurrentModalNavigationTask != null && !CurrentModalNavigationTask.IsCompleted) - { - handled = true; - } - else - { - handled = _navModel.CurrentPage.SendBackButtonPressed(); - } - } - return handled; + return _navModel.CurrentPage?.SendBackButtonPressed() ?? false; } - public EvasObject GetRootNativeView() + public NView GetRootNativeView() { - return _internalNaviframe as EvasObject; + return _viewStack; } public bool PageIsChildOfPlatform(Page page) { var parent = page.AncestorToRoot(); - return Page == parent || _navModel.Roots.Contains(parent); + return _navModel.Modals.FirstOrDefault() == page || _navModel.Roots.Contains(parent); } protected virtual void Dispose(bool disposing) @@ -274,7 +233,8 @@ protected virtual void Dispose(bool disposing) { _popupManager?.Dispose(); SetPage(null); - _internalNaviframe.Unrealize(); + _viewStack.Unparent(); + _viewStack.Dispose(); } _disposed = true; } @@ -333,15 +293,14 @@ Task INavigation.PushModalAsync(Page modal) async Task INavigation.PushModalAsync(Page modal, bool animated) { var previousPage = CurrentPageController; - Application.Current.Dispatcher.Dispatch(() => previousPage?.SendDisappearing()); + previousPage?.SendDisappearing(); _navModel.PushModal(modal); - await PushModalInternal(modal, animated); - - // Verify that the modal is still on the stack - if (_navModel.CurrentPage == modal) - CurrentPageController.SendAppearing(); + var renderer = Platform.GetOrCreateRenderer(modal); + _pageMap[renderer.NativeView] = modal; + await _viewStack.Push(renderer.NativeView, animated); + CurrentPageController.SendAppearing(); } Task INavigation.PopModalAsync() @@ -351,95 +310,19 @@ Task INavigation.PopModalAsync() async Task INavigation.PopModalAsync(bool animated) { - Page modal = _navModel.PopModal(); + Page page = _navModel.PopModal(); + (page as IPageController)?.SendDisappearing(); - IVisualElementRenderer modalRenderer = Platform.GetRenderer(modal); - if (modalRenderer != null) - { - await PopModalInternal(animated); - modalRenderer.Dispose(); - } + IVisualElementRenderer modalRenderer = Platform.GetRenderer(page); - CurrentPageController?.SendAppearing(); - return modal; - } - - async Task PushModalInternal(Page modal, bool animated) - { - TaskCompletionSource tcs = null; - if (CurrentModalNavigationTask != null && !CurrentModalNavigationTask.IsCompleted) - { - var previousTask = CurrentModalNavigationTask; - tcs = new TaskCompletionSource(); - CurrentModalNavigationTask = tcs.Task; - await previousTask; - } - - var after = _internalNaviframe.NavigationStack.LastOrDefault(); - NaviItem pushed = null; - if (animated || after == null) - { - pushed = _internalNaviframe.Push(Platform.GetOrCreateRenderer(modal).NativeView, modal.Title); - } - else - { - pushed = _internalNaviframe.InsertAfter(after, Platform.GetOrCreateRenderer(modal).NativeView, modal.Title); - } - pushed.TitleBarVisible = false; - - bool shouldWait = animated && after != null; - await WaitForCompletion(shouldWait, tcs); - } - - async Task PopModalInternal(bool animated) - { - TaskCompletionSource tcs = null; - if (CurrentModalNavigationTask != null && !CurrentModalNavigationTask.IsCompleted) - { - var previousTask = CurrentModalNavigationTask; - tcs = new TaskCompletionSource(); - CurrentModalNavigationTask = tcs.Task; - await previousTask; - } + await _viewStack.Pop(animated); + _pageMap.Remove(modalRenderer.NativeView); - if (animated) - { - _internalNaviframe.Pop(); - } - else - { - _internalNaviframe.NavigationStack.LastOrDefault()?.Delete(); - } + modalRenderer?.Dispose(); - bool shouldWait = animated && (_internalNaviframe.NavigationStack.Count != 0); - await WaitForCompletion(shouldWait, tcs); - } - - async Task WaitForCompletion(bool shouldWait, TaskCompletionSource tcs) - { - if (shouldWait) - { - tcs = tcs ?? new TaskCompletionSource(); - CurrentTaskCompletionSource = tcs; - if (CurrentModalNavigationTask == null || CurrentModalNavigationTask.IsCompleted) - { - CurrentModalNavigationTask = CurrentTaskCompletionSource.Task; - } - } - else - { - tcs?.SetResult(true); - } - - if (tcs != null) - await tcs.Task; - } + CurrentPageController?.SendAppearing(); - void NaviAnimationFinished(object sender, EventArgs e) - { - var tcs = CurrentTaskCompletionSource; - CurrentTaskCompletionSource = null; - tcs?.SetResult(true); + return page; } } } diff --git a/src/Compatibility/Core/src/Tizen/PopupManager.cs b/src/Compatibility/Core/src/Tizen/PopupManager.cs index e726c5f39294..1a0d5a2ae5a6 100644 --- a/src/Compatibility/Core/src/Tizen/PopupManager.cs +++ b/src/Compatibility/Core/src/Tizen/PopupManager.cs @@ -1,14 +1,5 @@ using System; -using System.Collections.Generic; -using ElmSharp; using Microsoft.Maui.Controls.Internals; -using Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific; -using Microsoft.Maui.Devices; -using EButton = ElmSharp.Button; -using EColor = ElmSharp.Color; -using EProgressBar = ElmSharp.ProgressBar; -using Color = Microsoft.Maui.Graphics.Color; -using XStackLayout = Microsoft.Maui.Controls.StackLayout; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -16,9 +7,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public class PopupManager : IDisposable { ITizenPlatform _platform; - Native.Dialog _pageBusyDialog; - int _pageBusyCount; - readonly HashSet _alerts = new HashSet(); public PopupManager(ITizenPlatform platform) { @@ -50,42 +38,7 @@ void OnBusySetRequest(Page sender, bool enabled) // Verify that the page making the request is child of this platform if (!_platform.PageIsChildOfPlatform(sender)) return; - - if (null == _pageBusyDialog) - { - _pageBusyDialog = new Native.Dialog(Forms.NativeParent) - { - Orientation = PopupOrientation.Center, - BackgroundColor = EColor.Transparent - }; - - if (DeviceInfo.Idiom == DeviceIdiom.Phone) - { - _pageBusyDialog.SetTitleBackgroundColor(EColor.Transparent); - _pageBusyDialog.SetContentBackgroundColor(EColor.Transparent); - } - else if (DeviceInfo.Idiom == DeviceIdiom.Watch) - { - _pageBusyDialog.SetWatchCircleStyle(); - } - - var activity = new EProgressBar(_pageBusyDialog) { IsPulseMode = true }.SetLargeStyle(); - activity.PlayPulse(); - activity.Show(); - - _pageBusyDialog.Content = activity; - - } - _pageBusyCount = Math.Max(0, enabled ? _pageBusyCount + 1 : _pageBusyCount - 1); - if (_pageBusyCount > 0) - { - _pageBusyDialog.Show(); - } - else - { - _pageBusyDialog.Dismiss(); - _pageBusyDialog = null; - } + // TODO. show busy popup } void OnAlertRequest(Page sender, AlertArguments arguments) @@ -93,41 +46,7 @@ void OnAlertRequest(Page sender, AlertArguments arguments) // Verify that the page making the request is child of this platform if (!_platform.PageIsChildOfPlatform(sender)) return; - - var alert = Native.Dialog.CreateDialog(Forms.NativeParent, (arguments.Accept != null)); - - alert.Title = arguments.Title; - var message = arguments.Message?.Replace("&", "&", StringComparison.Ordinal).Replace("<", "<", StringComparison.Ordinal).Replace(">", ">", StringComparison.Ordinal).Replace(Environment.NewLine, "
", StringComparison.Ordinal); - alert.Message = message; - - var cancel = new EButton(alert) { Text = arguments.Cancel }; - alert.NegativeButton = cancel; - cancel.Clicked += (s, evt) => - { - arguments.SetResult(false); - alert.Dismiss(); - }; - - if (arguments.Accept != null) - { - var ok = new EButton(alert) { Text = arguments.Accept }; - alert.NeutralButton = ok; - ok.Clicked += (s, evt) => - { - arguments.SetResult(true); - alert.Dismiss(); - }; - } - - alert.BackButtonPressed += (s, evt) => - { - arguments.SetResult(false); - alert.Dismiss(); - }; - - alert.Show(); - _alerts.Add(alert); - alert.Dismissed += (s, e) => _alerts.Remove(alert); + // TODO. Show alert popup } void OnActionSheetRequest(Page sender, ActionSheetArguments arguments) @@ -135,72 +54,7 @@ void OnActionSheetRequest(Page sender, ActionSheetArguments arguments) // Verify that the page making the request is child of this platform if (!_platform.PageIsChildOfPlatform(sender)) return; - - var alert = Native.Dialog.CreateDialog(Forms.NativeParent); - - alert.Title = arguments.Title; - var box = new Box(alert); - - if (null != arguments.Destruction) - { - var destruction = new Native.Button(alert) - { - Text = arguments.Destruction, - AlignmentX = -1 - }; - destruction.SetWatchTextStyle(); - //TextColor should be set after applying style - destruction.TextColor = EColor.Red; - - destruction.Clicked += (s, evt) => - { - arguments.SetResult(arguments.Destruction); - alert.Dismiss(); - }; - destruction.Show(); - box.PackEnd(destruction); - } - - foreach (string buttonName in arguments.Buttons) - { - var button = new Native.Button(alert) - { - Text = buttonName, - AlignmentX = -1 - }; - button.SetWatchTextStyle(); - - button.Clicked += (s, evt) => - { - arguments.SetResult(buttonName); - alert.Dismiss(); - }; - button.Show(); - box.PackEnd(button); - } - - box.Show(); - alert.Content = box; - - if (null != arguments.Cancel) - { - var cancel = new EButton(Forms.NativeParent) { Text = arguments.Cancel }; - alert.NegativeButton = cancel; - cancel.Clicked += (s, evt) => - { - alert.Dismiss(); - }; - } - - alert.BackButtonPressed += (s, evt) => - { - alert.Dismiss(); - }; - - alert.Show(); - - _alerts.Add(alert); - alert.Dismissed += (s, e) => _alerts.Remove(alert); + // TODO. Show action sheet popup } void OnPromptRequested(Page sender, PromptArguments args) @@ -209,91 +63,7 @@ void OnPromptRequested(Page sender, PromptArguments args) if (!_platform.PageIsChildOfPlatform(sender)) return; - var prompt = Native.Dialog.CreateDialog(Forms.NativeParent, (args.Accept != null)); - prompt.Title = args.Title; - - var entry = new Entry - { - MinimumWidthRequest = 200, - HorizontalOptions = LayoutOptions.Fill, - BackgroundColor = Color.FromRgb(250, 250, 250), - TextColor = Color.FromRgb(0, 0, 0), - Keyboard = args.Keyboard, - }; - - if (!string.IsNullOrEmpty(args.Placeholder)) - { - entry.Placeholder = args.Placeholder; - } - if (args.MaxLength > 0) - { - entry.MaxLength = args.MaxLength; - } - - var layout = new XStackLayout - { - Spacing = 10, - Children = - { - new Label - { - LineBreakMode = LineBreakMode.CharacterWrap, - TextColor = DeviceInfo.Idiom == DeviceIdiom.Watch ? Color.FromRgb(255,255,255) : Application.AccentColor, - Text = args.Message, - HorizontalOptions = LayoutOptions.Fill, - HorizontalTextAlignment = TextAlignment.Center, -#pragma warning disable CS0612 // Type or member is obsolete - FontSize = Device.GetNamedSize(NamedSize.Subtitle, typeof(Label)), -#pragma warning disable CS0612 // Type or member is obsolete - }, - entry, - } - }; - - layout.Parent = sender; - var layoutrenderer = Platform.GetOrCreateRenderer(layout); - - var request = layout.Measure(DeviceInfo.Idiom == DeviceIdiom.Watch ? sender.Width * 0.7 : sender.Width, sender.Height); - (layoutrenderer as ILayoutRenderer).RegisterOnLayoutUpdated(); - layoutrenderer.NativeView.MinimumHeight = Forms.ConvertToScaledPixel(request.Request.Height); - layoutrenderer.NativeView.MinimumWidth = Forms.ConvertToScaledPixel(request.Request.Width); - - prompt.Content = layoutrenderer.NativeView; - - var cancel = new EButton(prompt) { Text = args.Cancel }; - prompt.NegativeButton = cancel; - cancel.Clicked += (s, evt) => - { - args.SetResult(null); - prompt.Dismiss(); - }; - - if (args.Accept != null) - { - var ok = new EButton(prompt) { Text = args.Accept }; - prompt.NeutralButton = ok; - ok.Clicked += (s, evt) => - { - args.SetResult(entry.Text); - prompt.Dismiss(); - }; - } - - entry.Completed += (s, e) => - { - args.SetResult(entry.Text); - prompt.Dismiss(); - }; - - prompt.BackButtonPressed += (s, evt) => - { - prompt.Dismiss(); - }; - - prompt.Show(); - - _alerts.Add(prompt); - prompt.Dismissed += (s, e) => _alerts.Remove(prompt); + // TODO prompt popup } } diff --git a/src/Compatibility/Core/src/Tizen/PreloadedWindow.cs b/src/Compatibility/Core/src/Tizen/PreloadedWindow.cs deleted file mode 100644 index baa8aadf2f2e..000000000000 --- a/src/Compatibility/Core/src/Tizen/PreloadedWindow.cs +++ /dev/null @@ -1,43 +0,0 @@ -using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; -using ELayout = ElmSharp.Layout; -using EWindow = ElmSharp.Window; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - public class PreloadedWindow : EWindow - { - static PreloadedWindow s_precreated; - - public PreloadedWindow() : base("FormsWindow-pre") - { - s_precreated = this; - Initialize(); - } - - public ELayout BaseLayout - { - get; - protected set; - } - - protected void Initialize() - { - var conformant = new Conformant(this); - conformant.Show(); - - var layout = new ApplicationLayout(conformant); - layout.Show(); - - BaseLayout = layout; - conformant.SetContent(BaseLayout); - } - - public static PreloadedWindow GetInstance() - { - var instance = s_precreated; - s_precreated = null; - return instance; - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ActivityIndicatorRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ActivityIndicatorRenderer.cs deleted file mode 100644 index 42f7488c34d8..000000000000 --- a/src/Compatibility/Core/src/Tizen/Renderers/ActivityIndicatorRenderer.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Microsoft.Maui.Controls.Platform; -using EColor = ElmSharp.Color; -using EProgressBar = ElmSharp.ProgressBar; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] - public class ActivityIndicatorRenderer : ViewRenderer - { - static readonly EColor s_defaultColor = ThemeConstants.ProgressBar.ColorClass.Default; - - public ActivityIndicatorRenderer() - { - RegisterPropertyHandler(ActivityIndicator.ColorProperty, UpdateColor); - RegisterPropertyHandler(ActivityIndicator.IsRunningProperty, UpdateIsRunning); - } - - protected override void OnElementChanged(ElementChangedEventArgs e) - { - if (Control == null) - { - SetNativeControl(new EProgressBar(Forms.NativeParent) - { - IsPulseMode = true, - } - .SetSmallStyle()); - } - base.OnElementChanged(e); - } - - void UpdateColor(bool initialize) - { - if (initialize && Element.Color.IsDefault()) - return; - - Control.Color = (Element.Color.IsDefault()) ? s_defaultColor : Element.Color.ToNative(); - } - - void UpdateIsRunning() - { - if (Element.IsRunning && Element.IsEnabled) - { - Control.PlayPulse(); - } - else - { - Control.StopPulse(); - } - } - - protected override void UpdateIsEnabled(bool initialize) - { - base.UpdateIsEnabled(initialize); - UpdateIsRunning(); - } - - }; -} diff --git a/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs index 9823e21fb147..cd7fae1bd551 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs @@ -1,96 +1,38 @@ -using System.ComponentModel; +using NView = Tizen.NUI.BaseComponents.View; +using Tizen.UIExtensions.NUI; using Microsoft.Maui.Controls.Platform; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; -using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] - public class BoxViewRenderer : ViewRenderer + public class BoxViewRenderer : ViewRenderer { public BoxViewRenderer() { RegisterPropertyHandler(nameof(Element.CornerRadius), OnRadiusUpdate); + RegisterPropertyHandler(nameof(Element.Color), UpdateColor); } protected override void OnElementChanged(ElementChangedEventArgs e) { if (Control == null) { - SetNativeControl(new RoundRectangle(Forms.NativeParent)); + SetNativeControl(new NView()); } - - UpdateColor(); base.OnElementChanged(e); } - - protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == BoxView.ColorProperty.PropertyName) - { - UpdateColor(); - } - base.OnElementPropertyChanged(sender, e); - } - - protected override void UpdateBackgroundColor(bool initialize) - { - if (initialize && Element.BackgroundColor.IsDefault()) - return; - - if (Element.Color.IsDefault()) - { - UpdateColor(); - } - } - - protected override void UpdateLayout() + void OnRadiusUpdate() { - base.UpdateLayout(); - Control.Draw(Control.Geometry); + int topLeft = Forms.ConvertToScaledPixel(Element.CornerRadius.TopLeft); + Control.CornerRadius = topLeft; } - protected override void UpdateOpacity(bool initialize) + void UpdateColor(bool init) { - if (initialize && Element.Opacity == 1d) + if (init && Element.Color.IsDefault()) return; - UpdateColor(); - } - - void OnRadiusUpdate(bool init) - { - int topLeft = Forms.ConvertToScaledPixel(Element.CornerRadius.TopLeft); - int topRight = Forms.ConvertToScaledPixel(Element.CornerRadius.TopRight); - int bottomLeft = Forms.ConvertToScaledPixel(Element.CornerRadius.BottomLeft); - int bottomRight = Forms.ConvertToScaledPixel(Element.CornerRadius.BottomRight); - Control.SetRadius(topLeft, topRight, bottomLeft, bottomRight); - if (!init) - { - Control.Draw(); - } - } - - void UpdateColor() - { - if (Element.Color.IsDefault()) - { - if (Element.BackgroundColor.IsDefault()) - { - // Set to default color. (Transparent) - Control.Color = EColor.Transparent; - } - else - { - // Use BackgroundColor only if color is default and background color is not default. - Control.Color = Element.BackgroundColor.MultiplyAlpha((float)Element.Opacity).ToNative(); - } - } - else - { - // Color has higer priority than BackgroundColor. - Control.Color = Element.Color.MultiplyAlpha((float)Element.Opacity).ToNative(); - } + Control.UpdateBackgroundColor(!Element.Color.IsDefault() ? Element.Color.ToNative() : Element.BackgroundColor.ToNative()); } } } \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ButtonRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ButtonRenderer.cs deleted file mode 100644 index 8933fb8cfb30..000000000000 --- a/src/Compatibility/Core/src/Tizen/Renderers/ButtonRenderer.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System; -using Microsoft.Maui.Graphics; -using Microsoft.Maui.Controls.Platform; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; -using Microsoft.Maui.Devices; -using NIButton = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.IButton; -using EButton = ElmSharp.Button; -using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.VisualElement; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] - public class ButtonRenderer : ViewRenderer - { - public ButtonRenderer() - { - RegisterPropertyHandler(Button.TextProperty, UpdateText); - RegisterPropertyHandler(Button.FontFamilyProperty, UpdateFontFamily); - RegisterPropertyHandler(Button.FontSizeProperty, UpdateFontSize); - RegisterPropertyHandler(Button.FontAttributesProperty, UpdateFontAttributes); - RegisterPropertyHandler(Button.TextColorProperty, UpdateTextColor); - RegisterPropertyHandler(Button.ImageSourceProperty, UpdateBitmap); - RegisterPropertyHandler(Button.BorderColorProperty, UpdateBorder); - RegisterPropertyHandler(Button.CornerRadiusProperty, UpdateBorder); - RegisterPropertyHandler(Button.BorderWidthProperty, UpdateBorder); - } - - protected override void OnElementChanged(ElementChangedEventArgs