diff --git a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets index b077c57f7e..a9b30bac85 100644 --- a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets +++ b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets @@ -59,6 +59,12 @@ + + + + + + @@ -99,6 +105,11 @@ $(DefineConstants);MACCATALYST;IOS + + + $(DefineConstants);TIZEN + + @@ -120,4 +131,8 @@ + + + + diff --git a/.nuspec/Microsoft.Maui.Controls.SingleProject.props b/.nuspec/Microsoft.Maui.Controls.SingleProject.props index 52df01095c..2e565e39a9 100644 --- a/.nuspec/Microsoft.Maui.Controls.SingleProject.props +++ b/.nuspec/Microsoft.Maui.Controls.SingleProject.props @@ -16,4 +16,10 @@ <_MauiUsingDefaultRuntimeIdentifier>true + + + + + + diff --git a/.nuspec/Microsoft.Maui.Controls.SingleProject.targets b/.nuspec/Microsoft.Maui.Controls.SingleProject.targets index 9f2e22d371..484bfb0e70 100644 --- a/.nuspec/Microsoft.Maui.Controls.SingleProject.targets +++ b/.nuspec/Microsoft.Maui.Controls.SingleProject.targets @@ -22,6 +22,10 @@ false $(PlatformsProjectFolder)Windows\ $([MSBuild]::EnsureTrailingSlash('$(WindowsProjectFolder)')) + + false + $(PlatformsProjectFolder)Tizen\ + $([MSBuild]::EnsureTrailingSlash('$(TizenProjectFolder)')) @@ -29,6 +33,7 @@ + @@ -57,6 +62,12 @@ <_SingleProjectWindowsExcludes>$(WindowsProjectFolder)/**/.*/** + + $(TizenProjectFolder)tizen-manifest.xml + $(TizenProjectFolder)res + $(TizenProjectFolder)shared + + <_MauiXamlToRemove @@ -127,4 +141,4 @@ - \ No newline at end of file + diff --git a/.nuspec/Microsoft.Maui.Resizetizer.targets b/.nuspec/Microsoft.Maui.Resizetizer.targets index 6759cc6719..79c5eaf17a 100644 --- a/.nuspec/Microsoft.Maui.Resizetizer.targets +++ b/.nuspec/Microsoft.Maui.Resizetizer.targets @@ -33,6 +33,10 @@ AssemblyFile="$(_ResizetizerTaskAssemblyName)" TaskName="Microsoft.Maui.Resizetizer.GenerateSplashStoryboard" /> + + @@ -76,6 +80,7 @@ <_ResizetizerPlatformIsmacOS Condition="'$(_ResizetizerPlatformIdentifier)' == 'macos'">True <_ResizetizerPlatformIstvOS Condition="'$(_ResizetizerPlatformIdentifier)' == 'tvos'">True <_ResizetizerPlatformIsWindows Condition="$(_ResizetizerPlatformIdentifier.Contains('windows')) == 'True'">True + <_ResizetizerPlatformIsTizen Condition="'$(_ResizetizerPlatformIdentifier)' == 'tizen'">True False @@ -90,9 +95,10 @@ <_ResizetizerIsiOSApp Condition="( '$(_ResizetizerPlatformIsiOS)' == 'True' OR '$(_ResizetizerPlatformIsMacCatalyst)' == 'True' ) And ('$(OutputType)' == 'Exe' Or '$(IsAppExtension)' == 'True')">True <_ResizetizerIsWPFApp Condition="'$(IsApplication)' == 'True' And '$(NuGetRuntimeIdentifier)' == 'win' And '$(_ResizetizerPlatformIsWindows)' == 'True'">True <_ResizetizerIsWindowsAppSdk Condition="('$(ProjectReunionWinUI)'=='True' Or '$(WindowsAppSDKWinUI)'=='True') And '$(_ResizetizerPlatformIsWindows)' == 'True' And ('$(OutputType)' == 'WinExe' Or '$(OutputType)' == 'Exe')">True + <_ResizetizerIsTizenApp Condition="'$(_ResizetizerPlatformIsTizen)' == 'True'">True - + <_ResizetizerIsCompatibleApp>True @@ -190,10 +196,29 @@ + + + tizen + + + $(ResizetizeBeforeTargets); + PrepareResources; + + + + $(ResizetizeAfterTargets); + ResizetizeCollectItems; + + + + $(ProcessMauiFontsAfterTargets); + ResizetizeCollectItems; + + + - @@ -295,6 +320,12 @@ + + <_MauiAssetItemMetadata>TizenTpkFileName + + + + + @@ -348,7 +380,7 @@ <_MauiSplashAssets Include="$(_MauiIntermediateSplashScreen)**\*" /> @@ -358,6 +390,11 @@ + + + + + @@ -437,6 +474,11 @@ + + + + + @@ -479,6 +521,13 @@ Images="@(MauiImage->Distinct())"> + + + @@ -548,6 +597,20 @@ + + + $([System.IO.Path]::GetFullPath('$(_MauiIntermediateImages)')) + + + + + + + $([MSBuild]::MakeRelative($(ResizetizerIntermediateOutputAbsolutePath), $([System.IO.Path]::GetFullPath('%(_ResizetizerCollectedImages.RelativeDir)')))) + + + + @@ -602,4 +665,4 @@ - \ No newline at end of file + diff --git a/Directory.Build.props b/Directory.Build.props index 55301d5489..42d747e774 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,8 +12,12 @@ <_MauiTargetPlatformIsmacOS Condition="'$(_MauiTargetPlatformIdentifier)' == 'macos'">True <_MauiTargetPlatformIstvOS Condition="'$(_MauiTargetPlatformIdentifier)' == 'tvos'">True <_MauiTargetPlatformIsWindows Condition="$(_MauiTargetPlatformIdentifier.Contains('windows')) == 'True'">True + <_MauiTargetPlatformIsTizen Condition="'$(_MauiTargetPlatformIdentifier)' == 'tizen'">True true + true @@ -34,6 +38,7 @@ 30.0 10.0.19041 10.0.20348 + 6.5 @@ -41,6 +46,7 @@ net$(_MauiDotNetVersion)-ios;net$(_MauiDotNetVersion)-maccatalyst;net$(_MauiDotNetVersion)-android net$(_MauiDotNetVersion)-windows$(WindowsTargetFrameworkVersion);net$(_MauiDotNetVersion)-windows$(Windows2TargetFrameworkVersion) $(MauiPlatforms);$(WindowsMauiPlatforms) + $(MauiPlatforms);net$(_MauiDotNetVersion)-tizen net$(_MauiDotNetVersion)-ios;net$(_MauiDotNetVersion)-android diff --git a/Directory.Build.targets b/Directory.Build.targets index e1c4eda5c7..dc0e3527e7 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -33,6 +33,10 @@ 21.0 21.0 + + 6.5 + 6.5 + 6.0.4 $(MicrosoftNETWorkloadEmscriptenManifest60300PackageVersion) @@ -49,6 +50,7 @@ 1.0.0-prerelease.22211.4 1.0.0-prerelease.22211.4 1.0.0-prerelease.22211.4 + 0.6.0-pre1 @@ -60,5 +62,6 @@ $(DotNetVersionBand) $(DotNetVersionBand) $(DotNetVersionBand) + $(DotNetVersionBand) diff --git a/eng/pipelines/common/provision.yml b/eng/pipelines/common/provision.yml index 6fc8f5948b..937ae99787 100644 --- a/eng/pipelines/common/provision.yml +++ b/eng/pipelines/common/provision.yml @@ -107,6 +107,14 @@ steps: displayName: 'Setup MSBuild Paths' condition: eq(variables['provisioningVS'], 'true') + - pwsh: | + [xml] $fileXml = Get-Content "eng\Versions.props" + $DotNetVersionBand = $fileXml.SelectSingleNode("Project/PropertyGroup/DotNetVersionBand").InnerText + echo "Installing .NET $DotNetVersion" + Invoke-WebRequest 'https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.ps1' -OutFile 'workload-install.ps1' + .\workload-install.ps1 -t $DotNetVersion + displayName: 'Install Tizen' + # Prepare Both - pwsh: ./build.ps1 --target provision displayName: 'Cake Provision' diff --git a/src/BlazorWebView/src/Maui/PublicAPI/net6.0-tizen/PublicAPI.Shipped.txt b/src/BlazorWebView/src/Maui/PublicAPI/net6.0-tizen/PublicAPI.Shipped.txt new file mode 100644 index 0000000000..ab058de62d --- /dev/null +++ b/src/BlazorWebView/src/Maui/PublicAPI/net6.0-tizen/PublicAPI.Shipped.txt @@ -0,0 +1 @@ +#nullable enable diff --git a/src/BlazorWebView/src/Maui/PublicAPI/net6.0-tizen/PublicAPI.Unshipped.txt b/src/BlazorWebView/src/Maui/PublicAPI/net6.0-tizen/PublicAPI.Unshipped.txt new file mode 100644 index 0000000000..21bd2d4a2a --- /dev/null +++ b/src/BlazorWebView/src/Maui/PublicAPI/net6.0-tizen/PublicAPI.Unshipped.txt @@ -0,0 +1,63 @@ +#nullable enable +Microsoft.AspNetCore.Components.WebView.BlazorWebViewInitializedEventArgs +Microsoft.AspNetCore.Components.WebView.BlazorWebViewInitializedEventArgs.BlazorWebViewInitializedEventArgs() -> void +Microsoft.AspNetCore.Components.WebView.BlazorWebViewInitializingEventArgs +Microsoft.AspNetCore.Components.WebView.BlazorWebViewInitializingEventArgs.BlazorWebViewInitializingEventArgs() -> void +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.BlazorWebView() -> void +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.BlazorWebViewInitialized -> System.EventHandler? +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.BlazorWebViewInitializing -> System.EventHandler? +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.HostPage.get -> string? +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.HostPage.set -> void +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.RootComponents.get -> Microsoft.AspNetCore.Components.WebView.Maui.RootComponentsCollection! +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.UrlLoading -> System.EventHandler? +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.BlazorWebViewHandler() -> void +Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.BlazorWebViewHandler(Microsoft.Maui.PropertyMapper? mapper) -> void +Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView +Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.BlazorWebViewInitialized(Microsoft.AspNetCore.Components.WebView.BlazorWebViewInitializedEventArgs! args) -> void +Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.BlazorWebViewInitializing(Microsoft.AspNetCore.Components.WebView.BlazorWebViewInitializingEventArgs! args) -> void +Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.CreateFileProvider(string! contentRootDir) -> Microsoft.Extensions.FileProviders.IFileProvider! +Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.HostPage.get -> string? +Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.JSComponents.get -> Microsoft.AspNetCore.Components.Web.JSComponentConfigurationStore! +Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.RootComponents.get -> Microsoft.AspNetCore.Components.WebView.Maui.RootComponentsCollection! +Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView.UrlLoading(Microsoft.AspNetCore.Components.WebView.UrlLoadingEventArgs! args) -> void +Microsoft.AspNetCore.Components.WebView.Maui.IMauiBlazorWebViewBuilder +Microsoft.AspNetCore.Components.WebView.Maui.IMauiBlazorWebViewBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +Microsoft.AspNetCore.Components.WebView.Maui.RootComponent +Microsoft.AspNetCore.Components.WebView.Maui.RootComponent.ComponentType.get -> System.Type? +Microsoft.AspNetCore.Components.WebView.Maui.RootComponent.ComponentType.set -> void +Microsoft.AspNetCore.Components.WebView.Maui.RootComponent.Parameters.get -> System.Collections.Generic.IDictionary? +Microsoft.AspNetCore.Components.WebView.Maui.RootComponent.Parameters.set -> void +Microsoft.AspNetCore.Components.WebView.Maui.RootComponent.RootComponent() -> void +Microsoft.AspNetCore.Components.WebView.Maui.RootComponent.Selector.get -> string? +Microsoft.AspNetCore.Components.WebView.Maui.RootComponent.Selector.set -> void +Microsoft.AspNetCore.Components.WebView.Maui.RootComponentsCollection +Microsoft.AspNetCore.Components.WebView.Maui.RootComponentsCollection.JSComponents.get -> Microsoft.AspNetCore.Components.Web.JSComponentConfigurationStore! +Microsoft.AspNetCore.Components.WebView.Maui.RootComponentsCollection.RootComponentsCollection(Microsoft.AspNetCore.Components.Web.JSComponentConfigurationStore! jsComponents) -> void +Microsoft.AspNetCore.Components.WebView.Maui.TizenWebViewManager +Microsoft.AspNetCore.Components.WebView.Maui.TizenWebViewManager.TizenWebViewManager(Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler! blazorMauiWebViewHandler, Tizen.WebView.WebView! webview, System.IServiceProvider! provider, Microsoft.AspNetCore.Components.Dispatcher! dispatcher, Microsoft.Extensions.FileProviders.IFileProvider! fileProvider, Microsoft.AspNetCore.Components.Web.JSComponentConfigurationStore! jsComponents, string! contentRootRelativeToAppRoot, string! hostPageRelativePath) -> void +override Microsoft.AspNetCore.Components.WebView.Maui.TizenWebViewManager.NavigateCore(System.Uri! absoluteUri) -> void +override Microsoft.AspNetCore.Components.WebView.Maui.TizenWebViewManager.SendMessage(string! message) -> void +Microsoft.AspNetCore.Components.WebView.Maui.WebViewContainer +Microsoft.AspNetCore.Components.WebView.Maui.WebViewContainer.WebViewContainer(ElmSharp.EvasObject! parent) -> void +Microsoft.AspNetCore.Components.WebView.Maui.WebViewContainer.WebView.get -> Tizen.WebView.WebView! +Microsoft.AspNetCore.Components.WebView.UrlLoadingEventArgs +Microsoft.AspNetCore.Components.WebView.UrlLoadingEventArgs.Url.get -> System.Uri! +Microsoft.AspNetCore.Components.WebView.UrlLoadingEventArgs.UrlLoadingStrategy.get -> Microsoft.AspNetCore.Components.WebView.UrlLoadingStrategy +Microsoft.AspNetCore.Components.WebView.UrlLoadingEventArgs.UrlLoadingStrategy.set -> void +Microsoft.AspNetCore.Components.WebView.UrlLoadingStrategy +Microsoft.AspNetCore.Components.WebView.UrlLoadingStrategy.CancelLoad = 2 -> Microsoft.AspNetCore.Components.WebView.UrlLoadingStrategy +Microsoft.AspNetCore.Components.WebView.UrlLoadingStrategy.OpenExternally = 0 -> Microsoft.AspNetCore.Components.WebView.UrlLoadingStrategy +Microsoft.AspNetCore.Components.WebView.UrlLoadingStrategy.OpenInWebView = 1 -> Microsoft.AspNetCore.Components.WebView.UrlLoadingStrategy +Microsoft.Extensions.DependencyInjection.BlazorWebViewServiceCollectionExtensions +override Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.CreatePlatformView() -> Microsoft.AspNetCore.Components.WebView.Maui.WebViewContainer! +override Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.ConnectHandler(Microsoft.AspNetCore.Components.WebView.Maui.WebViewContainer! platformView) -> void +override Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.DisconnectHandler(Microsoft.AspNetCore.Components.WebView.Maui.WebViewContainer! platformView) -> void +static Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.MapHostPage(Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler! handler, Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView! webView) -> void +static Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.MapRootComponents(Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler! handler, Microsoft.AspNetCore.Components.WebView.Maui.IBlazorWebView! webView) -> void +static Microsoft.Extensions.DependencyInjection.BlazorWebViewServiceCollectionExtensions.AddBlazorWebViewDeveloperTools(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! +static Microsoft.Extensions.DependencyInjection.BlazorWebViewServiceCollectionExtensions.AddMauiBlazorWebView(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.AspNetCore.Components.WebView.Maui.IMauiBlazorWebViewBuilder! +static Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebViewHandler.BlazorWebViewMapper -> Microsoft.Maui.PropertyMapper! +virtual Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView.CreateFileProvider(string! contentRootDir) -> Microsoft.Extensions.FileProviders.IFileProvider! +~Microsoft.AspNetCore.Components.WebView.BlazorWebViewInitializedEventArgs.WebView.get -> Tizen.WebView.WebView diff --git a/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs new file mode 100644 index 0000000000..8e5f94930a --- /dev/null +++ b/src/BlazorWebView/src/Maui/Tizen/BlazorWebViewHandler.Tizen.cs @@ -0,0 +1,192 @@ +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 TChromium = Tizen.WebView.Chromium; +using TWebView = Tizen.WebView.WebView; + +namespace Microsoft.AspNetCore.Components.WebView.Maui +{ + /// + /// The Tizen for . + /// + public partial class BlazorWebViewHandler : ViewHandler + { + private const string AppOrigin = "http://0.0.0.0/"; + private const string BlazorInitScript = @" + window.__receiveMessageCallbacks = []; + window.__dispatchMessageCallback = function(message) { + window.__receiveMessageCallbacks.forEach(function(callback) { callback(message); }); + }; + window.external = { + sendMessage: function(message) { + window.BlazorHandler.postMessage(message); + }, + receiveMessage: function(callback) { + window.__receiveMessageCallbacks.push(callback); + } + }; + + Blazor.start(); + + (function () { + window.onpageshow = function(event) { + if (event.persisted) { + window.location.reload(); + } + }; + })(); + "; + + private TizenWebViewManager? _webviewManager; + private WebViewExtensions.InterceptRequestCallback? _interceptRequestCallback; + + private TWebView NativeWebView => PlatformView.WebView; + + private bool RequiredStartupPropertiesSet => + //_webview != null && + HostPage != null && + Services != null; + + /// + protected override WebViewContainer CreatePlatformView() + { + TChromium.Initialize(); + MauiApplication.Current.Terminated += (s, e) => TChromium.Shutdown(); + + return new WebViewContainer(NativeParent!); + } + + /// + protected override void ConnectHandler(WebViewContainer platformView) + { + _interceptRequestCallback = OnRequestInterceptCallback; + NativeWebView.LoadFinished += OnLoadFinished; + NativeWebView.AddJavaScriptMessageHandler("BlazorHandler", PostMessageFromJS); + NativeWebView.SetInterceptRequestCallback(_interceptRequestCallback); + NativeWebView.GetSettings().JavaScriptEnabled = true; + } + + /// + protected override void DisconnectHandler(WebViewContainer platformView) + { + NativeWebView.LoadFinished -= OnLoadFinished; + base.DisconnectHandler(platformView); + } + + private 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 || + _webviewManager != null) + { + return; + } + if (PlatformView == null) + { + throw new InvalidOperationException($"Can't start {nameof(BlazorWebView)} without platform web view instance."); + } + + // We assume the host page is always in the root of the content directory, because it's + // 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 fileProvider = VirtualView.CreateFileProvider(contentRootDir); + + _webviewManager = new TizenWebViewManager( + this, + NativeWebView, + Services!, + new MauiDispatcher(Services!.GetRequiredService()), + fileProvider, + VirtualView.JSComponents, + contentRootDir, + hostPageRelativePath); + + StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager); + + VirtualView.BlazorWebViewInitializing(new BlazorWebViewInitializingEventArgs()); + VirtualView.BlazorWebViewInitialized(new BlazorWebViewInitializedEventArgs + { + WebView = NativeWebView, + }); + + if (RootComponents != null) + { + foreach (var rootComponent in RootComponents) + { + // Since the page isn't loaded yet, this will always complete synchronously + _ = rootComponent.AddToWebViewManagerAsync(_webviewManager); + } + } + _webviewManager.Navigate("/"); + } + + private void OnRequestInterceptCallback(IntPtr context, IntPtr request, IntPtr userdata) + { + if (request == IntPtr.Zero) + { + return; + } + + var url = NativeWebView.GetInterceptRequestUrl(request); + + if (url.StartsWith(AppOrigin)) + { + var allowFallbackOnHostPage = url.EndsWith("/"); + url = QueryStringHelper.RemovePossibleQueryString(url); + if (_webviewManager!.TryGetResponseContentInternal(url, allowFallbackOnHostPage, out var statusCode, out var statusMessage, out var content, out var headers)) + { + var header = $"HTTP/1.0 200 OK\r\n"; + foreach (var item in headers) + { + header += $"{item.Key}:{item.Value}\r\n"; + } + header += "\r\n"; + + using (MemoryStream memstream = new MemoryStream()) + { + content.CopyTo(memstream); + var body = memstream.ToArray(); + NativeWebView.SetInterceptRequestResponse(request, header, body, (uint)body.Length); + } + return; + } + } + + NativeWebView.IgnoreInterceptRequest(request); + } + + private void OnLoadFinished(object? sender, EventArgs e) + { + NativeWebView.SetFocus(true); + var url = NativeWebView.Url; + + if (url == AppOrigin) + NativeWebView.Eval(BlazorInitScript); + } + + internal IFileProvider CreateFileProvider(string contentRootDir) + { + return new TizenMauiAssetFileProvider(contentRootDir); + } + + } +} diff --git a/src/BlazorWebView/src/Maui/Tizen/TizenMauiAssetFileProvider.cs b/src/BlazorWebView/src/Maui/Tizen/TizenMauiAssetFileProvider.cs new file mode 100644 index 0000000000..dd5824fa32 --- /dev/null +++ b/src/BlazorWebView/src/Maui/Tizen/TizenMauiAssetFileProvider.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Primitives; +using Tizen.Applications; + +namespace Microsoft.AspNetCore.Components.WebView.Maui +{ + /// + /// A minimal implementation of an IFileProvider to be used by the BlazorWebView and WebViewManager types. + /// + internal sealed class TizenMauiAssetFileProvider : IFileProvider + { + private readonly string _resDir; + + public TizenMauiAssetFileProvider(string contentRootDir) + { + _resDir = Path.Combine(Application.Current.DirectoryInfo.Resource, contentRootDir); + } + + public IDirectoryContents GetDirectoryContents(string subpath) + => new TizenMauiAssetDirectoryContents(Path.Combine(_resDir, subpath)); + + public IFileInfo GetFileInfo(string subpath) + => new TizenMauiAssetFileInfo(Path.Combine(_resDir, subpath)); + + public IChangeToken? Watch(string filter) + => null; + + private sealed class TizenMauiAssetFileInfo : IFileInfo + { + private readonly string _filePath; + + public TizenMauiAssetFileInfo(string filePath) + { + _filePath = filePath; + + Name = Path.GetFileName(_filePath); + + var fileInfo = new FileInfo(_filePath); + Exists = fileInfo.Exists; + Length = Exists ? fileInfo.Length : -1; + } + + public bool Exists { get; } + public long Length { get; } + public string PhysicalPath { get; } = null!; + public string Name { get; } + public DateTimeOffset LastModified { get; } = DateTimeOffset.FromUnixTimeSeconds(0); + public bool IsDirectory => false; + + public Stream CreateReadStream() + => File.OpenRead(_filePath); + } + + // This is never used by BlazorWebView or WebViewManager + private sealed class TizenMauiAssetDirectoryContents : IDirectoryContents + { + public TizenMauiAssetDirectoryContents(string filePath) + { + } + + public bool Exists => false; + + public IEnumerator GetEnumerator() + => throw new NotImplementedException(); + + IEnumerator IEnumerable.GetEnumerator() + => throw new NotImplementedException(); + } + } +} diff --git a/src/BlazorWebView/src/Maui/Tizen/TizenWebViewManager.cs b/src/BlazorWebView/src/Maui/Tizen/TizenWebViewManager.cs new file mode 100644 index 0000000000..967fe158ca --- /dev/null +++ b/src/BlazorWebView/src/Maui/Tizen/TizenWebViewManager.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.Extensions.FileProviders; +using TWebView = Tizen.WebView.WebView; + +namespace Microsoft.AspNetCore.Components.WebView.Maui +{ + /// + /// An implementation of that uses the Tizen WebView browser control + /// to render web content. + /// + public class TizenWebViewManager : WebViewManager + { + private const string AppOrigin = "http://0.0.0.0/"; + + private readonly BlazorWebViewHandler _blazorMauiWebViewHandler; + private readonly TWebView _webview; + private readonly string _contentRootRelativeToAppRoot; + + /// + /// Initializes a new instance of + /// + /// The . + /// A wrapper to access platform-specific WebView APIs. + /// The for the application. + /// A instance instance that can marshal calls to the required thread or sync context. + /// Provides static content to the webview. + /// Describes configuration for adding, removing, and updating root components from JavaScript code. + /// Path to the directory containing application content files. + /// Path to the host page within the fileProvider. + public TizenWebViewManager(BlazorWebViewHandler blazorMauiWebViewHandler, TWebView webview, IServiceProvider provider, Dispatcher dispatcher, IFileProvider fileProvider, JSComponentConfigurationStore jsComponents, string contentRootRelativeToAppRoot, string hostPageRelativePath) + : base(provider, dispatcher, new Uri(AppOrigin), fileProvider, jsComponents, hostPageRelativePath) + { + _blazorMauiWebViewHandler = blazorMauiWebViewHandler ?? throw new ArgumentNullException(nameof(blazorMauiWebViewHandler)); + _webview = webview ?? throw new ArgumentNullException(nameof(webview)); + _contentRootRelativeToAppRoot = contentRootRelativeToAppRoot; + + } + + internal bool TryGetResponseContentInternal(string uri, bool allowFallbackOnHostPage, out int statusCode, out string statusMessage, out Stream content, out IDictionary headers) + { + var defaultResult = TryGetResponseContent(uri, allowFallbackOnHostPage, out statusCode, out statusMessage, out content, out headers); + var hotReloadedResult = StaticContentHotReloadManager.TryReplaceResponseContent(_contentRootRelativeToAppRoot, uri, ref statusCode, ref content, headers); + return defaultResult || hotReloadedResult; + } + + + /// + protected override void NavigateCore(Uri absoluteUri) + { + _webview.LoadUrl(absoluteUri.ToString()); + } + + /// + protected override void SendMessage(string message) + { + var messageJSStringLiteral = JavaScriptEncoder.Default.Encode(message); + _webview.Eval($"__dispatchMessageCallback(\"{messageJSStringLiteral}\")"); + } + + internal void MessageReceivedInternal(Uri uri, string message) + { + MessageReceived(uri, message); + } + } +} diff --git a/src/BlazorWebView/src/Maui/Tizen/WebViewContainer.cs b/src/BlazorWebView/src/Maui/Tizen/WebViewContainer.cs new file mode 100644 index 0000000000..52b3a3423f --- /dev/null +++ b/src/BlazorWebView/src/Maui/Tizen/WebViewContainer.cs @@ -0,0 +1,42 @@ +using System; +using Tizen.UIExtensions.ElmSharp; +using ElmSharp; +using TWebView = Tizen.WebView.WebView; + +namespace Microsoft.AspNetCore.Components.WebView.Maui +{ + /// + /// A Tizen WebView browser control container. + /// + public class WebViewContainer : WidgetLayout + { + + /// + /// A Tizen WebView. + /// + public TWebView WebView { get; } + + /// + /// Initializes a new instance of + /// + /// The . + 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/BlazorWebView/src/Maui/Tizen/WebViewExtensions.cs b/src/BlazorWebView/src/Maui/Tizen/WebViewExtensions.cs new file mode 100644 index 0000000000..4150989f10 --- /dev/null +++ b/src/BlazorWebView/src/Maui/Tizen/WebViewExtensions.cs @@ -0,0 +1,79 @@ +using System; +using System.Runtime.InteropServices; +using TWebView = Tizen.WebView.WebView; + +namespace Microsoft.AspNetCore.Components.WebView.Maui +{ + /// + /// WebViewExtension + /// + internal static class WebViewExtensions + { + 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); + } + + 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, byte[] body, uint length) + { + return ewk_intercept_request_response_set(request, header, body, length); + } + + public static bool IgnoreInterceptRequest(this TWebView webView, IntPtr request) + { + return ewk_intercept_request_ignore(request); + } + + public static string GetInterceptRequestUrl(this TWebView webView, IntPtr request) + { + 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)] + 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); + + [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); + } +} diff --git a/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializedEventArgs.cs b/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializedEventArgs.cs index e8d124cac0..a7de76a6af 100644 --- a/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializedEventArgs.cs +++ b/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializedEventArgs.cs @@ -13,6 +13,8 @@ using WebView2Control = Microsoft.UI.Xaml.Controls.WebView2; using AWebView = Android.Webkit.WebView; #elif IOS || MACCATALYST using WebKit; +#elif TIZEN +using TWebView = Tizen.WebView.WebView; #endif namespace Microsoft.AspNetCore.Components.WebView @@ -39,6 +41,11 @@ namespace Microsoft.AspNetCore.Components.WebView /// the default values to allow further configuring additional options. /// public WKWebView WebView { get; internal set; } +#elif TIZEN + /// + /// Gets the instance that was initialized. + /// + public TWebView WebView { get; internal set; } #endif } } diff --git a/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializingEventArgs.cs b/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializingEventArgs.cs index dc11d075e8..f14ccd6564 100644 --- a/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializingEventArgs.cs +++ b/src/BlazorWebView/src/SharedSource/BlazorWebViewInitializingEventArgs.cs @@ -12,6 +12,8 @@ using WebView2Control = Microsoft.UI.Xaml.Controls.WebView2; using AWebView = Android.Webkit.WebView; #elif IOS || MACCATALYST using WebKit; +#elif TIZEN +using TWebView = Tizen.WebView.WebView; #endif namespace Microsoft.AspNetCore.Components.WebView diff --git a/src/Compatibility/ControlGallery/src/Core/Startup.cs b/src/Compatibility/ControlGallery/src/Core/Startup.cs index 2c0044972a..ffd97ef433 100644 --- a/src/Compatibility/ControlGallery/src/Core/Startup.cs +++ b/src/Compatibility/ControlGallery/src/Core/Startup.cs @@ -4,6 +4,7 @@ using Microsoft.Maui; using Microsoft.Maui.Controls.Compatibility; using Microsoft.Maui.Controls.Compatibility.Hosting; using Microsoft.Maui.Controls.Hosting; +using Microsoft.Maui.Devices; using Microsoft.Maui.Hosting; namespace Microsoft.Maui.Controls.Compatibility.ControlGallery @@ -41,6 +42,12 @@ namespace Microsoft.Maui.Controls.Compatibility.ControlGallery effects.AddCompatibilityEffects(AppDomain.CurrentDomain.GetAssemblies()); }); + if (DeviceInfo.Platform == DevicePlatform.Tizen) + { + //Some controls still need to use legacy renderers on Tizen. + builder.UseMauiCompatibility(); + } + DependencyService.Register(AppDomain.CurrentDomain.GetAssemblies()); return builder; diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/BorderEffect.cs b/src/Compatibility/ControlGallery/src/Tizen/BorderEffect.cs similarity index 69% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/BorderEffect.cs rename to src/Compatibility/ControlGallery/src/Tizen/BorderEffect.cs index 786ad812e7..66d95efcbd 100644 --- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/BorderEffect.cs +++ b/src/Compatibility/ControlGallery/src/Tizen/BorderEffect.cs @@ -1,12 +1,13 @@ using System.ComponentModel; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +using Microsoft.Maui.Controls.Platform; using ElmSharp; -using Xamarin.Forms; -using Xamarin.Forms.ControlGallery.Tizen; -using Xamarin.Forms.Platform.Tizen; using EColor = ElmSharp.Color; [assembly: ExportEffect(typeof(BorderEffect), "BorderEffect")] -namespace Xamarin.Forms.ControlGallery.Tizen +namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen { public class BorderEffect : PlatformEffect { diff --git a/src/Compatibility/ControlGallery/src/Tizen/Compatibility.ControlGallery.Tizen.csproj b/src/Compatibility/ControlGallery/src/Tizen/Compatibility.ControlGallery.Tizen.csproj new file mode 100644 index 0000000000..41ea8acb66 --- /dev/null +++ b/src/Compatibility/ControlGallery/src/Tizen/Compatibility.ControlGallery.Tizen.csproj @@ -0,0 +1,38 @@ + + + + $(_MauiDotNetTfm)-tizen + Exe + Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen + Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen + false + disable + + + 0612 + + + + + + + + + + + + + + + + + + + diff --git a/src/Compatibility/ControlGallery/src/Tizen/ControlGallery.Tizen.cs b/src/Compatibility/ControlGallery/src/Tizen/ControlGallery.Tizen.cs new file mode 100644 index 0000000000..c8c6b95594 --- /dev/null +++ b/src/Compatibility/ControlGallery/src/Tizen/ControlGallery.Tizen.cs @@ -0,0 +1,32 @@ +using ElmSharp; +using Tizen.Applications; +using Tizen.NET.MaterialComponents; +using Microsoft.Maui.Controls.Compatibility.ControlGallery; +using Microsoft.Maui.Controls.Compatibility.ControlGallery.Issues; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Handlers; +using Microsoft.Maui.Hosting; +using Microsoft.Maui.Platform; + +namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen +{ + class MainApplication : MauiApplication + { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + + protected override void OnCreate() + { + base.OnCreate(); + MaterialComponents.Init(DirectoryInfo.Resource); + } + + static void Main(string[] args) + { + var app = new MainApplication(); + FormsMaps.Init("HERE", "write-your-API-key-here"); + //FormsMaterial.Init(); + app.Run(args); + } + } +} diff --git a/src/Compatibility/ControlGallery/src/Tizen/DisposeLabelRenderer.cs b/src/Compatibility/ControlGallery/src/Tizen/DisposeLabelRenderer.cs new file mode 100644 index 0000000000..a56b2ce2a2 --- /dev/null +++ b/src/Compatibility/ControlGallery/src/Tizen/DisposeLabelRenderer.cs @@ -0,0 +1,22 @@ +using Microsoft.Maui.Controls.Compatibility; +using Microsoft.Maui.Controls.Compatibility.ControlGallery; +using Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; + +[assembly: ExportRenderer(typeof(DisposeLabel), typeof(DisposeLabelRenderer))] +namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen +{ +#pragma warning disable CS0618 // Type or member is obsolete + public class DisposeLabelRenderer : LabelRenderer +#pragma warning disable CS0618 // Type or member is obsolete + { + protected override void Dispose(bool disposing) + { + if (disposing) + { + ((DisposeLabel)Element).SendRendererDisposed(); + } + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/src/Tizen/DisposePageRenderer.cs b/src/Compatibility/ControlGallery/src/Tizen/DisposePageRenderer.cs new file mode 100644 index 0000000000..9067c3f1e6 --- /dev/null +++ b/src/Compatibility/ControlGallery/src/Tizen/DisposePageRenderer.cs @@ -0,0 +1,22 @@ +using Microsoft.Maui.Controls.Compatibility; +using Microsoft.Maui.Controls.Compatibility.ControlGallery; +using Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; + +[assembly: ExportRenderer(typeof(DisposePage), typeof(DisposePageRenderer))] +namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen +{ +#pragma warning disable CS0618 // Type or member is obsolete + public class DisposePageRenderer : PageRenderer +#pragma warning disable CS0618 // Type or member is obsolete + { + protected override void Dispose(bool disposing) + { + if (disposing) + { + ((DisposePage)Element).SendRendererDisposed(); + } + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/PlatformSpecificCoreGalleryFactory.cs b/src/Compatibility/ControlGallery/src/Tizen/PlatformSpecificCoreGalleryFactory.cs similarity index 57% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/PlatformSpecificCoreGalleryFactory.cs rename to src/Compatibility/ControlGallery/src/Tizen/PlatformSpecificCoreGalleryFactory.cs index 04d6275344..12a0d7aadd 100644 --- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/PlatformSpecificCoreGalleryFactory.cs +++ b/src/Compatibility/ControlGallery/src/Tizen/PlatformSpecificCoreGalleryFactory.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; -using Xamarin.Forms; -using Xamarin.Forms.ControlGallery.Tizen; -using Xamarin.Forms.Controls; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Compatibility; +using Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen; +using Microsoft.Maui.Controls.Internals; [assembly: Dependency(typeof(PlatformSpecificCoreGalleryFactory))] -namespace Xamarin.Forms.ControlGallery.Tizen +namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen { public class PlatformSpecificCoreGalleryFactory : IPlatformSpecificCoreGalleryFactory { diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/RegistrarValidationService.cs b/src/Compatibility/ControlGallery/src/Tizen/RegistrarValidationService.cs similarity index 65% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/RegistrarValidationService.cs rename to src/Compatibility/ControlGallery/src/Tizen/RegistrarValidationService.cs index 57ae24f7e0..1d029d5eec 100644 --- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/RegistrarValidationService.cs +++ b/src/Compatibility/ControlGallery/src/Tizen/RegistrarValidationService.cs @@ -1,10 +1,11 @@ -using Xamarin.Forms; -using Xamarin.Forms.ControlGallery.Tizen; -using Xamarin.Forms.Controls; -using Xamarin.Forms.Platform.Tizen; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Compatibility; +using Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +using Microsoft.Maui.Controls.Internals; [assembly: Dependency(typeof(RegistrarValidationService))] -namespace Xamarin.Forms.ControlGallery.Tizen +namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen { public class RegistrarValidationService : IRegistrarValidationService { diff --git a/src/Compatibility/ControlGallery/src/Tizen/SampleNativeControl.cs b/src/Compatibility/ControlGallery/src/Tizen/SampleNativeControl.cs new file mode 100644 index 0000000000..e2c11508fa --- /dev/null +++ b/src/Compatibility/ControlGallery/src/Tizen/SampleNativeControl.cs @@ -0,0 +1,27 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Compatibility; +using Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen; +using Microsoft.Maui.Controls.Compatibility.ControlGallery.Issues.Helpers; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Platform; +using ELabel = ElmSharp.Label; + +[assembly: Dependency(typeof(SampleNativeControl))] +namespace Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen +{ + public class SampleNativeControl : ISampleNativeControl + { + public View View + { + get + { + var label = new ELabel(CoreAppExtensions.MainWindow) + { + Text = "Sample Native Control" + }; + return label.ToView(); + } + } + } +} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/FlowerBuds.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/FlowerBuds.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/FlowerBuds.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/FlowerBuds.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Fruits.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/Fruits.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Fruits.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/Fruits.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Icon-Small.png b/src/Compatibility/ControlGallery/src/Tizen/res/Icon-Small.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Icon-Small.png rename to src/Compatibility/ControlGallery/src/Tizen/res/Icon-Small.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Icon.png b/src/Compatibility/ControlGallery/src/Tizen/res/Icon.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Icon.png rename to src/Compatibility/ControlGallery/src/Tizen/res/Icon.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Intranet-icon.png b/src/Compatibility/ControlGallery/src/Tizen/res/Intranet-icon.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Intranet-icon.png rename to src/Compatibility/ControlGallery/src/Tizen/res/Intranet-icon.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Legumes.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/Legumes.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Legumes.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/Legumes.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Vegetables.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/Vegetables.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/Vegetables.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/Vegetables.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/about.png b/src/Compatibility/ControlGallery/src/Tizen/res/about.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/about.png rename to src/Compatibility/ControlGallery/src/Tizen/res/about.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/bank.png b/src/Compatibility/ControlGallery/src/Tizen/res/bank.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/bank.png rename to src/Compatibility/ControlGallery/src/Tizen/res/bank.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/bell.png b/src/Compatibility/ControlGallery/src/Tizen/res/bell.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/bell.png rename to src/Compatibility/ControlGallery/src/Tizen/res/bell.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/blog.png b/src/Compatibility/ControlGallery/src/Tizen/res/blog.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/blog.png rename to src/Compatibility/ControlGallery/src/Tizen/res/blog.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/books.png b/src/Compatibility/ControlGallery/src/Tizen/res/books.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/books.png rename to src/Compatibility/ControlGallery/src/Tizen/res/books.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/booksflyout.png b/src/Compatibility/ControlGallery/src/Tizen/res/booksflyout.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/booksflyout.png rename to src/Compatibility/ControlGallery/src/Tizen/res/booksflyout.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/calculator.png b/src/Compatibility/ControlGallery/src/Tizen/res/calculator.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/calculator.png rename to src/Compatibility/ControlGallery/src/Tizen/res/calculator.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/card.png b/src/Compatibility/ControlGallery/src/Tizen/res/card.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/card.png rename to src/Compatibility/ControlGallery/src/Tizen/res/card.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/caret_r.png b/src/Compatibility/ControlGallery/src/Tizen/res/caret_r.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/caret_r.png rename to src/Compatibility/ControlGallery/src/Tizen/res/caret_r.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/coffee.png b/src/Compatibility/ControlGallery/src/Tizen/res/coffee.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/coffee.png rename to src/Compatibility/ControlGallery/src/Tizen/res/coffee.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/cover1.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/cover1.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/cover1.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/cover1.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/cover1small.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/cover1small.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/cover1small.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/cover1small.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/crimson.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/crimson.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/crimson.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/crimson.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/crimsonsmall.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/crimsonsmall.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/crimsonsmall.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/crimsonsmall.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/facebook.png b/src/Compatibility/ControlGallery/src/Tizen/res/facebook.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/facebook.png rename to src/Compatibility/ControlGallery/src/Tizen/res/facebook.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/favorite.png b/src/Compatibility/ControlGallery/src/Tizen/res/favorite.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/favorite.png rename to src/Compatibility/ControlGallery/src/Tizen/res/favorite.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/film.png b/src/Compatibility/ControlGallery/src/Tizen/res/film.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/film.png rename to src/Compatibility/ControlGallery/src/Tizen/res/film.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/filmflyout.png b/src/Compatibility/ControlGallery/src/Tizen/res/filmflyout.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/filmflyout.png rename to src/Compatibility/ControlGallery/src/Tizen/res/filmflyout.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/games.png b/src/Compatibility/ControlGallery/src/Tizen/res/games.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/games.png rename to src/Compatibility/ControlGallery/src/Tizen/res/games.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/gamesflyout.png b/src/Compatibility/ControlGallery/src/Tizen/res/gamesflyout.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/gamesflyout.png rename to src/Compatibility/ControlGallery/src/Tizen/res/gamesflyout.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/googleplus.png b/src/Compatibility/ControlGallery/src/Tizen/res/googleplus.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/googleplus.png rename to src/Compatibility/ControlGallery/src/Tizen/res/googleplus.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/grid.png b/src/Compatibility/ControlGallery/src/Tizen/res/grid.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/grid.png rename to src/Compatibility/ControlGallery/src/Tizen/res/grid.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/headphone.png b/src/Compatibility/ControlGallery/src/Tizen/res/headphone.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/headphone.png rename to src/Compatibility/ControlGallery/src/Tizen/res/headphone.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/headphoneflyout.png b/src/Compatibility/ControlGallery/src/Tizen/res/headphoneflyout.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/headphoneflyout.png rename to src/Compatibility/ControlGallery/src/Tizen/res/headphoneflyout.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/hm.png b/src/Compatibility/ControlGallery/src/Tizen/res/hm.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/hm.png rename to src/Compatibility/ControlGallery/src/Tizen/res/hm.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/hm_full.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/hm_full.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/hm_full.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/hm_full.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/home.png b/src/Compatibility/ControlGallery/src/Tizen/res/home.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/home.png rename to src/Compatibility/ControlGallery/src/Tizen/res/home.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/homeflyout.png b/src/Compatibility/ControlGallery/src/Tizen/res/homeflyout.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/homeflyout.png rename to src/Compatibility/ControlGallery/src/Tizen/res/homeflyout.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ic_pause.png b/src/Compatibility/ControlGallery/src/Tizen/res/ic_pause.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ic_pause.png rename to src/Compatibility/ControlGallery/src/Tizen/res/ic_pause.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ic_play.png b/src/Compatibility/ControlGallery/src/Tizen/res/ic_play.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ic_play.png rename to src/Compatibility/ControlGallery/src/Tizen/res/ic_play.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ic_share.png b/src/Compatibility/ControlGallery/src/Tizen/res/ic_share.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ic_share.png rename to src/Compatibility/ControlGallery/src/Tizen/res/ic_share.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ic_stop.png b/src/Compatibility/ControlGallery/src/Tizen/res/ic_stop.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ic_stop.png rename to src/Compatibility/ControlGallery/src/Tizen/res/ic_stop.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/instagram.png b/src/Compatibility/ControlGallery/src/Tizen/res/instagram.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/instagram.png rename to src/Compatibility/ControlGallery/src/Tizen/res/instagram.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/invalidimage.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/invalidimage.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/invalidimage.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/invalidimage.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/jet.png b/src/Compatibility/ControlGallery/src/Tizen/res/jet.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/jet.png rename to src/Compatibility/ControlGallery/src/Tizen/res/jet.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/lists.png b/src/Compatibility/ControlGallery/src/Tizen/res/lists.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/lists.png rename to src/Compatibility/ControlGallery/src/Tizen/res/lists.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/loop.png b/src/Compatibility/ControlGallery/src/Tizen/res/loop.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/loop.png rename to src/Compatibility/ControlGallery/src/Tizen/res/loop.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/menuIcon.png b/src/Compatibility/ControlGallery/src/Tizen/res/menuIcon.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/menuIcon.png rename to src/Compatibility/ControlGallery/src/Tizen/res/menuIcon.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/messages.png b/src/Compatibility/ControlGallery/src/Tizen/res/messages.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/messages.png rename to src/Compatibility/ControlGallery/src/Tizen/res/messages.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/newspaper.png b/src/Compatibility/ControlGallery/src/Tizen/res/newspaper.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/newspaper.png rename to src/Compatibility/ControlGallery/src/Tizen/res/newspaper.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/newspaperflyout.png b/src/Compatibility/ControlGallery/src/Tizen/res/newspaperflyout.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/newspaperflyout.png rename to src/Compatibility/ControlGallery/src/Tizen/res/newspaperflyout.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/notifications.png b/src/Compatibility/ControlGallery/src/Tizen/res/notifications.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/notifications.png rename to src/Compatibility/ControlGallery/src/Tizen/res/notifications.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/oasis.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/oasis.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/oasis.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/oasis.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/oasissmall.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/oasissmall.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/oasissmall.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/oasissmall.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/person.png b/src/Compatibility/ControlGallery/src/Tizen/res/person.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/person.png rename to src/Compatibility/ControlGallery/src/Tizen/res/person.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/photo.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/photo.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/photo.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/photo.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/profile.png b/src/Compatibility/ControlGallery/src/Tizen/res/profile.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/profile.png rename to src/Compatibility/ControlGallery/src/Tizen/res/profile.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ratchet.png b/src/Compatibility/ControlGallery/src/Tizen/res/ratchet.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ratchet.png rename to src/Compatibility/ControlGallery/src/Tizen/res/ratchet.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ratchet_full.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/ratchet_full.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/ratchet_full.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/ratchet_full.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/refresh.png b/src/Compatibility/ControlGallery/src/Tizen/res/refresh.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/refresh.png rename to src/Compatibility/ControlGallery/src/Tizen/res/refresh.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/reply.png b/src/Compatibility/ControlGallery/src/Tizen/res/reply.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/reply.png rename to src/Compatibility/ControlGallery/src/Tizen/res/reply.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/retweet.png b/src/Compatibility/ControlGallery/src/Tizen/res/retweet.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/retweet.png rename to src/Compatibility/ControlGallery/src/Tizen/res/retweet.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/scott.png b/src/Compatibility/ControlGallery/src/Tizen/res/scott.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/scott.png rename to src/Compatibility/ControlGallery/src/Tizen/res/scott.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/scott159.png b/src/Compatibility/ControlGallery/src/Tizen/res/scott159.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/scott159.png rename to src/Compatibility/ControlGallery/src/Tizen/res/scott159.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/search.png b/src/Compatibility/ControlGallery/src/Tizen/res/search.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/search.png rename to src/Compatibility/ControlGallery/src/Tizen/res/search.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/seth.png b/src/Compatibility/ControlGallery/src/Tizen/res/seth.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/seth.png rename to src/Compatibility/ControlGallery/src/Tizen/res/seth.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/slideout.png b/src/Compatibility/ControlGallery/src/Tizen/res/slideout.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/slideout.png rename to src/Compatibility/ControlGallery/src/Tizen/res/slideout.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/star.png b/src/Compatibility/ControlGallery/src/Tizen/res/star.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/star.png rename to src/Compatibility/ControlGallery/src/Tizen/res/star.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/tdl.png b/src/Compatibility/ControlGallery/src/Tizen/res/tdl.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/tdl.png rename to src/Compatibility/ControlGallery/src/Tizen/res/tdl.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/tdl_full.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/tdl_full.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/tdl_full.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/tdl_full.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/test.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/test.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/test.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/test.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/toolbar_close.png b/src/Compatibility/ControlGallery/src/Tizen/res/toolbar_close.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/toolbar_close.png rename to src/Compatibility/ControlGallery/src/Tizen/res/toolbar_close.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/tweet.png b/src/Compatibility/ControlGallery/src/Tizen/res/tweet.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/tweet.png rename to src/Compatibility/ControlGallery/src/Tizen/res/tweet.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/twitter.png b/src/Compatibility/ControlGallery/src/Tizen/res/twitter.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/twitter.png rename to src/Compatibility/ControlGallery/src/Tizen/res/twitter.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/twitternav.png b/src/Compatibility/ControlGallery/src/Tizen/res/twitternav.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/twitternav.png rename to src/Compatibility/ControlGallery/src/Tizen/res/twitternav.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/xamarinlogo.png b/src/Compatibility/ControlGallery/src/Tizen/res/xamarinlogo.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/xamarinlogo.png rename to src/Compatibility/ControlGallery/src/Tizen/res/xamarinlogo.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/xamarinstore.jpg b/src/Compatibility/ControlGallery/src/Tizen/res/xamarinstore.jpg similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/res/xamarinstore.jpg rename to src/Compatibility/ControlGallery/src/Tizen/res/xamarinstore.jpg diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/shared/res/Xamarin.Forms.ControlGallery.Tizen.png b/src/Compatibility/ControlGallery/src/Tizen/shared/res/Compatibility.ControlGallery.Tizen.png similarity index 100% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/shared/res/Xamarin.Forms.ControlGallery.Tizen.png rename to src/Compatibility/ControlGallery/src/Tizen/shared/res/Compatibility.ControlGallery.Tizen.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/tizen-manifest.xml b/src/Compatibility/ControlGallery/src/Tizen/tizen-manifest.xml similarity index 53% rename from src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/tizen-manifest.xml rename to src/Compatibility/ControlGallery/src/Tizen/tizen-manifest.xml index 6305605b28..e655844d17 100644 --- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/tizen-manifest.xml +++ b/src/Compatibility/ControlGallery/src/Tizen/tizen-manifest.xml @@ -1,9 +1,9 @@  - + - - - Xamarin.Forms.ControlGallery.Tizen.png + + + Compatibility.ControlGallery.Tizen.png diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/ControlGallery.Tizen.cs b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/ControlGallery.Tizen.cs deleted file mode 100644 index 5d29a47908..0000000000 --- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/ControlGallery.Tizen.cs +++ /dev/null @@ -1,31 +0,0 @@ -using ElmSharp; -using Tizen.Applications; -using Tizen.NET.MaterialComponents; -using Xamarin.Forms; -using Xamarin.Forms.Controls; -using Xamarin.Forms.Platform.Tizen; - -namespace Xamarin.Forms.ControlGallery.Tizen -{ - class MainApplication : FormsApplication - { - internal static EvasObject NativeParent { get; private set; } - protected override void OnCreate() - { - base.OnCreate(); - MaterialComponents.Init(DirectoryInfo.Resource); - NativeParent = MainWindow; - LoadApplication(new App()); - } - - static void Main(string[] args) - { - var app = new MainApplication(); - FormsMaps.Init("HERE", "write-your-API-key-here"); - Forms.SetFlags("CollectionView_Experimental", "Shell_Experimental"); - Forms.Init(app); - FormsMaterial.Init(); - app.Run(args); - } - } -} diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/DisposeLabelRenderer.cs b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/DisposeLabelRenderer.cs deleted file mode 100644 index 27005a6701..0000000000 --- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/DisposeLabelRenderer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Xamarin.Forms; -using Xamarin.Forms.ControlGallery.Tizen; -using Xamarin.Forms.Controls; -using Xamarin.Forms.Platform.Tizen; - -[assembly: ExportRenderer(typeof(DisposeLabel), typeof(DisposeLabelRenderer))] -namespace Xamarin.Forms.ControlGallery.Tizen -{ - public class DisposeLabelRenderer : LabelRenderer - { - protected override void Dispose(bool disposing) - { - if (disposing) - { - ((DisposeLabel)Element).SendRendererDisposed(); - } - base.Dispose(disposing); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/DisposePageRenderer.cs b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/DisposePageRenderer.cs deleted file mode 100644 index 942e3b9480..0000000000 --- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/DisposePageRenderer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Xamarin.Forms; -using Xamarin.Forms.ControlGallery.Tizen; -using Xamarin.Forms.Controls; -using Xamarin.Forms.Platform.Tizen; - -[assembly: ExportRenderer(typeof(DisposePage), typeof(DisposePageRenderer))] -namespace Xamarin.Forms.ControlGallery.Tizen -{ - public class DisposePageRenderer : PageRenderer - { - protected override void Dispose(bool disposing) - { - if (disposing) - { - ((DisposePage)Element).SendRendererDisposed(); - } - base.Dispose(disposing); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/SampleNativeControl.cs b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/SampleNativeControl.cs deleted file mode 100644 index 2d56a96fb8..0000000000 --- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/SampleNativeControl.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Xamarin.Forms; -using Xamarin.Forms.ControlGallery.Tizen; -using Xamarin.Forms.Controls.Issues.Helpers; -using Xamarin.Forms.Platform.Tizen; -using ELabel = ElmSharp.Label; - -[assembly: Dependency(typeof(SampleNativeControl))] -namespace Xamarin.Forms.ControlGallery.Tizen -{ - public class SampleNativeControl : ISampleNativeControl - { - public View View - { - get - { - var label = new ELabel(MainApplication.NativeParent) - { - Text = "Sample Native Control" - }; - return label.ToView(); - } - } - } -} \ No newline at end of file diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/Xamarin.Forms.ControlGallery.Tizen.csproj b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/Xamarin.Forms.ControlGallery.Tizen.csproj deleted file mode 100644 index 2896ae684d..0000000000 --- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.Tizen/Xamarin.Forms.ControlGallery.Tizen.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - Exe - tizen40 - - - - - - - - - - - - - - - - - - diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs new file mode 100644 index 0000000000..3142d9fcf9 --- /dev/null +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs @@ -0,0 +1,55 @@ +using Microsoft.Maui.Hosting; +using Microsoft.Maui.LifecycleEvents; +using Microsoft.Maui.Controls.Compatibility; +using Microsoft.Extensions.DependencyInjection; +using TDeviceInfo = Tizen.UIExtensions.Common.DeviceInfo; + +namespace Microsoft.Maui.Controls.Compatibility.Hosting +{ + public static partial class AppHostBuilderExtensions + { + internal static MauiAppBuilder ConfigureCompatibilityLifecycleEvents(this MauiAppBuilder builder) => + builder.ConfigureLifecycleEvents(events => events.AddTizen(OnConfigureLifeCycle)); + + static void OnConfigureLifeCycle(ITizenLifecycleBuilder tizen) + { + tizen.OnPreCreate((app) => + { + // This is the initial Init to set up any system services registered by + // Forms.Init(). This happens before any UI has appeared. + // This creates a dummy MauiContext. + + var services = MauiApplication.Current.Services; + MauiContext mauiContext = new MauiContext(services); + ActivationState state = new ActivationState(mauiContext); + +#pragma warning disable CS0612 // Type or member is obsolete + var options = services.GetService(); + if (options == null) + { + options = new InitializationOptions(MauiApplication.Current) + { + DisplayResolutionUnit = TDeviceInfo.DisplayResolutionUnit.ToCompatibility(TDeviceInfo.ViewPortWidth) + }; + } + else + { + options.Context = options.Context ?? MauiApplication.Current; + TDeviceInfo.DisplayResolutionUnit = options.DisplayResolutionUnit.ToDeviceInfo(); + } + options.Flags |= InitializationFlags.SkipRenderers; + Forms.Init(state, options); +#pragma warning disable CS0612 // Type or member is obsolete + }) + .OnMauiContextCreated((mauiContext) => + { + // This is the final Init that sets up the real context from the application. + + var state = new ActivationState(mauiContext!); +#pragma warning disable CS0612 // Type or member is obsolete + Forms.Init(state); +#pragma warning disable CS0612 // Type or member is obsolete + }); + } + } +} diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs index b221d8e0b1..6efb4d6f88 100644 --- a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs +++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs @@ -33,6 +33,23 @@ using Microsoft.Maui.Controls.Compatibility.Platform.iOS; using WebViewRenderer = Microsoft.Maui.Controls.Compatibility.Platform.iOS.WkWebViewRenderer; using RadioButtonRenderer = Microsoft.Maui.Controls.Compatibility.Platform.iOS.Platform.DefaultRenderer; using DefaultRenderer = Microsoft.Maui.Controls.Compatibility.Platform.iOS.Platform.DefaultRenderer; +#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 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 @@ -89,11 +106,32 @@ namespace Microsoft.Maui.Controls.Compatibility.Hosting #pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0612 // Type or member is obsolete +#if TIZEN +#pragma warning disable CS0618 // Type or member is obsolete +#pragma warning disable CS0612 // Type or member is obsolete + handlers.TryAddCompatibilityRenderer(typeof(ContentView), typeof(LayoutRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(TabbedPage), typeof(TabbedPageRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(NavigationPage), typeof(NavigationPageRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(FlyoutPage), typeof(FlyoutPageRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ListView), typeof(ListViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Cell), typeof(CellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ImageCell), typeof(ImageCellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(EntryCell), typeof(EntryCellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(TextCell), typeof(TextCellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(ViewCell), typeof(ViewCellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(SwitchCell), typeof(SwitchCellRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(TableView), typeof(TableViewRenderer)); + handlers.TryAddCompatibilityRenderer(typeof(Frame), typeof(FrameRenderer)); +#pragma warning disable CS0612 // Type or member is obsolete +#pragma warning disable CS0618 // Type or member is obsolete +#endif // Shimmed renderers go directly to the registrar to load Image Handlers Internals.Registrar.Registered.Register(typeof(FileImageSource), typeof(FileImageSourceHandler)); Internals.Registrar.Registered.Register(typeof(StreamImageSource), typeof(StreamImagesourceHandler)); Internals.Registrar.Registered.Register(typeof(UriImageSource), typeof(ImageLoaderSourceHandler)); +#if !TIZEN Internals.Registrar.Registered.Register(typeof(FontImageSource), typeof(FontImageSourceHandler)); +#endif Internals.Registrar.Registered.Register(typeof(Microsoft.Maui.EmbeddedFont), typeof(Microsoft.Maui.EmbeddedFontLoader)); #endif diff --git a/src/Compatibility/Core/src/Compatibility.csproj b/src/Compatibility/Core/src/Compatibility.csproj index 5a4a4beec9..635e411fb1 100644 --- a/src/Compatibility/Core/src/Compatibility.csproj +++ b/src/Compatibility/Core/src/Compatibility.csproj @@ -7,6 +7,7 @@ Android\ iOS\ Windows\ + Tizen\ false true @@ -21,19 +22,15 @@ - - - - @@ -48,6 +45,7 @@ + diff --git a/src/Compatibility/Core/src/Forms.cs b/src/Compatibility/Core/src/Forms.cs index 3e288ebd19..9b4c24ec1a 100644 --- a/src/Compatibility/Core/src/Forms.cs +++ b/src/Compatibility/Core/src/Forms.cs @@ -1,4 +1,4 @@ -#if !(__ANDROID__ || __IOS__ || WINDOWS) +#if !(__ANDROID__ || __IOS__ || WINDOWS || TIZEN) using System; using System.Collections.Generic; using System.Text; diff --git a/src/Compatibility/Core/src/MauiHandlersCollectionExtensions.cs b/src/Compatibility/Core/src/MauiHandlersCollectionExtensions.cs index e89ea8313c..9c6fad5d85 100644 --- a/src/Compatibility/Core/src/MauiHandlersCollectionExtensions.cs +++ b/src/Compatibility/Core/src/MauiHandlersCollectionExtensions.cs @@ -126,4 +126,4 @@ namespace Microsoft.Maui.Controls.Compatibility.Hosting return effectsBuilder; } } -} \ No newline at end of file +} diff --git a/src/Compatibility/Core/src/RendererToHandlerShim.Tizen.cs b/src/Compatibility/Core/src/RendererToHandlerShim.Tizen.cs new file mode 100644 index 0000000000..dab4452aaa --- /dev/null +++ b/src/Compatibility/Core/src/RendererToHandlerShim.Tizen.cs @@ -0,0 +1,62 @@ +#pragma warning disable CS0612 // Type or member is obsolete +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +#pragma warning disable CS0612 // Type or member is obsolete +using Microsoft.Maui.Graphics; +using Rect = Microsoft.Maui.Graphics.Rect; +using ERect = ElmSharp.Rect; +using PlatformView = ElmSharp.EvasObject; + +namespace Microsoft.Maui.Controls.Compatibility +{ + public partial class RendererToHandlerShim : IPlatformViewHandler + { + protected override PlatformView CreatePlatformView() + { + return VisualElementRenderer.NativeView; + } + + IVisualElementRenderer CreateRenderer(IView view) + { + return Internals.Registrar.Registered.GetHandlerForObject(view) ?? new DefaultRenderer(); + } + + public override Size GetDesiredSize(double widthConstraint, double heightConstraint) + { + if (VisualElementRenderer == null) + return Size.Zero; + + // TODO. It is workaroud code, Controls.VisualElement.MeasureOverride implementation is wrong. it does not apply Height/WidthRequest + return VisualElementRenderer.Element.Measure(widthConstraint, heightConstraint).Request; + } + + public override void UpdateValue(string property) + { + base.UpdateValue(property); + if (property == "Frame") + { + PlatformArrange(VisualElementRenderer.Element.Bounds); + } + } + + public override void PlatformArrange(Rect frame) + { + base.PlatformArrange(frame); + VisualElementRenderer.UpdateLayout(); + } + + public override ERect GetPlatformContentGeometry() + { + return VisualElementRenderer?.GetNativeContentGeometry() ?? new ERect(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + VisualElementRenderer?.Dispose(); + VisualElementRenderer = null; + } + base.Dispose(disposing); + } + } +} diff --git a/src/Compatibility/Core/src/RendererToHandlerShim.cs b/src/Compatibility/Core/src/RendererToHandlerShim.cs index 39cd804c61..11d9c74384 100644 --- a/src/Compatibility/Core/src/RendererToHandlerShim.cs +++ b/src/Compatibility/Core/src/RendererToHandlerShim.cs @@ -18,6 +18,13 @@ using static Microsoft.Maui.Controls.Compatibility.Platform.iOS.Platform; using PlatformView = UIKit.UIView; using Microsoft.Maui.Controls.Compatibility.Platform.iOS; using ViewHandler = Microsoft.Maui.Handlers.ViewHandler; +#elif TIZEN +#pragma warning disable CS0612 // Type or member is obsolete +using static Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Platform; +#pragma warning disable CS0612 // Type or member is obsolete +using PlatformView = ElmSharp.EvasObject; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +using ViewHandler = Microsoft.Maui.Handlers.ViewHandler; #elif NETSTANDARD 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 index 9d3b1b8260..9ef5ce2075 100644 --- a/src/Compatibility/Core/src/Tizen/Cells/CellRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Cells/CellRenderer.cs @@ -3,6 +3,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public abstract class CellRenderer : IRegisterable { const string HeightProperty = "Height"; @@ -100,9 +101,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { var nativeSpan = new Native.Span(); nativeSpan.Text = span.Text; - nativeSpan.ForegroundColor = span.TextColor.ToPlatform(); + nativeSpan.ForegroundColor = span.TextColor.ToNative(); nativeSpan.FontAttributes = span.FontAttributes; - nativeSpan.BackgroundColor = span.BackgroundColor.ToPlatform(); + nativeSpan.BackgroundColor = span.BackgroundColor.ToNative(); nativeSpan.FontSize = span.FontSize; nativeSpan.FontFamily = span.FontFamily; return nativeSpan; diff --git a/src/Compatibility/Core/src/Tizen/Cells/EntryCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/EntryCellRenderer.cs index 62f4ecd19e..55ab30338c 100644 --- a/src/Compatibility/Core/src/Tizen/Cells/EntryCellRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Cells/EntryCellRenderer.cs @@ -2,9 +2,11 @@ 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(); @@ -33,7 +35,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen var entry = new Entry() { - HorizontalOptions = LayoutOptions.FillAndExpand, + HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Center, FontSize = -1, }; @@ -42,7 +44,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen entry.SetBinding(InputView.KeyboardProperty, new Binding(EntryCell.KeyboardProperty.PropertyName)); entry.SetBinding(Entry.HorizontalTextAlignmentProperty, new Binding(EntryCell.HorizontalTextAlignmentProperty.PropertyName)); - var layout = new StackLayout() + var layout = new XStackLayout() { Orientation = StackOrientation.Horizontal, Children = { @@ -95,7 +97,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return ((Color)value).IsDefault ? ThemeConstants.EntryCell.ColorClass.DefaultLabelColor : value; + return (value == null || ((Color)value).IsDefault) ? ThemeConstants.EntryCell.ColorClass.DefaultLabelColor : value; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) diff --git a/src/Compatibility/Core/src/Tizen/Cells/ImageCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/ImageCellRenderer.cs index 57b36327eb..d11c12561d 100644 --- a/src/Compatibility/Core/src/Tizen/Cells/ImageCellRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Cells/ImageCellRenderer.cs @@ -3,6 +3,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ImageCellRenderer : TextCellRenderer { public ImageCellRenderer() : this(ThemeManager.GetImageCellRendererStyle()) diff --git a/src/Compatibility/Core/src/Tizen/Cells/SwitchCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/SwitchCellRenderer.cs index 53ac419f17..ff1475b201 100644 --- a/src/Compatibility/Core/src/Tizen/Cells/SwitchCellRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Cells/SwitchCellRenderer.cs @@ -1,8 +1,10 @@ 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(); diff --git a/src/Compatibility/Core/src/Tizen/Cells/TextCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/TextCellRenderer.cs index 1e44d9a699..4c89702d5e 100644 --- a/src/Compatibility/Core/src/Tizen/Cells/TextCellRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Cells/TextCellRenderer.cs @@ -3,6 +3,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class TextCellRenderer : CellRenderer { bool _groupMode = false; diff --git a/src/Compatibility/Core/src/Tizen/Cells/ViewCellRenderer.cs b/src/Compatibility/Core/src/Tizen/Cells/ViewCellRenderer.cs index 6acda7e5de..7351d27fe6 100644 --- a/src/Compatibility/Core/src/Tizen/Cells/ViewCellRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Cells/ViewCellRenderer.cs @@ -3,6 +3,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ViewCellRenderer : CellRenderer { readonly Dictionary _cacheCandidate = new Dictionary(); @@ -98,7 +99,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { if (element is Button || element is Switch) { - var nativeView = Platform.GetRenderer(element).NativeView ?? null; + var nativeView = Platform.GetRenderer(element)?.NativeView ?? null; if (nativeView != null) { nativeView.PropagateEvents = false; diff --git a/src/Compatibility/Core/src/Tizen/Compatibility.Tizen.csproj b/src/Compatibility/Core/src/Tizen/Compatibility.Tizen.csproj deleted file mode 100644 index 8a2e33b20d..0000000000 --- a/src/Compatibility/Core/src/Tizen/Compatibility.Tizen.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - Tizen Backend for Xamarin.Forms - - - tizen40 - Tizen - v4.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Compatibility/Core/src/Tizen/Deserializer.cs b/src/Compatibility/Core/src/Tizen/Deserializer.cs deleted file mode 100644 index a8e7a690ab..0000000000 --- a/src/Compatibility/Core/src/Tizen/Deserializer.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO.IsolatedStorage; -using System.Runtime.Serialization; -using System.Threading.Tasks; -using System.Xml; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - internal class Deserializer : Internals.IDeserializer - { - const string PropertyStoreFile = "PropertyStore.forms"; - - public Task> DeserializePropertiesAsync() => Task.Factory.StartNew(DeserializeProperties); - - [RequiresUnreferencedCode(TrimmerConstants.SerializerTrimmerWarning)] - IDictionary DeserializeProperties() - { - // Deserialize property dictionary to local storage - // Make sure to use Internal - using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) - { - if (!store.FileExists(PropertyStoreFile)) - return null; - - using (IsolatedStorageFileStream stream = store.OpenFile(PropertyStoreFile, System.IO.FileMode.Open, System.IO.FileAccess.Read)) - using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max)) - { - if (stream.Length == 0) - return null; - - try - { - var dcs = new DataContractSerializer(typeof(Dictionary)); - return (IDictionary)dcs.ReadObject(reader); - } - catch (Exception e) - { - Debug.WriteLine("Could not deserialize properties: " + e.Message); - Internals.Log.Warning("Microsoft.Maui.Controls.Compatibility PropertyStore", $"Exception while reading Application properties: {e}"); - } - } - } - - return null; - } - - [RequiresUnreferencedCode(TrimmerConstants.SerializerTrimmerWarning)] - public Task SerializePropertiesAsync(IDictionary properties) - { - properties = new Dictionary(properties); - - // No need to write 0 properties if no file exists - if (properties.Count <= 0) - return Task.CompletedTask; - - return Task.Factory.StartNew(SerializeProperties, properties); - } - - [RequiresUnreferencedCode(TrimmerConstants.SerializerTrimmerWarning)] - void SerializeProperties(object properties) - { - using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) - { - // No need to write 0 properties if no file exists - if (properties.Count == 0 && !store.FileExists(PropertyStoreFile)) - { - return; - } - using (IsolatedStorageFileStream stream = store.OpenFile(PropertyStoreFile + ".tmp", System.IO.FileMode.OpenOrCreate)) - using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream)) - { - try - { - var dcs = new DataContractSerializer(typeof(Dictionary)); - dcs.WriteObject(writer, properties); - writer.Flush(); - } - catch (Exception e) - { - Debug.WriteLine("Could not serialize properties: " + e.Message); - Internals.Log.Warning("Microsoft.Maui.Controls.Compatibility PropertyStore", $"Exception while writing Application properties: {e}"); - return; - } - } - - try - { - if (store.FileExists(PropertyStoreFile)) - store.DeleteFile(PropertyStoreFile); - store.MoveFile(PropertyStoreFile + ".tmp", PropertyStoreFile); - } - catch (Exception e) - { - Debug.WriteLine("Could not move new serialized property file over old: " + e.Message); - Internals.Log.Warning("Microsoft.Maui.Controls.Compatibility PropertyStore", $"Exception while writing Application properties: {e}"); - } - } - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/DisplayResolutionUnit.cs b/src/Compatibility/Core/src/Tizen/DisplayResolutionUnit.cs index fdd1138ffc..dd8925343d 100644 --- a/src/Compatibility/Core/src/Tizen/DisplayResolutionUnit.cs +++ b/src/Compatibility/Core/src/Tizen/DisplayResolutionUnit.cs @@ -1,4 +1,5 @@ using System; +using TDisplayResolutionUnit = Tizen.UIExtensions.Common.DisplayResolutionUnit; namespace Microsoft.Maui.Controls.Compatibility { @@ -50,4 +51,34 @@ namespace Microsoft.Maui.Controls.Compatibility public double ViewportWidth { get; private set; } = -1; } + + public static class DisplayResolutionUnitConverter + { + public static DisplayResolutionUnit ToCompatibility(this TDisplayResolutionUnit unit, double width = 0) => unit switch + { + TDisplayResolutionUnit.DP => DisplayResolutionUnit.DP(), + TDisplayResolutionUnit.DeviceScaledDP => DisplayResolutionUnit.DP(true), + TDisplayResolutionUnit.Pixel => DisplayResolutionUnit.Pixel(), + TDisplayResolutionUnit.DeviceScaledPixel => DisplayResolutionUnit.Pixel(true), + TDisplayResolutionUnit.VP => DisplayResolutionUnit.VP(width), + _ => DisplayResolutionUnit.DP(), + }; + + public static TDisplayResolutionUnit ToDeviceInfo(this DisplayResolutionUnit unit) + { + if (unit.UseDP) + { + return unit.UseDeviceScale ? TDisplayResolutionUnit.DeviceScaledDP : TDisplayResolutionUnit.DP; + } + else if (unit.UseVP) + { + Tizen.UIExtensions.Common.DeviceInfo.ViewPortWidth = unit.ViewportWidth; + return TDisplayResolutionUnit.VP; + } + else + { + return unit.UseDeviceScale ? TDisplayResolutionUnit.DeviceScaledPixel : TDisplayResolutionUnit.Pixel; + } + } + } } diff --git a/src/Compatibility/Core/src/Tizen/DragGestureHandler.cs b/src/Compatibility/Core/src/Tizen/DragGestureHandler.cs index 3608360e0e..dc1e4001ad 100644 --- a/src/Compatibility/Core/src/Tizen/DragGestureHandler.cs +++ b/src/Compatibility/Core/src/Tizen/DragGestureHandler.cs @@ -7,6 +7,7 @@ using EGestureType = ElmSharp.GestureLayer.GestureType; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class DragGestureHandler : GestureHandler { bool _isApi4; @@ -84,7 +85,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (Renderer == null) return; - var arg = dragGestureRecognizer.SendDragStarting(Renderer.Element); + if (Renderer.Element is not View view) + return; + + var arg = dragGestureRecognizer.SendDragStarting(view); if (arg.Cancel) return; diff --git a/src/Compatibility/Core/src/Tizen/DropGestureHandler.cs b/src/Compatibility/Core/src/Tizen/DropGestureHandler.cs index f9c03d5650..13b73ae158 100644 --- a/src/Compatibility/Core/src/Tizen/DropGestureHandler.cs +++ b/src/Compatibility/Core/src/Tizen/DropGestureHandler.cs @@ -6,6 +6,7 @@ using EGestureType = ElmSharp.GestureLayer.GestureType; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class DropGestureHandler : GestureHandler { bool _isApi4; @@ -103,7 +104,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (currentStateData.DataPackage == null || currentStateData.AcceptedOperation == DataPackageOperation.None) return false; - Device.BeginInvokeOnMainThread(async () => + Application.Current?.Dispatcher.Dispatch(async () => { if (Recognizer is DropGestureRecognizer dropRecognizer && dropRecognizer.AllowDrop) await dropRecognizer.SendDrop(new DropEventArgs(currentStateData.DataPackage.View)); diff --git a/src/Compatibility/Core/src/Tizen/EmbeddedFontLoader.cs b/src/Compatibility/Core/src/Tizen/EmbeddedFontLoader.cs index 00d57405c5..09d16a7cba 100644 --- a/src/Compatibility/Core/src/Tizen/EmbeddedFontLoader.cs +++ b/src/Compatibility/Core/src/Tizen/EmbeddedFontLoader.cs @@ -1,49 +1,7 @@ -using System; -using System.IO; -using ElmSharp; -using Tizen.Common; -using IOPath = System.IO.Path; -using TApplication = Tizen.Applications.Application; - namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { - public class EmbeddedFontLoader : IEmbeddedFontLoader, IRegisterable + public class CompatibilityEmbeddedFontLoader : EmbeddedFontLoader, IRegisterable { - const string _fontCacheFolderName = "fonts"; - - public DirectoryInfo FontCacheDirectory { get; private set; } - - public EmbeddedFontLoader() - { - FontCacheDirectory = Directory.CreateDirectory(IOPath.Combine(TApplication.Current.DirectoryInfo.Data, _fontCacheFolderName)); - Utility.AppendGlobalFontPath(FontCacheDirectory.FullName); - } - - public (bool success, string filePath) LoadFont(EmbeddedFont font) - { - var filePath = IOPath.Combine(FontCacheDirectory.FullName, font.FontName); - if (File.Exists(filePath)) - return (true, filePath); - try - { - using (var fileStream = File.Create(filePath)) - { - font.ResourceStream.CopyTo(fileStream); - } - - if (DotnetUtil.TizenAPIVersion > 5) - { - FontExtensions.FontReinit(); - } - - return (true, filePath); - } - catch (Exception ex) - { - Log.Error(ex.Message); - File.Delete(filePath); - } - return (false, null); - } + //Provide compatibilityEmveddedFontLoader (implements IRegisterable) for static registar } } \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/ExportCellAttribute.cs b/src/Compatibility/Core/src/Tizen/ExportCellAttribute.cs deleted file mode 100644 index fd6844112e..0000000000 --- a/src/Compatibility/Core/src/Tizen/ExportCellAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Microsoft.Maui.Controls.Compatibility -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class ExportCellAttribute : HandlerAttribute - { - public ExportCellAttribute(Type handler, Type target) : base(handler, target) - { - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/ExportHandlerAttribute.cs b/src/Compatibility/Core/src/Tizen/ExportHandlerAttribute.cs deleted file mode 100644 index 17a126abb3..0000000000 --- a/src/Compatibility/Core/src/Tizen/ExportHandlerAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Microsoft.Maui.Controls.Compatibility -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class ExportHandlerAttribute : HandlerAttribute - { - public ExportHandlerAttribute(Type handler, Type target) : base(handler, target) - { - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/ExportImageSourceHandlerAttribute.cs b/src/Compatibility/Core/src/Tizen/ExportImageSourceHandlerAttribute.cs deleted file mode 100644 index fb680b156e..0000000000 --- a/src/Compatibility/Core/src/Tizen/ExportImageSourceHandlerAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Microsoft.Maui.Controls.Compatibility -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class ExportImageSourceHandlerAttribute : HandlerAttribute - { - public ExportImageSourceHandlerAttribute(Type handler, Type target) : base(handler, target) - { - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/ExportRendererAttribute.cs b/src/Compatibility/Core/src/Tizen/ExportRendererAttribute.cs deleted file mode 100644 index f07feb8da8..0000000000 --- a/src/Compatibility/Core/src/Tizen/ExportRendererAttribute.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; - -namespace Microsoft.Maui.Controls.Compatibility -{ - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class ExportRendererAttribute : HandlerAttribute - { - TargetIdiom Target { get; set; } - - public ExportRendererAttribute(Type handler, Type target) : this(handler, target, null) - { - } - - public ExportRendererAttribute(Type handler, Type target, Type[] supportedVisuals) : base(handler, target, supportedVisuals) - { - } - - public ExportRendererAttribute(Type handler, Type target, TargetIdiom targetIdiom) : this(handler, target, null, targetIdiom) - { - } - - public ExportRendererAttribute(Type handler, Type target, Type[] supportedVisuals, TargetIdiom targetIdiom) : base(handler, target, supportedVisuals) - { - Target = targetIdiom; - } - - public override bool ShouldRegister() - { - if (Target == TargetIdiom.Unsupported) - return true; - - return (Target == Device.Idiom); - } - } -} diff --git a/src/Compatibility/Core/src/Tizen/Extensions/AccessibilityExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/AccessibilityExtensions.cs index e1e025ff2d..31d5923c59 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/AccessibilityExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/AccessibilityExtensions.cs @@ -2,6 +2,7 @@ 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) diff --git a/src/Compatibility/Core/src/Tizen/Extensions/BrushExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/BrushExtensions.cs index 17f2980eaf..4d641e206c 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/BrushExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/BrushExtensions.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using SkiaSharp; using SkiaSharp.Views.Tizen; +using Microsoft.Maui.Graphics; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -82,7 +83,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public static SKColor ToSolidColor(this SolidColorBrush solidColorBrush) { - return solidColorBrush.Color != Color.Default ? solidColorBrush.Color.ToPlatform().ToSKColor() : SKColor.Empty; + return solidColorBrush.Color.IsDefault() ? SKColor.Empty : solidColorBrush.Color.ToNative().ToSKColor(); } static SKShader CreateLinearGradient(LinearGradientBrush linearGradientBrush, SKRect pathBounds) @@ -90,7 +91,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen 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.ToPlatform().ToSKColor()).ToArray(); + var gradientColors = orderedGradientStops.Select(x => x.Color.ToNative().ToSKColor()).ToArray(); var gradientColorPos = orderedGradientStops.Select(x => x.Offset).ToArray(); return SKShader.CreateLinearGradient(startPoint, endPoint, gradientColors, gradientColorPos, SKShaderTileMode.Clamp); } @@ -100,7 +101,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen 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.ToPlatform().ToSKColor()).ToArray(); + var gradientColors = orderedGradientStops.Select(x => x.Color.ToNative().ToSKColor()).ToArray(); var gradientColorPos = orderedGradientStops.Select(x => x.Offset).ToArray(); return SKShader.CreateRadialGradient(center, radius, gradientColors, gradientColorPos, SKShaderTileMode.Clamp); } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs index 0a5e12f52a..0f86966258 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs @@ -1,3 +1,4 @@ +using Microsoft.Maui.Graphics; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen @@ -11,25 +12,25 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// The Microsoft.Maui.Controls.Compatibility.Color instance which will be converted to a ElmSharp.Color public static EColor ToNative(this Color c) { - if (c.IsDefault) + if (c == null) { // Trying to convert the default color, this may result in black color. return EColor.Default; } else { - return new EColor((int)(255.0 * c.R), (int)(255.0 * c.G), (int)(255.0 * c.B), (int)(255.0 * c.A)); + return new EColor((int)(255.0 * c.Red), (int)(255.0 * c.Green), (int)(255.0 * c.Blue), (int)(255.0 * c.Alpha)); } } public static Color WithAlpha(this Color color, double alpha) { - return new Color(color.R, color.G, color.B, (int)(255 * alpha)); + return new Color(color.Red, color.Green, color.Blue, (int)(255 * alpha)); } public static Color WithPremultiplied(this Color color, double alpha) { - return new Color((int)(color.R * alpha), (int)(color.G * alpha), (int)(color.B * alpha), color.A); + return new Color((int)(color.Red * alpha), (int)(color.Green * alpha), (int)(color.Blue * alpha), color.Alpha); } /// diff --git a/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs index 2d293ce5e3..fb54025692 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs @@ -1,3 +1,5 @@ +using Microsoft.Maui.Graphics; +using Rect = Microsoft.Maui.Graphics.Rect; using ERect = ElmSharp.Rect; using ESize = ElmSharp.Size; @@ -8,12 +10,12 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// public static class DensityIndependentPixelExtensions { - public static Rectangle ToDP(this ERect rect) + public static Rect ToDP(this ERect rect) { - return new Rectangle(Forms.ConvertToScaledDP(rect.X), Forms.ConvertToScaledDP(rect.Y), Forms.ConvertToScaledDP(rect.Width), Forms.ConvertToScaledDP(rect.Height)); + return new Rect(Forms.ConvertToScaledDP(rect.X), Forms.ConvertToScaledDP(rect.Y), Forms.ConvertToScaledDP(rect.Width), Forms.ConvertToScaledDP(rect.Height)); } - public static ERect ToPixel(this Rectangle rect) + public static ERect ToPixel(this Rect rect) { return new ERect(Forms.ConvertToScaledPixel(rect.X), Forms.ConvertToScaledPixel(rect.Y), Forms.ConvertToScaledPixel(rect.Width), Forms.ConvertToScaledPixel(rect.Height)); } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/FontExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/FontExtensions.cs deleted file mode 100644 index 74d485f18d..0000000000 --- a/src/Compatibility/Core/src/Tizen/Extensions/FontExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Runtime.InteropServices; -using Microsoft.Maui.Controls.Compatibility.Core; -using Microsoft.Maui.Controls.Compatibility.Internals; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - public static class FontExtensions - { - public static string ToNativeFontFamily(this string self) - { - if (string.IsNullOrEmpty(self)) - return null; - - var cleansedFont = CleanseFontName(self); - int index = cleansedFont.LastIndexOf('-'); - if (index != -1) - { - string font = cleansedFont.Substring(0, index); - string style = cleansedFont.Substring(index + 1); - return $"{font}:style={style}"; - } - else - { - return cleansedFont; - } - } - - static string CleanseFontName(string fontName) - { - //First check Alias - var (hasFontAlias, fontPostScriptName) = FontRegistrar.HasFont(fontName); - if (hasFontAlias) - return fontPostScriptName; - var fontFile = FontFile.FromString(fontName); - - if (!string.IsNullOrWhiteSpace(fontFile.Extension)) - { - var (hasFont, _) = FontRegistrar.HasFont(fontFile.FileNameWithExtension()); - if (hasFont) - return fontFile.PostScriptName; - } - else - { - foreach (var ext in FontFile.Extensions) - { - var formated = fontFile.FileNameWithExtension(ext); - var (hasFont, filePath) = FontRegistrar.HasFont(formated); - if (hasFont) - return fontFile.PostScriptName; - } - } - return fontFile.PostScriptName; - } - - public static void FontReinit() - { - evas_font_reinit(); - } - - [DllImport("libelementary.so.1")] - static extern void evas_font_reinit(); - } -} diff --git a/src/Compatibility/Core/src/Tizen/Extensions/GeometryExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/GeometryExtensions.cs index c9319e18cd..ceb0487636 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/GeometryExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/GeometryExtensions.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; using SkiaSharp; -using Microsoft.Maui.Controls.Compatibility.Shapes; -using FormsRectangle = Microsoft.Maui.Controls.Compatibility.Rectangle; +using Microsoft.Maui.Controls.Shapes; +using Rect = Microsoft.Maui.Graphics.Rect; +using Point = Microsoft.Maui.Graphics.Point; + namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -9,7 +11,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { public static SKPath ToSKPath(this Geometry geometry) { +#pragma warning disable IL2026 return geometry == null ? MakePath(geometry) : MakePath((dynamic)geometry); +#pragma warning disable IL2026 } static SKPath MakePath(Geometry geometry) @@ -34,7 +38,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen static SKPath MakePath(RectangleGeometry rectangleGeometry) { var path = new SKPath(); - FormsRectangle rect = rectangleGeometry.Rect; + Rect rect = rectangleGeometry.Rect; path.AddRect(new SKRect( Forms.ConvertToScaledPixel(rect.Left), @@ -66,7 +70,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen foreach (Geometry child in geometryGroup.Children) { +#pragma warning disable IL2026 SKPath childPath = MakePath((dynamic)child); +#pragma warning disable IL2026 path.AddPath(childPath); } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/KeyboardExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/KeyboardExtensions.cs index 25ca64110e..d07cbba0ed 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/KeyboardExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/KeyboardExtensions.cs @@ -1,5 +1,4 @@ using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; using EEntry = ElmSharp.Entry; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen @@ -66,7 +65,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public static void UpdateKeyboard(this Native.IEntry control, Keyboard keyboard, bool isSpellCheckEnabled, bool isTextPredictionEnabled) { - control.Keyboard = keyboard.ToPlatform(); + control.Keyboard = keyboard.ToNative(); if (keyboard is CustomKeyboard customKeyboard) { (control as EEntry).AutoCapital = customKeyboard.Flags.ToAutoCapital(); diff --git a/src/Compatibility/Core/src/Tizen/Extensions/NativeBindingExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/NativeBindingExtensions.cs index 4fca4515e3..a833dd5bf9 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/NativeBindingExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/NativeBindingExtensions.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; using EObject = ElmSharp.EvasObject; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen diff --git a/src/Compatibility/Core/src/Tizen/Extensions/PageExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/PageExtensions.cs index d0c6c756d3..6d777e438e 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/PageExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/PageExtensions.cs @@ -3,6 +3,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility { + [Obsolete] public static class PageExtensions { public static EvasObject CreateEvasObject(this Page page, EvasObject parent, bool hasAlpha = false) @@ -33,6 +34,7 @@ namespace Microsoft.Maui.Controls.Compatibility namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public static class PageExtensions { public static EvasObject CreateEvasObject(this ContentPage page, EvasObject parent, bool hasAlpha = false) diff --git a/src/Compatibility/Core/src/Tizen/Extensions/PlatformConfigurationExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/PlatformConfigurationExtensions.cs index 2f674573c8..088e7f4e27 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/PlatformConfigurationExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/PlatformConfigurationExtensions.cs @@ -1,4 +1,4 @@ -using CurrentPlatform = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.Tizen; +using CurrentPlatform = Microsoft.Maui.Controls.PlatformConfiguration.Tizen; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { diff --git a/src/Compatibility/Core/src/Tizen/Extensions/TextAlignmentExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/TextAlignmentExtensions.cs index 276d0fc574..7abde6d2c2 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/TextAlignmentExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/TextAlignmentExtensions.cs @@ -1,3 +1,5 @@ +using Microsoft.Extensions.Logging; + namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { public static class TextAlignmentExtensions @@ -16,9 +18,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen return Native.TextAlignment.End; default: - Log.Warn("Warning: unrecognized HorizontalTextAlignment value {0}. " + + Application.Current?.FindMauiContext()?.CreateLogger()?.LogWarning("Warning: unrecognized HorizontalTextAlignment value {0}. " + "Expected: {Start|Center|End}.", alignment); - Log.Debug("Falling back to platform's default settings."); + Application.Current?.FindMauiContext()?.CreateLogger()?.LogDebug("Falling back to platform's default settings."); return Native.TextAlignment.Auto; } } diff --git a/src/Compatibility/Core/src/Tizen/Extensions/TransformExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/TransformExtensions.cs index 7649bc12c4..63805730a7 100644 --- a/src/Compatibility/Core/src/Tizen/Extensions/TransformExtensions.cs +++ b/src/Compatibility/Core/src/Tizen/Extensions/TransformExtensions.cs @@ -1,5 +1,5 @@ using SkiaSharp; -using Microsoft.Maui.Controls.Compatibility.Shapes; +using Microsoft.Maui.Controls.Shapes; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { diff --git a/src/Compatibility/Core/src/Tizen/Forms.cs b/src/Compatibility/Core/src/Tizen/Forms.cs index cd214025da..529d8c97c5 100644 --- a/src/Compatibility/Core/src/Tizen/Forms.cs +++ b/src/Compatibility/Core/src/Tizen/Forms.cs @@ -7,12 +7,14 @@ using System.Reflection; using ElmSharp; using ElmSharp.Wearable; using Tizen.Applications; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; -using Microsoft.Maui.Controls.Compatibility.Shapes; -using DeviceOrientation = Microsoft.Maui.Controls.Compatibility.Internals.DeviceOrientation; +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 Color = Microsoft.Maui.Graphics.Color; namespace Microsoft.Maui.Controls.Compatibility { @@ -29,11 +31,12 @@ namespace Microsoft.Maui.Controls.Compatibility Lightweight, } + [Obsolete] public class InitializationOptions { public CoreApplication Context { get; set; } public bool UseDeviceIndependentPixel { get; set; } - public bool UseSkiaSharp { 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; } @@ -51,6 +54,9 @@ namespace Microsoft.Maui.Controls.Compatibility public string Name; public ExportEffectAttribute[] Effects; } + public InitializationOptions() + { + } public InitializationOptions(CoreApplication application) { @@ -80,7 +86,11 @@ namespace Microsoft.Maui.Controls.Compatibility } } +#pragma warning disable CS0618 // Type or member is obsolete +#pragma warning disable CS0612 // Type or member is obsolete 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(() => { @@ -137,92 +147,41 @@ namespace Microsoft.Maui.Controls.Compatibility return ThemeManager.GetBaseScale(s_deviceType.Value); }); - class TizenDeviceInfo : DeviceInfo + static Lazy s_scalingFactor = new Lazy(() => { - readonly Size pixelScreenSize; + int width = 0; + int height = 0; - readonly Size scaledScreenSize; + TSystemInfo.TryGetValue("http://tizen.org/feature/screen.width", out width); + TSystemInfo.TryGetValue("http://tizen.org/feature/screen.height", out height); - readonly double scalingFactor; - - readonly string profile; - - public override Size PixelScreenSize + var scalingFactor = 1.0; // scaling is disabled, we're using pixels as Xamarin's geometry units + if (DisplayResolutionUnit.UseVP && DisplayResolutionUnit.ViewportWidth > 0) { - get - { - return this.pixelScreenSize; - } + scalingFactor = width / DisplayResolutionUnit.ViewportWidth; } - - public override Size ScaledScreenSize + else { - get + if (DisplayResolutionUnit.UseDP) { - return this.scaledScreenSize; + scalingFactor = s_dpi.Value / 160.0; } - } - public Size PhysicalScreenSize { get; } - - public override double ScalingFactor - { - get + if (DisplayResolutionUnit.UseDeviceScale) { - return this.scalingFactor; - } - } - - public string Profile - { - get - { - return this.profile; - } - } - - public TizenDeviceInfo() - { - int width = 0; - int height = 0; - - TSystemInfo.TryGetValue("http://tizen.org/feature/screen.width", out width); - TSystemInfo.TryGetValue("http://tizen.org/feature/screen.height", out height); - - var physicalScale = s_dpi.Value / 160.0; - PhysicalScreenSize = new Size(width / physicalScale, height / physicalScale); - - 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) + var portraitSize = Math.Min(PhysicalScreenSize.Width, PhysicalScreenSize.Height); + if (portraitSize > 2000) { - scalingFactor = s_dpi.Value / 160.0; + scalingFactor *= 4; } - - if (DisplayResolutionUnit.UseDeviceScale) + else if (portraitSize > 1000) { - var portraitSize = Math.Min(PhysicalScreenSize.Width, PhysicalScreenSize.Height); - if (portraitSize > 2000) - { - scalingFactor *= 4; - } - else if (portraitSize > 1000) - { - scalingFactor *= 2.5; - } + scalingFactor *= 2.5; } } - - pixelScreenSize = new Size(width, height); - scaledScreenSize = new Size(width / scalingFactor, height / scalingFactor); - profile = s_profile.Value; } - } + return scalingFactor; + }); static StaticRegistrarStrategy s_staticRegistrarStrategy = StaticRegistrarStrategy.None; @@ -232,6 +191,12 @@ namespace Microsoft.Maui.Controls.Compatibility public static event EventHandler ViewInitialized; + public static IMauiContext MauiContext + { + get; + internal set; + } + public static CoreApplication Context { get; @@ -262,8 +227,6 @@ namespace Microsoft.Maui.Controls.Compatibility private set; } - public static DeviceOrientation NaturalOrientation { get; } = GetDeviceOrientation(); - public static StaticRegistrarStrategy StaticRegistrarStrategy => s_staticRegistrarStrategy; public static PlatformType PlatformType => s_platformType; @@ -274,11 +237,11 @@ namespace Microsoft.Maui.Controls.Compatibility public static bool UseFastLayout { get; private set; } - public static DisplayResolutionUnit DisplayResolutionUnit { get; private set; } + public static DisplayResolutionUnit DisplayResolutionUnit { get; private set; } = DisplayResolutionUnit.Pixel(); public static int ScreenDPI => s_dpi.Value; - public static Size PhysicalScreenSize => (Device.info as TizenDeviceInfo).PhysicalScreenSize; + public static Size PhysicalScreenSize => DeviceDisplay.MainDisplayInfo.GetScaledScreenSize(); internal static TizenTitleBarVisibility TitleBarVisibility { @@ -286,23 +249,6 @@ namespace Microsoft.Maui.Controls.Compatibility private set; } - static DeviceOrientation GetDeviceOrientation() - { - int width = 0; - int height = 0; - TSystemInfo.TryGetValue("http://tizen.org/feature/screen.width", out width); - TSystemInfo.TryGetValue("http://tizen.org/feature/screen.height", out height); - - if (height >= width) - { - return DeviceOrientation.Portrait; - } - else - { - return DeviceOrientation.Landscape; - } - } - internal static void SendViewInitialized(this VisualElement self, EvasObject nativeView) { EventHandler viewInitialized = Forms.ViewInitialized; @@ -316,6 +262,8 @@ namespace Microsoft.Maui.Controls.Compatibility } } + public static bool IsInitializedRenderers { get; private set; } + public static void SetTitleBarVisibility(TizenTitleBarVisibility visibility) { TitleBarVisibility = visibility; @@ -384,41 +332,32 @@ namespace Microsoft.Maui.Controls.Compatibility } } - public static void Init(CoreApplication application) - { - Init(application, false); - } + [Obsolete] + public static void Init(IActivationState activationState) => Init(activationState.Context); - public static void Init(CoreApplication application, bool useDeviceIndependentPixel) - { - DisplayResolutionUnit = DisplayResolutionUnit.FromInit(useDeviceIndependentPixel); - SetupInit(application); - } + [Obsolete] + public static void Init(IActivationState activationState, InitializationOptions options) => Init(activationState.Context, options); - public static void Init(CoreApplication application, DisplayResolutionUnit unit) + [Obsolete] + public static void Init(IMauiContext context, InitializationOptions options = null) { - DisplayResolutionUnit = unit ?? DisplayResolutionUnit.Pixel(); - SetupInit(application); - } - - public static void Init(InitializationOptions options) - { - if (options == null) + if (options != null && options.DisplayResolutionUnit != null) { - throw new ArgumentException("Must be set options", nameof(options)); + DisplayResolutionUnit = options.DisplayResolutionUnit; } - - DisplayResolutionUnit = options.DisplayResolutionUnit ?? DisplayResolutionUnit.FromInit(options.UseDeviceIndependentPixel); - SetupInit(options.Context, options); + SetupInit(context, options); } - static void SetupInit(CoreApplication application, InitializationOptions options = null) + [Obsolete] + static void SetupInit(IMauiContext context, InitializationOptions options = null) { - Context = application; + MauiContext = context; + Context = options?.Context ?? MauiApplication.Current; + NativeParent = context.GetNativeParent(); + Registrar.RegisterRendererToHandlerShim(RendererToHandlerShim.CreateShim); if (!IsInitialized) { - Internals.Log.Listeners.Add(new XamarinLogListener()); if (System.Threading.SynchronizationContext.Current == null) { TizenSynchronizationContext.Initialize(); @@ -429,73 +368,51 @@ namespace Microsoft.Maui.Controls.Compatibility Utility.AppendGlobalFontPath(@"/usr/share/fonts"); } - Device.PlatformServices = new TizenPlatformServices(); - if (Device.info != null) + Device.DefaultRendererAssembly = typeof(Forms).Assembly; + + if (options?.Flags.HasFlag(InitializationFlags.SkipRenderers) != true) + RegisterCompatRenderers(options); + + if (options != null) { - ((TizenDeviceInfo)Device.info).Dispose(); - Device.info = null; + s_platformType = options.PlatformType; + s_useMessagingCenter = options.UseMessagingCenter; + UseSkiaSharp = options.UseSkiaSharp; + UseFastLayout = options.UseFastLayout; } - Device.Info = new Forms.TizenDeviceInfo(); + Application.AccentColor = GetAccentColor(); + ExpressionSearch.Default = new TizenExpressionSearch(); - if (!Forms.IsInitialized) + if (Context is WatchApplication) + s_platformType = PlatformType.Lightweight; + + IsInitialized = true; + } + + [Obsolete] + internal static void RegisterCompatRenderers(InitializationOptions maybeOptions = null) + { + if (!IsInitializedRenderers) { - if (options != null) + IsInitializedRenderers = true; + if (maybeOptions != null) { - s_platformType = options.PlatformType; - s_useMessagingCenter = options.UseMessagingCenter; - UseSkiaSharp = options.UseSkiaSharp; - UseFastLayout = options.UseFastLayout; + var options = maybeOptions; + var handlers = options.Handlers; + var flags = options.Flags; + var effectScopes = options.EffectScopes; + + //TODO: ExportCell? + //TODO: ExportFont // renderers - if (options.Handlers != null) + if (handlers != null) { - Registrar.RegisterRenderers(options.Handlers); - } - else - { - // static registrar - if (options.StaticRegistarStrategy != StaticRegistrarStrategy.None) - { - s_staticRegistrarStrategy = options.StaticRegistarStrategy; - StaticRegistrar.RegisterHandlers(options.CustomHandlers); - - if (options.StaticRegistarStrategy == StaticRegistrarStrategy.All) - { - Registrar.RegisterAll(new Type[] - { - typeof(ExportRendererAttribute), - typeof(ExportImageSourceHandlerAttribute), - typeof(ExportCellAttribute), - typeof(ExportHandlerAttribute), - typeof(ExportFontAttribute) - }); - - if (UseSkiaSharp) - RegisterSkiaSharpRenderers(); - } - } - else - { - Registrar.RegisterAll(new Type[] - { - typeof(ExportRendererAttribute), - typeof(ExportImageSourceHandlerAttribute), - typeof(ExportCellAttribute), - typeof(ExportHandlerAttribute), - typeof(ExportFontAttribute) - }); - - if (UseSkiaSharp) - RegisterSkiaSharpRenderers(); - - if (UseFastLayout) - Registrar.Registered.Register(typeof(Layout), typeof(FastLayoutRenderer)); - } + Registrar.RegisterRenderers(handlers); } // effects - var effectScopes = options.EffectScopes; if (effectScopes != null) { for (var i = 0; i < effectScopes.Length; i++) @@ -506,28 +423,19 @@ namespace Microsoft.Maui.Controls.Compatibility } // css - Registrar.RegisterStylesheets(options.Flags); + Registrar.RegisterStylesheets(flags); } else { - Registrar.RegisterAll(new Type[] - { + // Only need to do this once + Registrar.RegisterAll(new[] { typeof(ExportRendererAttribute), - typeof(ExportImageSourceHandlerAttribute), typeof(ExportCellAttribute), - typeof(ExportHandlerAttribute), + typeof(ExportImageSourceHandlerAttribute), typeof(ExportFontAttribute) }); } } - - Color.SetAccent(GetAccentColor(profile)); - ExpressionSearch.Default = new TizenExpressionSearch(); - - if (application is WatchApplication) - s_platformType = PlatformType.Lightweight; - - IsInitialized = true; } static void RegisterSkiaSharpRenderers() @@ -545,26 +453,23 @@ namespace Microsoft.Maui.Controls.Compatibility Registrar.Registered.Register(typeof(Shapes.Rectangle), typeof(Platform.Tizen.SkiaSharp.RectangleRenderer)); } - static Color GetAccentColor(string profile) + static Color GetAccentColor() { // On Windows Phone, this is the complementary color chosen by the user. // Good Windows Phone applications use this as part of their styling to provide a native look and feel. // On iOS and Android this instance is set to a contrasting color that is visible on the default // background but is not the same as the default text color. - switch (profile) - { - case "mobile": - // [Tizen_3.0]Basic_Interaction_GUI_[REF].xlsx Theme 001 (Default) 1st HSB: 188 70 80 - return Color.FromRgba(61, 185, 204, 255); - case "tv": - return Color.FromRgba(15, 15, 15, 230); - case "wearable": - // Theme A (Default) 1st HSB: 207 75 16 - return Color.FromRgba(10, 27, 41, 255); - default: - return Color.Black; - } + if (DeviceInfo.Idiom == DeviceIdiom.Phone) + // [Tizen_3.0]Basic_Interaction_GUI_[REF].xlsx Theme 001 (Default) 1st HSB: 188 70 80 + return Color.FromRgba(61, 185, 204, 255); + else if (DeviceInfo.Idiom == DeviceIdiom.TV) + return Color.FromRgba(15, 15, 15, 230); + else if (DeviceInfo.Idiom == DeviceIdiom.Watch) + // Theme A (Default) 1st HSB: 207 75 16 + return Color.FromRgba(10, 27, 41, 255); + else + return Color.FromRgb(0, 0, 0); } /// @@ -591,7 +496,7 @@ namespace Microsoft.Maui.Controls.Compatibility /// public static int ConvertToScaledPixel(double dp) { - return (int)Math.Round(dp * Device.Info.ScalingFactor); + return (int)Math.Round(dp * s_scalingFactor.Value); } /// @@ -604,7 +509,9 @@ namespace Microsoft.Maui.Controls.Compatibility /// public static double ConvertToScaledDP(int pixel) { - return pixel / Device.Info.ScalingFactor; + if (pixel == int.MaxValue) + return double.PositiveInfinity; + return pixel / s_scalingFactor.Value; } /// @@ -617,7 +524,9 @@ namespace Microsoft.Maui.Controls.Compatibility /// public static double ConvertToScaledDP(double pixel) { - return pixel / Device.Info.ScalingFactor; + if (pixel == double.PositiveInfinity) + return double.PositiveInfinity; + return pixel / s_scalingFactor.Value; } /// @@ -660,7 +569,7 @@ namespace Microsoft.Maui.Controls.Compatibility { Elementary.Initialize(); Elementary.ThemeOverlay(); - var window = new PreloadedWindow(); + 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); } diff --git a/src/Compatibility/Core/src/Tizen/FormsApplication.cs b/src/Compatibility/Core/src/Tizen/FormsApplication.cs index 593437afae..330de47c62 100644 --- a/src/Compatibility/Core/src/Tizen/FormsApplication.cs +++ b/src/Compatibility/Core/src/Tizen/FormsApplication.cs @@ -7,20 +7,23 @@ using ElmSharp; using ElmSharp.Wearable; using Tizen.Applications; using Tizen.Common; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; -using DeviceOrientation = Microsoft.Maui.Controls.Compatibility.Internals.DeviceOrientation; +using Microsoft.Maui.Devices; +using EWindow = ElmSharp.Window; using ELayout = ElmSharp.Layout; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Application; +using EDisplayRotation = ElmSharp.DisplayRotation; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Application; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class FormsApplication : CoreUIApplication { ITizenPlatform _platform; Application _application; - Window _window; + EWindow _window; bool _useBezelInteration; protected FormsApplication() @@ -31,7 +34,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// Gets the main window or null if it's not set. /// /// The main window or null. - public Window MainWindow + public EWindow MainWindow { get { @@ -67,20 +70,20 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Environment.SetEnvironmentVariable("XDG_DATA_HOME", Current.DirectoryInfo.Data); } - var type = typeof(Window); + 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); - Window window = null; + EWindow window = null; if (methodInfo != null) { - window = (Window)methodInfo.Invoke(null, new object[] { "FormsWindow" }); + 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 Window("FormsWindow"); + window = PreloadedWindow.GetInstance() ?? new EWindow("FormsWindow"); if (window is PreloadedWindow precreated) { BaseLayout = precreated.BaseLayout; @@ -128,7 +131,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (null == MainWindow) { - throw new InvalidOperationException("MainWindow is not prepared. This method should be called in OnCreated()."); + throw new InvalidOperationException("MainEWindow is not prepared. This method should be called in OnCreated()."); } if (null == application) @@ -192,7 +195,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void InitializeWindow() { - Debug.Assert(MainWindow != null, "Window cannot be null"); + Debug.Assert(MainWindow != null, "EWindow cannot be null"); MainWindow.Active(); MainWindow.Show(); @@ -217,20 +220,13 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen conformant.SetContent(BaseLayout); } - MainWindow.AvailableRotations = DisplayRotation.Degree_0 | DisplayRotation.Degree_90 | DisplayRotation.Degree_180 | DisplayRotation.Degree_270; + MainWindow.AvailableRotations = EDisplayRotation.Degree_0 | EDisplayRotation.Degree_90 | EDisplayRotation.Degree_180 | EDisplayRotation.Degree_270; MainWindow.Deleted += (s, e) => { Exit(); }; - Device.Info.CurrentOrientation = MainWindow.GetDeviceOrientation(); - - MainWindow.RotationChanged += (sender, e) => - { - Device.Info.CurrentOrientation = MainWindow.GetDeviceOrientation(); - }; - MainWindow.BackButtonPressed += (sender, e) => { if (_platform != null) @@ -275,25 +271,4 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen base.Exit(); } } - static class WindowExtension - { - public static DeviceOrientation GetDeviceOrientation(this Window window) - { - DeviceOrientation orientation = DeviceOrientation.Other; - var isPortraitDevice = Forms.NaturalOrientation.IsPortrait(); - switch (window.Rotation) - { - case 0: - case 180: - orientation = isPortraitDevice ? DeviceOrientation.Portrait : DeviceOrientation.Landscape; - break; - - case 90: - case 270: - orientation = isPortraitDevice ? DeviceOrientation.Landscape : DeviceOrientation.Portrait; - break; - } - return orientation; - } - } } diff --git a/src/Compatibility/Core/src/Tizen/GestureDetector.cs b/src/Compatibility/Core/src/Tizen/GestureDetector.cs index 6e41259bac..a5c7fca263 100644 --- a/src/Compatibility/Core/src/Tizen/GestureDetector.cs +++ b/src/Compatibility/Core/src/Tizen/GestureDetector.cs @@ -1,11 +1,13 @@ 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; diff --git a/src/Compatibility/Core/src/Tizen/GestureHandler.cs b/src/Compatibility/Core/src/Tizen/GestureHandler.cs index 763523013d..0df0a99280 100644 --- a/src/Compatibility/Core/src/Tizen/GestureHandler.cs +++ b/src/Compatibility/Core/src/Tizen/GestureHandler.cs @@ -4,6 +4,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public abstract class GestureHandler : IGestureController, INotifyPropertyChanged, IRegisterable { public IGestureRecognizer Recognizer { get; private set; } diff --git a/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs new file mode 100644 index 0000000000..22489b74cd --- /dev/null +++ b/src/Compatibility/Core/src/Tizen/HandlerToRendererShim.cs @@ -0,0 +1,196 @@ +using System; +using System.ComponentModel; +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; + +namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen +{ +#pragma warning disable CS0612 // Type or member is obsolete + public class HandlerToRendererShim : IVisualElementRenderer +#pragma warning disable CS0612 // Type or member is obsolete + { + bool _disposed; + + public HandlerToRendererShim(IPlatformViewHandler vh) + { + Compatibility.Hosting.MauiAppBuilderExtensions.CheckForCompatibility(); + ViewHandler = vh; + } + + IPlatformViewHandler ViewHandler { get; } + + public VisualElement Element { get; private set; } + + public EvasObject NativeView => ViewHandler.ContainerView ?? ViewHandler.PlatformView; + + public event EventHandler ElementChanged; + public event EventHandler ElementPropertyChanged; + + public void Dispose() + { + if (!_disposed) + { + _disposed = true; + Platform.SetRenderer(Element, null); + ViewHandler.Dispose(); + } + } + + public void SetElement(VisualElement element) + { + var oldElement = Element; + + if (oldElement != null) + { + oldElement.PropertyChanged -= OnElementPropertyChanged; + oldElement.BatchCommitted -= OnBatchCommitted; + } + + if (element != null) + { + element.PropertyChanged += OnElementPropertyChanged; + element.BatchCommitted += OnBatchCommitted; + } + + Element = element; + ((IView)element).Handler = ViewHandler; + Platform.SetRenderer(element, this); + + 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)); + } + + void OnBatchCommitted(object sender, EventArg e) + { + ViewHandler?.PlatformArrange(Element.Bounds); + } + + void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + ElementPropertyChanged?.Invoke(this, new PropertyChangedEventArgs(e.PropertyName)); + } + + void OnNativeDeleted(object sender, EventArgs e) + { + Dispose(); + } + + public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) + { + return ViewHandler.GetDesiredSize(widthConstraint, heightConstraint); + } + + public void SetElementSize(Size size) + { + Layout.LayoutChildIntoBoundingRegion(Element, new Rect(Element.X, Element.Y, size.Width, size.Height)); + } + + 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; } + 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/IMEApplication.cs b/src/Compatibility/Core/src/Tizen/IMEApplication.cs index d874fa78b3..96c07ef780 100644 --- a/src/Compatibility/Core/src/Tizen/IMEApplication.cs +++ b/src/Compatibility/Core/src/Tizen/IMEApplication.cs @@ -4,6 +4,7 @@ using Tizen.Uix.InputMethod; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class IMEApplication : FormsApplication { public EditorWindow EditorWindow diff --git a/src/Compatibility/Core/src/Tizen/LightweightPlatform.cs b/src/Compatibility/Core/src/Tizen/LightweightPlatform.cs index 357ae26b64..71e4046944 100644 --- a/src/Compatibility/Core/src/Tizen/LightweightPlatform.cs +++ b/src/Compatibility/Core/src/Tizen/LightweightPlatform.cs @@ -3,11 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; +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(); diff --git a/src/Compatibility/Core/src/Tizen/Log/XamarinLogListener.cs b/src/Compatibility/Core/src/Tizen/Log/XamarinLogListener.cs deleted file mode 100644 index 5105ecf5ca..0000000000 --- a/src/Compatibility/Core/src/Tizen/Log/XamarinLogListener.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Microsoft.Maui.Controls.Compatibility.Internals; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - internal class XamarinLogListener : LogListener - { - public XamarinLogListener() - { - } - - #region implemented abstract members of LogListener - - public override void Warning(string category, string message) - { - Log.Warn("[{0}] {1}", category, message); - } - - #endregion - } -} diff --git a/src/Compatibility/Core/src/Tizen/Native/BorderRectangle.cs b/src/Compatibility/Core/src/Tizen/Native/BorderRectangle.cs index 13836a28d5..db0dcdb2c3 100644 --- a/src/Compatibility/Core/src/Tizen/Native/BorderRectangle.cs +++ b/src/Compatibility/Core/src/Tizen/Native/BorderRectangle.cs @@ -35,7 +35,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native radius[2] = Math.Min(bottomLeft, maxR); radius[3] = Math.Min(bottomRight, maxR); - Point first = new Point(-1, -1); + Graphics.Point first = new Graphics.Point(-1, -1); for (int i = 0; i <= radius[0]; i++) { int x = i; diff --git a/src/Compatibility/Core/src/Tizen/Native/Button.cs b/src/Compatibility/Core/src/Tizen/Native/Button.cs index 3e70f482dc..f53ecefb66 100644 --- a/src/Compatibility/Core/src/Tizen/Native/Button.cs +++ b/src/Compatibility/Core/src/Tizen/Native/Button.cs @@ -3,7 +3,7 @@ using ElmSharp; using EButton = ElmSharp.Button; using EColor = ElmSharp.Color; using ESize = ElmSharp.Size; -using TSButtonStyle = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.ButtonStyle; +using TSButtonStyle = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.ButtonStyle; #if __MATERIAL__ using Tizen.NET.MaterialComponents; diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/CollectionView.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/CollectionView.cs index ac6bbf9f85..46dbbefb1d 100644 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/CollectionView.cs +++ b/src/Compatibility/Core/src/Tizen/Native/CollectionView/CollectionView.cs @@ -2,6 +2,7 @@ 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; @@ -332,7 +333,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native if (holder.State == ViewHolderState.Focused && FocusedItemScrollPosition != ScrollToPosition.MakeVisible) { - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { if (holder.State == ViewHolderState.Focused && _viewHolderIndexTable.TryGetValue(holder, out int itemIndex)) { @@ -613,7 +614,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native Scroller.HorizontalStepSize = _layoutManager.GetScrollBlockSize(); Scroller.VerticalStepSize = _layoutManager.GetScrollBlockSize(); UpdateSnapPointsType(SnapPointsType); - Device.BeginInvokeOnMainThread(SendScrolledEvent); + Application.Current.Dispatcher.Dispatch(SendScrolledEvent); } } @@ -625,7 +626,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native if (!_requestLayoutItems) { _requestLayoutItems = true; - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { _requestLayoutItems = false; if (_adaptor != null && _layoutManager != null) diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/EmptyItemAdaptor.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/EmptyItemAdaptor.cs index f0c8113df6..f194c7e3a6 100644 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/EmptyItemAdaptor.cs +++ b/src/Compatibility/Core/src/Tizen/Native/CollectionView/EmptyItemAdaptor.cs @@ -2,10 +2,12 @@ using System.Collections; using System.Collections.Generic; using ElmSharp; using ESize = ElmSharp.Size; -using XLabel = Microsoft.Maui.Controls.Compatibility.Label; +using XLabel = Microsoft.Maui.Controls.Label; +using XStackLayout = Microsoft.Maui.Controls.StackLayout; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native { + [System.Obsolete] public class EmptyItemAdaptor : ItemTemplateAdaptor, IEmptyAdaptor { static DataTemplate s_defaultEmptyTemplate = new DataTemplate(typeof(EmptyView)); @@ -56,7 +58,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native var header = CreateHeaderView(); var footer = CreateFooterView(); - var layout = new StackLayout(); + var layout = new XStackLayout(); if (header != null) { @@ -79,20 +81,20 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native native.Unrealize(); } - class EmptyView : StackLayout + class EmptyView : XStackLayout { public EmptyView() { - HorizontalOptions = LayoutOptions.FillAndExpand; - VerticalOptions = LayoutOptions.FillAndExpand; + HorizontalOptions = LayoutOptions.Fill; + VerticalOptions = LayoutOptions.Fill; Children.Add( new XLabel { Text = "No items found", - VerticalOptions = LayoutOptions.CenterAndExpand, - HorizontalOptions = LayoutOptions.CenterAndExpand, - HorizontalTextAlignment = Microsoft.Maui.Controls.Compatibility.TextAlignment.Center, - VerticalTextAlignment = Microsoft.Maui.Controls.Compatibility.TextAlignment.Center, + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + HorizontalTextAlignment = Maui.TextAlignment.Center, + VerticalTextAlignment = Maui.TextAlignment.Center, } ); } diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/GridLayoutManager.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/GridLayoutManager.cs index 28b3699108..595b532a45 100644 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/GridLayoutManager.cs +++ b/src/Compatibility/Core/src/Tizen/Native/CollectionView/GridLayoutManager.cs @@ -111,8 +111,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native int ItemSpacing => IsHorizontal ? HorizontalItemSpacing : VerticalItemSpacing; - int ItemWidthConstraint => IsHorizontal ? _allocatedSize.Width * 100 : ColumnSize; - int ItemHeightConstraint => IsHorizontal ? ColumnSize : _allocatedSize.Height * 100; + // 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 { @@ -404,7 +405,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native public int GetVisibleItemIndex(int x, int y) { int index = 0; - if (x < 0 || y < 0) + if (x < 0 || y < 0 || _accumulatedItemSizes == null) return index; if (_scrollCanvasSize.Width < x || _scrollCanvasSize.Height < y) return CollectionView.Count - 1; diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/IndicatorView.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/IndicatorView.cs index 7680b996c9..593c4a6984 100644 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/IndicatorView.cs +++ b/src/Compatibility/Core/src/Tizen/Native/CollectionView/IndicatorView.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using Microsoft.Maui.Devices; using ElmSharp; +using Index = ElmSharp.Index; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native { diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemTemplateAdaptor.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemTemplateAdaptor.cs index 7444dbcd09..9c0e8ea7df 100644 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemTemplateAdaptor.cs +++ b/src/Compatibility/Core/src/Tizen/Native/CollectionView/ItemTemplateAdaptor.cs @@ -4,10 +4,13 @@ using System.Collections.Generic; using System.Globalization; using ElmSharp; using ESize = ElmSharp.Size; -using XLabel = Microsoft.Maui.Controls.Compatibility.Label; +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 { + [Obsolete] public class ItemDefaultTemplateAdaptor : ItemTemplateAdaptor { class ToTextConverter : IValueConverter @@ -26,13 +29,13 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native { var label = new XLabel { - TextColor = Color.Black, + TextColor = XColor.FromRgb(0,0,0), }; label.SetBinding(XLabel.TextProperty, new Binding(".", converter: new ToTextConverter())); - return new StackLayout + return new XStackLayout { - BackgroundColor = Color.White, + BackgroundColor = XColor.FromRgb(255, 255, 255), Padding = 30, Children = { @@ -43,6 +46,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native } } + [Obsolete] public class ItemTemplateAdaptor : ItemAdaptor { Dictionary _nativeFormsTable = new Dictionary(); @@ -182,7 +186,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native { if (_dataBindedViewTable.TryGetValue(this[index], out View createdView) && createdView != null) { - return createdView.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint), MeasureFlags.IncludeMargins).Request.ToPixel(); + return createdView.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint), MeasureFlags.IncludeMargins).Request.ToEFLPixel(); } View view = null; @@ -200,18 +204,18 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native if (Count > index) view.BindingContext = this[index]; var request = view.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint), MeasureFlags.IncludeMargins).Request; - return request.ToPixel(); + return request.ToEFLPixel(); } } public override ESize MeasureHeader(int widthConstraint, int heightConstraint) { - return _headerCache?.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint)).Request.ToPixel() ?? new ESize(0, 0); + return _headerCache?.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint)).Request.ToEFLPixel() ?? new ESize(0, 0); } public override ESize MeasureFooter(int widthConstraint, int heightConstraint) { - return _footerCache?.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint)).Request.ToPixel() ?? new ESize(0, 0); + return _footerCache?.Measure(Forms.ConvertToScaledDP(widthConstraint), Forms.ConvertToScaledDP(heightConstraint)).Request.ToEFLPixel() ?? new ESize(0, 0); } public override void UpdateViewState(EvasObject view, ViewHolderState state) diff --git a/src/Compatibility/Core/src/Tizen/Native/CollectionView/LinearLayoutManager.cs b/src/Compatibility/Core/src/Tizen/Native/CollectionView/LinearLayoutManager.cs index 414cf3b8ea..d5e32d2b9b 100644 --- a/src/Compatibility/Core/src/Tizen/Native/CollectionView/LinearLayoutManager.cs +++ b/src/Compatibility/Core/src/Tizen/Native/CollectionView/LinearLayoutManager.cs @@ -100,8 +100,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native } } - int ItemWidthConstraint => IsHorizontal ? _allocatedSize.Width * 100 : _allocatedSize.Width; - int ItemHeightConstraint => IsHorizontal ? _allocatedSize.Height : _allocatedSize.Height * 100; + // 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; diff --git a/src/Compatibility/Core/src/Tizen/Native/DateTimePickerDialog.cs b/src/Compatibility/Core/src/Tizen/Native/DateTimePickerDialog.cs index 11ddcb5c1a..03234ecf48 100644 --- a/src/Compatibility/Core/src/Tizen/Native/DateTimePickerDialog.cs +++ b/src/Compatibility/Core/src/Tizen/Native/DateTimePickerDialog.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Maui.Devices; using ElmSharp; using EButton = ElmSharp.Button; diff --git a/src/Compatibility/Core/src/Tizen/Native/Dialog.cs b/src/Compatibility/Core/src/Tizen/Native/Dialog.cs index 3bad6f74af..10c4f292cf 100644 --- a/src/Compatibility/Core/src/Tizen/Native/Dialog.cs +++ b/src/Compatibility/Core/src/Tizen/Native/Dialog.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Maui.Devices; using ElmSharp; using EButton = ElmSharp.Button; using EColor = ElmSharp.Color; @@ -56,7 +57,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native /// /// Occurs whenever the dialog is first displayed. /// - public event EventHandler Shown; + public event EventHandler DialogShown; /// /// Gets or sets the title of the dialog @@ -194,7 +195,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native public new void Show() { base.Show(); - Shown?.Invoke(this, EventArgs.Empty); + DialogShown?.Invoke(this, EventArgs.Empty); } /// @@ -301,7 +302,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native // Adds a handler for the Shown event. // In effect, registers this instance to be affected by the hardware back key presses. - Shown += (s, e) => + DialogShown += (s, e) => { OnShown(); }; diff --git a/src/Compatibility/Core/src/Tizen/Native/EditfieldEntry.cs b/src/Compatibility/Core/src/Tizen/Native/EditfieldEntry.cs index a2d20154e6..b66ab8f583 100644 --- a/src/Compatibility/Core/src/Tizen/Native/EditfieldEntry.cs +++ b/src/Compatibility/Core/src/Tizen/Native/EditfieldEntry.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Maui.Devices; using ElmSharp; using EColor = ElmSharp.Color; using ELayout = ElmSharp.Layout; diff --git a/src/Compatibility/Core/src/Tizen/Native/Entry.cs b/src/Compatibility/Core/src/Tizen/Native/Entry.cs index 4a914642ab..27579173d3 100644 --- a/src/Compatibility/Core/src/Tizen/Native/Entry.cs +++ b/src/Compatibility/Core/src/Tizen/Native/Entry.cs @@ -105,11 +105,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native var old = _span.Text; _span.Text = value; ApplyTextAndStyle(); - Device.StartTimer(TimeSpan.FromTicks(1), () => - { - OnTextChanged(old, value); - return false; - }); + Application.Current.Dispatcher.DispatchDelayed(TimeSpan.FromTicks(1), () => OnTextChanged(old, value)); } } } diff --git a/src/Compatibility/Core/src/Tizen/Native/FlyoutPage.cs b/src/Compatibility/Core/src/Tizen/Native/FlyoutPage.cs index bcd12ec388..ce3841aac8 100644 --- a/src/Compatibility/Core/src/Tizen/Native/FlyoutPage.cs +++ b/src/Compatibility/Core/src/Tizen/Native/FlyoutPage.cs @@ -1,6 +1,7 @@ using System; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Devices; +using Microsoft.Maui.Controls.Internals; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native { @@ -127,12 +128,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native // in case of the screen rotation we may need to update the choice between split // and popover behaviors and reconfigure the layout - Device.Info.PropertyChanged += (s, e) => + DeviceDisplay.MainDisplayInfoChanged += (s, e) => { - if (e.PropertyName == nameof(Device.Info.CurrentOrientation)) - { - UpdateFlyoutLayoutBehavior(); - } + UpdateFlyoutLayoutBehavior(); }; } @@ -352,7 +350,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native // Screen orientation affects those 2 behaviors if (behavior == FlyoutLayoutBehavior.SplitOnLandscape || behavior == FlyoutLayoutBehavior.SplitOnPortrait) { - var orientation = Device.Info.CurrentOrientation; + var orientation = DeviceDisplay.MainDisplayInfo.Orientation; if ((orientation.IsLandscape() && behavior == FlyoutLayoutBehavior.SplitOnLandscape) || (orientation.IsPortrait() && behavior == FlyoutLayoutBehavior.SplitOnPortrait)) { diff --git a/src/Compatibility/Core/src/Tizen/Native/ListView.cs b/src/Compatibility/Core/src/Tizen/Native/ListView.cs index 7e75e82bd3..e504d3711b 100644 --- a/src/Compatibility/Core/src/Tizen/Native/ListView.cs +++ b/src/Compatibility/Core/src/Tizen/Native/ListView.cs @@ -3,7 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.ComponentModel; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; using EColor = ElmSharp.Color; using ERect = ElmSharp.Rect; using EScroller = ElmSharp.Scroller; @@ -25,6 +25,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native /// 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 { /// @@ -293,7 +294,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native { GenListItem item = GetItemContext(cell)?.Item as GenListItem; if (item != null) - this.ScrollTo(item, position.ToPlatform(), animated); + this.ScrollTo(item, position.ToNative(), animated); } /// diff --git a/src/Compatibility/Core/src/Tizen/Native/Span.cs b/src/Compatibility/Core/src/Tizen/Native/Span.cs index 8ce1b31ed4..2b663171c9 100644 --- a/src/Compatibility/Core/src/Tizen/Native/Span.cs +++ b/src/Compatibility/Core/src/Tizen/Native/Span.cs @@ -1,7 +1,7 @@ using System; using System.Text; using EColor = ElmSharp.Color; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native { @@ -257,10 +257,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native string ConvertTags(string text) { - return text.Replace("&", "&") - .Replace("<", "<") - .Replace(">", ">") - .Replace(Environment.NewLine, "
"); + return text.Replace("&", "&", StringComparison.Ordinal) + .Replace("<", "<", StringComparison.Ordinal) + .Replace(">", ">", StringComparison.Ordinal) + .Replace(Environment.NewLine, "
", StringComparison.Ordinal); } public string GetStyle() diff --git a/src/Compatibility/Core/src/Tizen/Native/TableView.cs b/src/Compatibility/Core/src/Tizen/Native/TableView.cs index 21162287e3..3b9621bf0b 100644 --- a/src/Compatibility/Core/src/Tizen/Native/TableView.cs +++ b/src/Compatibility/Core/src/Tizen/Native/TableView.cs @@ -5,6 +5,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native /// /// Extends the ListView class to provide TableView class implementation. /// + [System.Obsolete] public class TableView : ListView, ITableView { @@ -44,7 +45,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native /// /// Sets the section title. /// - void AddSectionTitle(string title, Color textColor) + void AddSectionTitle(string title, Graphics.Color textColor) { Cell cell = new SectionCell() { diff --git a/src/Compatibility/Core/src/Tizen/Native/TitleViewPage.cs b/src/Compatibility/Core/src/Tizen/Native/TitleViewPage.cs index 460befafd3..3697632d90 100644 --- a/src/Compatibility/Core/src/Tizen/Native/TitleViewPage.cs +++ b/src/Compatibility/Core/src/Tizen/Native/TitleViewPage.cs @@ -3,13 +3,14 @@ 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.Compatibility.Page page, View titleView) : base(parent) + public TitleViewPage(EvasObject parent, Microsoft.Maui.Controls.Page page, View titleView) : base(parent) { _page = Platform.GetOrCreateRenderer(page).NativeView as Native.Page; _titleView = titleView; diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/FormsWatchLayout.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/FormsWatchLayout.cs index 1ec60ad485..9d2e9972cc 100644 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/FormsWatchLayout.cs +++ b/src/Compatibility/Core/src/Tizen/Native/Watch/FormsWatchLayout.cs @@ -1,3 +1,4 @@ +using Microsoft.Maui.Devices; using ElmSharp; using EColor = ElmSharp.Color; @@ -7,8 +8,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch { public FormsWatchLayout(EvasObject parent) : base(parent) { - if (Device.Idiom != TargetIdiom.Watch) - Log.Error($"{0} is only supported on TargetIdiom.Watch : {1}", this, Device.Idiom); + if (DeviceInfo.Idiom != DeviceIdiom.Watch) + Log.Error($"{0} is only supported on TargetIdiom.Watch : {1}", this, DeviceInfo.Idiom); } } diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchButton.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchButton.cs index 70ecd2137e..6bde527a75 100644 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchButton.cs +++ b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchButton.cs @@ -1,6 +1,6 @@ using System; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific; +using Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific; using ESize = ElmSharp.Size; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePickerDialog.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePickerDialog.cs index ea7e4e6cdc..891b0a6129 100644 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePickerDialog.cs +++ b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchDateTimePickerDialog.cs @@ -3,7 +3,7 @@ using ElmSharp; using ElmSharp.Wearable; using EButton = ElmSharp.Button; using ELayout = ElmSharp.Layout; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Application; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Application; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch { diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchListView.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchListView.cs index 72dc5ff9ee..c0a365e0a7 100644 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchListView.cs +++ b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchListView.cs @@ -5,6 +5,7 @@ using ElmSharp.Wearable; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch { + [Obsolete] public class WatchListView : Native.ListView, IRotaryActionWidget, IRotaryInteraction { CircleGenList _circleGenList; diff --git a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchTableView.cs b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchTableView.cs index 63b8e626ca..65ff1e120f 100644 --- a/src/Compatibility/Core/src/Tizen/Native/Watch/WatchTableView.cs +++ b/src/Compatibility/Core/src/Tizen/Native/Watch/WatchTableView.cs @@ -3,6 +3,7 @@ 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(); @@ -34,7 +35,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch return base.GetCellRenderer(cell, isGroup); } - void AddSectionTitle(string title, Color textColor) + void AddSectionTitle(string title, Graphics.Color textColor) { Cell cell = new SectionCell() { diff --git a/src/Compatibility/Core/src/Tizen/NativeBindingService.cs b/src/Compatibility/Core/src/Tizen/NativeBindingService.cs index adfc61627c..a4d7cc87b1 100644 --- a/src/Compatibility/Core/src/Tizen/NativeBindingService.cs +++ b/src/Compatibility/Core/src/Tizen/NativeBindingService.cs @@ -1,6 +1,5 @@ using System.Diagnostics.CodeAnalysis; -using Microsoft.Maui.Controls.Compatibility.Internals; -using Microsoft.Maui.Controls.Compatibility.Xaml.Internals; +using Microsoft.Maui.Controls.Xaml.Internals; using EObject = ElmSharp.EvasObject; @@ -11,6 +10,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen [UnconditionalSuppressMessage ("Trimming", "IL2075", Justification = TrimmerConstants.NativeBindingService)] public bool TrySetBinding(object target, string propertyName, BindingBase binding) { + Hosting.MauiAppBuilderExtensions.CheckForCompatibility(); var view = target as EObject; if (view == null) return false; @@ -22,6 +22,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public bool TrySetBinding(object target, BindableProperty property, BindingBase binding) { + Hosting.MauiAppBuilderExtensions.CheckForCompatibility(); var view = target as EObject; if (view == null) return false; @@ -31,6 +32,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public bool TrySetValue(object target, BindableProperty property, object value) { + Hosting.MauiAppBuilderExtensions.CheckForCompatibility(); var view = target as EObject; if (view == null) return false; diff --git a/src/Compatibility/Core/src/Tizen/NativeValueConverterService.cs b/src/Compatibility/Core/src/Tizen/NativeValueConverterService.cs index 7b22f3bf55..274b9cf5a5 100644 --- a/src/Compatibility/Core/src/Tizen/NativeValueConverterService.cs +++ b/src/Compatibility/Core/src/Tizen/NativeValueConverterService.cs @@ -1,6 +1,5 @@ using System; -using Microsoft.Maui.Controls.Compatibility.Internals; -using Microsoft.Maui.Controls.Compatibility.Xaml.Internals; +using Microsoft.Maui.Controls.Xaml.Internals; using EObject = ElmSharp.EvasObject; @@ -10,6 +9,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { public bool ConvertTo(object value, Type toType, out object nativeValue) { + Hosting.MauiAppBuilderExtensions.CheckForCompatibility(); nativeValue = null; if ((value is EObject) && toType.IsAssignableFrom(typeof(View))) { diff --git a/src/Compatibility/Core/src/Tizen/NativeViewWrapper.cs b/src/Compatibility/Core/src/Tizen/NativeViewWrapper.cs index 32a4251aa6..3aee745950 100644 --- a/src/Compatibility/Core/src/Tizen/NativeViewWrapper.cs +++ b/src/Compatibility/Core/src/Tizen/NativeViewWrapper.cs @@ -5,7 +5,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { public delegate ESize? 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) { diff --git a/src/Compatibility/Core/src/Tizen/PanGestureHandler.cs b/src/Compatibility/Core/src/Tizen/PanGestureHandler.cs index c6c90f60f4..8a3213fa1f 100644 --- a/src/Compatibility/Core/src/Tizen/PanGestureHandler.cs +++ b/src/Compatibility/Core/src/Tizen/PanGestureHandler.cs @@ -4,6 +4,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class PanGestureHandler : GestureHandler { int _currentPanGestureId; diff --git a/src/Compatibility/Core/src/Tizen/PinchGestureHandler.cs b/src/Compatibility/Core/src/Tizen/PinchGestureHandler.cs index 3e7cbf8bc4..a5888f2935 100644 --- a/src/Compatibility/Core/src/Tizen/PinchGestureHandler.cs +++ b/src/Compatibility/Core/src/Tizen/PinchGestureHandler.cs @@ -4,9 +4,10 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class PinchGestureHandler : GestureHandler { - Point _currentScalePoint; + Graphics.Point _currentScalePoint; int _previousPinchRadius; double _originalPinchScale; @@ -26,7 +27,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { var geometry = Platform.GetRenderer(sender).NativeView.Geometry; var zoomData = (GestureLayer.ZoomData)data; - _currentScalePoint = new Point((zoomData.X - geometry.X) / (double)geometry.Width, (zoomData.Y - geometry.Y) / (double)geometry.Height); + _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); diff --git a/src/Compatibility/Core/src/Tizen/Platform.cs b/src/Compatibility/Core/src/Tizen/Platform.cs index c89281a4e9..0ef8670bf9 100644 --- a/src/Compatibility/Core/src/Tizen/Platform.cs +++ b/src/Compatibility/Core/src/Tizen/Platform.cs @@ -5,20 +5,28 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Handlers; -[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Material")] +[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Material")] namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public static class Platform { internal static readonly BindableProperty RendererProperty = BindableProperty.CreateAttached("Renderer", typeof(IVisualElementRenderer), typeof(Platform), default(IVisualElementRenderer), propertyChanged: (bindable, oldvalue, newvalue) => { - var ve = bindable as VisualElement; - if (ve != null && newvalue == null) - ve.IsPlatformEnabled = false; + var view = bindable as VisualElement; + if (view != null) + view.IsPlatformEnabled = newvalue != null; + + if (bindable is IView mauiView) + { + if (mauiView.Handler == null && newvalue is IVisualElementRenderer ver) + mauiView.Handler = new RendererToHandlerShim(ver); + } }); public static IVisualElementRenderer GetRenderer(BindableObject bindable) @@ -43,14 +51,58 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen internal static IVisualElementRenderer CreateRenderer(VisualElement element) { - IVisualElementRenderer renderer = Forms.GetHandlerForObject(element) ?? new DefaultRenderer(); + IVisualElementRenderer renderer = null; + + if (renderer == null) + { + IViewHandler handler = null; + + //TODO: Handle this with AppBuilderHost + try + { + handler = Forms.MauiContext.Handlers.GetHandler(element.GetType()) as IViewHandler; + handler.SetMauiContext(Forms.MauiContext); + } + catch + { + // TODO define better catch response or define if this is needed? + } + + if (handler == null) + { + renderer = Forms.GetHandlerForObject(element) ?? new DefaultRenderer(); + } + // This means the only thing registered is the RendererToHandlerShim + // Which is only used when you are running a .NET MAUI app + // This indicates that the user hasn't registered a specific handler for this given type + else if (handler is RendererToHandlerShim shim) + { + renderer = shim.VisualElementRenderer; + + if (renderer == null) + { + renderer = Forms.GetHandlerForObject(element) ?? new DefaultRenderer(); + } + } + else if (handler is IVisualElementRenderer ver) + 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; + } + } renderer.SetElement(element); return renderer; } internal static ITizenPlatform CreatePlatform(EvasObject parent) { - if (Forms.PlatformType == PlatformType.Lightweight || Forms.Flags.Contains(Flags.LightweightPlatformExperimental)) + if (Forms.PlatformType == PlatformType.Lightweight) { return new LightweightPlatform(parent); } @@ -63,10 +115,13 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen widthConstraint = widthConstraint <= -1 ? double.PositiveInfinity : widthConstraint; heightConstraint = heightConstraint <= -1 ? double.PositiveInfinity : heightConstraint; - double width = !double.IsPositiveInfinity(widthConstraint) ? widthConstraint : Int32.MaxValue; - double height = !double.IsPositiveInfinity(heightConstraint) ? heightConstraint : Int32.MaxValue; + var renderView = GetRenderer(view); + if (renderView == null || renderView.NativeView == null) + { + return (view is IView iView) ? new SizeRequest(iView.Handler.GetDesiredSize(widthConstraint, heightConstraint)) : new SizeRequest(Graphics.Size.Zero); + } - return Platform.GetRenderer(view).GetDesiredSize(width, height); + return renderView.GetDesiredSize(widthConstraint, heightConstraint); } } @@ -87,6 +142,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public EvasObject RootNativeView { get; private set; } } + [Obsolete] public class DefaultPlatform : BindableObject, ITizenPlatform, INavigation { NavigationModel _navModel = new NavigationModel(); @@ -179,11 +235,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen ((Application)Page.RealParent).NavigationProxy.Inner = this; - Device.StartTimer(TimeSpan.Zero, () => - { - CurrentPageController?.SendAppearing(); - return false; - }); + Application.Current.Dispatcher.DispatchDelayed(TimeSpan.Zero, () => CurrentPageController?.SendAppearing()); } public bool SendBackButtonPressed() @@ -281,7 +333,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen async Task INavigation.PushModalAsync(Page modal, bool animated) { var previousPage = CurrentPageController; - Device.BeginInvokeOnMainThread(() => previousPage?.SendDisappearing()); + Application.Current.Dispatcher.Dispatch(() => previousPage?.SendDisappearing()); _navModel.PushModal(modal); diff --git a/src/Compatibility/Core/src/Tizen/PlatformEffect.cs b/src/Compatibility/Core/src/Tizen/PlatformEffect.cs deleted file mode 100644 index d5875e1577..0000000000 --- a/src/Compatibility/Core/src/Tizen/PlatformEffect.cs +++ /dev/null @@ -1,11 +0,0 @@ -using ElmSharp; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - /// - /// Base class for platform-specific effect classes. - /// - public abstract class PlatformEffect : PlatformEffect - { - } -} diff --git a/src/Compatibility/Core/src/Tizen/PopupManager.cs b/src/Compatibility/Core/src/Tizen/PopupManager.cs index 131a49fc19..c830f19774 100644 --- a/src/Compatibility/Core/src/Tizen/PopupManager.cs +++ b/src/Compatibility/Core/src/Tizen/PopupManager.cs @@ -1,14 +1,18 @@ using System; using System.Collections.Generic; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; -using Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific; +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 { + [Obsolete] public class PopupManager : IDisposable { ITizenPlatform _platform; @@ -23,7 +27,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen MessagingCenter.Subscribe(this, Page.AlertSignalName, OnAlertRequest); MessagingCenter.Subscribe(this, Page.ActionSheetSignalName, OnActionSheetRequest); MessagingCenter.Subscribe(this, Page.PromptSignalName, OnPromptRequested); - } + } public void Dispose() { @@ -93,7 +97,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen var alert = Native.Dialog.CreateDialog(Forms.NativeParent, (arguments.Accept != null)); alert.Title = arguments.Title; - var message = arguments.Message?.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace(Environment.NewLine, "
"); + 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 }; @@ -211,9 +215,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen var entry = new Entry { MinimumWidthRequest = 200, - HorizontalOptions = LayoutOptions.FillAndExpand, + HorizontalOptions = LayoutOptions.Fill, BackgroundColor = Color.FromRgb(250, 250, 250), - TextColor = Color.Black, + TextColor = Color.FromRgb(0, 0, 0), Keyboard = args.Keyboard, }; @@ -226,7 +230,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen entry.MaxLength = args.MaxLength; } - var layout = new StackLayout + var layout = new XStackLayout { Spacing = 10, Children = @@ -234,11 +238,13 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen new Label { LineBreakMode = LineBreakMode.CharacterWrap, - TextColor = DeviceInfo.Idiom == DeviceIdiom.Watch ? Color.White : Color.Accent, + TextColor = DeviceInfo.Idiom == DeviceIdiom.Watch ? Color.FromRgb(255,255,255) : Application.AccentColor, Text = args.Message, - HorizontalOptions = LayoutOptions.FillAndExpand, + 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, } diff --git a/src/Compatibility/Core/src/Tizen/PreloadedWindow.cs b/src/Compatibility/Core/src/Tizen/PreloadedWindow.cs index b92adb9aea..baa8aadf2f 100644 --- a/src/Compatibility/Core/src/Tizen/PreloadedWindow.cs +++ b/src/Compatibility/Core/src/Tizen/PreloadedWindow.cs @@ -1,10 +1,11 @@ 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 : Window + public class PreloadedWindow : EWindow { static PreloadedWindow s_precreated; diff --git a/src/Compatibility/Core/src/Tizen/Properties/AssemblyInfo.cs b/src/Compatibility/Core/src/Tizen/Properties/AssemblyInfo.cs index 408ab48f44..54f1710e1f 100644 --- a/src/Compatibility/Core/src/Tizen/Properties/AssemblyInfo.cs +++ b/src/Compatibility/Core/src/Tizen/Properties/AssemblyInfo.cs @@ -1,79 +1,6 @@ -using Microsoft.Maui.Controls.Compatibility; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; -using Microsoft.Maui.Controls.Compatibility.Shapes; +using System.Runtime.CompilerServices; +using Microsoft.Maui.Controls.Internals; -[assembly: Dependency(typeof(ResourcesProvider))] -[assembly: Dependency(typeof(Deserializer))] -[assembly: Dependency(typeof(NativeBindingService))] -[assembly: Dependency(typeof(NativeValueConverterService))] - -[assembly: ExportRenderer(typeof(Layout), typeof(LayoutRenderer))] -[assembly: ExportRenderer(typeof(ScrollView), typeof(ScrollViewRenderer))] -[assembly: ExportRenderer(typeof(CarouselPage), typeof(CarouselPageRenderer))] -[assembly: ExportRenderer(typeof(Page), typeof(PageRenderer))] -[assembly: ExportRenderer(typeof(NavigationPage), typeof(NavigationPageRenderer))] -#pragma warning disable CS0618 // Type or member is obsolete -[assembly: ExportRenderer(typeof(MasterDetailPage), typeof(MasterDetailPageRenderer))] -#pragma warning restore CS0618 // Type or member is obsolete -[assembly: ExportRenderer(typeof(FlyoutPage), typeof(FlyoutPageRenderer))] -[assembly: ExportRenderer(typeof(TabbedPage), typeof(TabbedPageRenderer))] -[assembly: ExportRenderer(typeof(Shell), typeof(ShellRenderer))] - -[assembly: ExportRenderer(typeof(Label), typeof(LabelRenderer))] -[assembly: ExportRenderer(typeof(Button), typeof(ButtonRenderer))] -[assembly: ExportRenderer(typeof(Image), typeof(ImageRenderer))] -[assembly: ExportRenderer(typeof(Slider), typeof(SliderRenderer))] -[assembly: ExportRenderer(typeof(Picker), typeof(PickerRenderer))] -[assembly: ExportRenderer(typeof(Frame), typeof(FrameRenderer))] -[assembly: ExportRenderer(typeof(Stepper), typeof(StepperRenderer))] -[assembly: ExportRenderer(typeof(DatePicker), typeof(DatePickerRenderer))] -[assembly: ExportRenderer(typeof(TimePicker), typeof(TimePickerRenderer))] -[assembly: ExportRenderer(typeof(ProgressBar), typeof(ProgressBarRenderer))] -[assembly: ExportRenderer(typeof(Switch), typeof(SwitchRenderer))] -[assembly: ExportRenderer(typeof(CheckBox), typeof(CheckBoxRenderer))] -[assembly: ExportRenderer(typeof(ListView), typeof(ListViewRenderer))] -[assembly: ExportRenderer(typeof(BoxView), typeof(BoxViewRenderer))] -[assembly: ExportRenderer(typeof(ActivityIndicator), typeof(ActivityIndicatorRenderer))] -[assembly: ExportRenderer(typeof(IndicatorView), typeof(IndicatorViewRenderer))] -[assembly: ExportRenderer(typeof(SearchBar), typeof(SearchBarRenderer))] -[assembly: ExportRenderer(typeof(Entry), typeof(EntryRenderer))] -[assembly: ExportRenderer(typeof(Editor), typeof(EditorRenderer))] -[assembly: ExportRenderer(typeof(TableView), typeof(TableViewRenderer))] -[assembly: ExportRenderer(typeof(NativeViewWrapper), typeof(NativeViewWrapperRenderer))] -[assembly: ExportRenderer(typeof(WebView), typeof(WebViewRenderer))] -[assembly: ExportRenderer(typeof(ImageButton), typeof(ImageButtonRenderer))] -[assembly: ExportRenderer(typeof(StructuredItemsView), typeof(StructuredItemsViewRenderer))] -[assembly: ExportRenderer(typeof(CarouselView), typeof(CarouselViewRenderer))] -[assembly: ExportRenderer(typeof(SwipeView), typeof(SwipeViewRenderer))] -[assembly: ExportRenderer(typeof(RefreshView), typeof(RefreshViewRenderer))] -[assembly: ExportRenderer(typeof(IndicatorView), typeof(IndicatorViewRenderer))] -[assembly: ExportRenderer(typeof(RadioButton), typeof(RadioButtonRenderer))] - -[assembly: ExportImageSourceHandler(typeof(FileImageSource), typeof(FileImageSourceHandler))] -[assembly: ExportImageSourceHandler(typeof(StreamImageSource), typeof(StreamImageSourceHandler))] -[assembly: ExportImageSourceHandler(typeof(UriImageSource), typeof(UriImageSourceHandler))] - -[assembly: ExportCell(typeof(TextCell), typeof(TextCellRenderer))] -[assembly: ExportCell(typeof(ImageCell), typeof(ImageCellRenderer))] -[assembly: ExportCell(typeof(SwitchCell), typeof(SwitchCellRenderer))] -[assembly: ExportCell(typeof(EntryCell), typeof(EntryCellRenderer))] -[assembly: ExportCell(typeof(ViewCell), typeof(ViewCellRenderer))] - -[assembly: ExportRenderer(typeof(EmbeddedFont), typeof(EmbeddedFontLoader))] - -[assembly: ExportHandler(typeof(TapGestureRecognizer), typeof(TapGestureHandler))] -[assembly: ExportHandler(typeof(PinchGestureRecognizer), typeof(PinchGestureHandler))] -[assembly: ExportHandler(typeof(PanGestureRecognizer), typeof(PanGestureHandler))] -[assembly: ExportHandler(typeof(SwipeGestureRecognizer), typeof(SwipeGestureHandler))] -[assembly: ExportHandler(typeof(DragGestureRecognizer), typeof(DragGestureHandler))] -[assembly: ExportHandler(typeof(DropGestureRecognizer), typeof(DropGestureHandler))] - -[assembly: ExportRenderer(typeof(Shell), typeof(Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch.ShellRenderer), TargetIdiom.Watch)] -[assembly: ExportRenderer(typeof(Shell), typeof(Microsoft.Maui.Controls.Compatibility.Platform.Tizen.TV.TVShellRenderer), TargetIdiom.TV)] - -[assembly: ExportRenderer(typeof(Ellipse), typeof(EllipseRenderer))] -[assembly: ExportRenderer(typeof(Line), typeof(LineRenderer))] -[assembly: ExportRenderer(typeof(Path), typeof(PathRenderer))] -[assembly: ExportRenderer(typeof(Polygon), typeof(PolygonRenderer))] -[assembly: ExportRenderer(typeof(Polyline), typeof(PolylineRenderer))] -[assembly: ExportRenderer(typeof(Microsoft.Maui.Controls.Compatibility.Shapes.Rectangle), typeof(RectangleRenderer))] +[assembly: Preserve] +[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Platform")] +[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Material")] \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ActivityIndicatorRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ActivityIndicatorRenderer.cs index 4234edf67f..42f7488c34 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ActivityIndicatorRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ActivityIndicatorRenderer.cs @@ -1,8 +1,10 @@ +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; @@ -28,10 +30,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateColor(bool initialize) { - if (initialize && Element.Color.IsDefault) + if (initialize && Element.Color.IsDefault()) return; - Control.Color = (Element.Color == Color.Default) ? s_defaultColor : Element.Color.ToPlatform(); + Control.Color = (Element.Color.IsDefault()) ? s_defaultColor : Element.Color.ToNative(); } void UpdateIsRunning() diff --git a/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs index 63c5d3126c..9823e21fb1 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs @@ -1,9 +1,11 @@ using System.ComponentModel; +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 BoxViewRenderer() @@ -33,10 +35,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected override void UpdateBackgroundColor(bool initialize) { - if (initialize && Element.BackgroundColor.IsDefault) + if (initialize && Element.BackgroundColor.IsDefault()) return; - if (Element.Color.IsDefault) + if (Element.Color.IsDefault()) { UpdateColor(); } @@ -71,9 +73,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateColor() { - if (Element.Color.IsDefault) + if (Element.Color.IsDefault()) { - if (Element.BackgroundColor.IsDefault) + if (Element.BackgroundColor.IsDefault()) { // Set to default color. (Transparent) Control.Color = EColor.Transparent; @@ -81,13 +83,13 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen else { // Use BackgroundColor only if color is default and background color is not default. - Control.Color = Element.BackgroundColor.MultiplyAlpha(Element.Opacity).ToPlatform(); + Control.Color = Element.BackgroundColor.MultiplyAlpha((float)Element.Opacity).ToNative(); } } else { // Color has higer priority than BackgroundColor. - Control.Color = Element.Color.MultiplyAlpha(Element.Opacity).ToPlatform(); + Control.Color = Element.Color.MultiplyAlpha((float)Element.Opacity).ToNative(); } } } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ButtonRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ButtonRenderer.cs index f51d3766d1..8933fb8cfb 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ButtonRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ButtonRenderer.cs @@ -1,10 +1,15 @@ 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.Compatibility.PlatformConfiguration.TizenSpecific.VisualElement; +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() @@ -61,8 +66,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen var style = Specific.GetStyle(Element); if (!string.IsNullOrEmpty(style)) { - (Control as IButton)?.UpdateStyle(style); - ((IVisualElementController)Element).NativeSizeChanged(); + (Control as NIButton)?.UpdateStyle(style); + ((IVisualElementController)Element).PlatformSizeChanged(); UpdateBackgroundColor(false); } } @@ -98,12 +103,12 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateText() { - (Control as IButton).Text = Element.Text ?? ""; + (Control as NIButton).Text = Element.Text ?? ""; } void UpdateFontSize() { - if (Control is IButton ib) + if (Control is NIButton ib) { ib.FontSize = Element.FontSize; } @@ -111,7 +116,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontAttributes() { - if (Control is IButton ib) + if (Control is NIButton ib) { ib.FontAttributes = Element.FontAttributes; } @@ -119,23 +124,23 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontFamily() { - if (Control is IButton ib) + if (Control is NIButton ib) { - ib.FontFamily = Element.FontFamily.ToNativeFontFamily(); + ib.FontFamily = Element.FontFamily.ToNativeFontFamily(Element.RequireFontManager()); } } void UpdateTextColor() { - if (Control is IButton ib) + if (Control is NIButton ib) { - ib.TextColor = Element.TextColor.ToPlatform(); + ib.TextColor = Element.TextColor.ToPlatformEFL(); } } void UpdateBitmap() { - if (Control is IButton ib) + if (Control is NIButton ib) { if (Element.ImageSource != null) { diff --git a/src/Compatibility/Core/src/Tizen/Renderers/CarouselPageRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/CarouselPageRenderer.cs index 69602c6a13..e072950006 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/CarouselPageRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/CarouselPageRenderer.cs @@ -2,17 +2,21 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using ElmSharp; +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Devices; using EBox = ElmSharp.Box; using ELayout = ElmSharp.Layout; using ERect = ElmSharp.Rect; using ESize = ElmSharp.Size; +using Index = ElmSharp.Index; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] /// /// Renderer of a CarouselPage widget. /// - public class CarouselPageRenderer : VisualElementRenderer + internal class CarouselPageRenderer : VisualElementRenderer { const int ItemMaxCount = 20; const int OddMiddleItem = 10; @@ -137,7 +141,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { _scroller.Geometry = _outterLayout.Geometry; var newGeometry = _outterLayout.Geometry; - if (Device.Idiom != TargetIdiom.Watch) + if (DeviceInfo.Idiom != DeviceIdiom.Watch) newGeometry.Y += (int)(newGeometry.Height * 0.9); newGeometry.Height = (int)(newGeometry.Height * 0.1); _index.Geometry = newGeometry; @@ -171,8 +175,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void OnCurrentPageChanged(object sender, EventArgs e) { - CustomFocusManager.StartReorderTabIndex(); - Element.UpdateFocusTreePolicy(); if (IsChangedByScroll()) diff --git a/src/Compatibility/Core/src/Tizen/Renderers/CarouselViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/CarouselViewRenderer.cs index 2fd6c864c4..0d616c8d16 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/CarouselViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/CarouselViewRenderer.cs @@ -2,10 +2,12 @@ using System; using System.Collections.Generic; using System.ComponentModel; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class CarouselViewRenderer : ItemsViewRenderer { List _oldViews = new List(); @@ -41,7 +43,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen _animationStart = new SmartEvent(Control.Scroll, Control.Scroll.RealHandle, ThemeConstants.Scroller.Signals.StartScrollAnimation); _animationStart.On += OnScrollStart; } - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { UpdatePositionFromElement(false); UpdateCurrentItemFromElement(false); diff --git a/src/Compatibility/Core/src/Tizen/Renderers/CheckBoxRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/CheckBoxRenderer.cs index fc60d0cd79..73cbeae02b 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/CheckBoxRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/CheckBoxRenderer.cs @@ -1,9 +1,11 @@ using System; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class CheckBoxRenderer : ViewRenderer { public CheckBoxRenderer() @@ -46,16 +48,16 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateOnColor(bool initialize) { - if (initialize && Element.Color.IsDefault) + if (initialize && Element.Color.IsDefault()) return; - if (Element.Color.IsDefault) + if (Element.Color.IsDefault()) { Control.DeleteOnColors(); } else { - Control.SetOnColors(Element.Color.ToPlatform()); + Control.SetOnColors(Element.Color.ToNative()); } } } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/CustomFocusManager.cs b/src/Compatibility/Core/src/Tizen/Renderers/CustomFocusManager.cs index 2668fde47b..fb6e0c4d08 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/CustomFocusManager.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/CustomFocusManager.cs @@ -7,23 +7,18 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] class CustomFocusManager : IDisposable { - static bool s_reorderTriggered; - static readonly ObservableCollection s_tabIndexList = new ObservableCollection(); - VisualElement _nextUp; VisualElement _nextDown; VisualElement _nextLeft; VisualElement _nextRight; VisualElement _nextForward; VisualElement _nextBackward; - int _tabIndex = -1; - bool _isTabStop = true; static CustomFocusManager() { - s_tabIndexList.CollectionChanged += TabIndexCollectionChanged; } public CustomFocusManager(VisualElement element, Widget nativeView) @@ -40,52 +35,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen VisualElement Element { get; } Widget NativeView { get; } - public int TabIndex - { - get - { - return _tabIndex; - } - set - { - if (IsTabStop) - { - if (_tabIndex > -1) - { - s_tabIndexList.Remove(this); - } - if (value > -1) - { - s_tabIndexList.Add(this); - } - } - _tabIndex = value; - } - } - - public bool IsTabStop - { - get - { - return _isTabStop; - } - set - { - if (TabIndex > -1) - { - if (_isTabStop) - { - s_tabIndexList.Remove(this); - } - if (value) - { - s_tabIndexList.Add(this); - } - } - _isTabStop = value; - } - } - public VisualElement NextUp { get => _nextUp; @@ -152,23 +101,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen GC.SuppressFinalize(this); } - public static void StartReorderTabIndex() - { - if (Device.IsInvokeRequired) - { - Device.BeginInvokeOnMainThread(() => - { - StartReorderTabIndex(); - }); - return; - } - if (!s_reorderTriggered) - { - s_reorderTriggered = true; - Device.BeginInvokeOnMainThread(ReorderTabIndex); - } - } - protected virtual void Dispose(bool disposing) { if (disposing) @@ -198,10 +130,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen NextBackward.PropertyChanged -= OnNextViewPropertyChanged; } } - if (s_tabIndexList.Contains(this)) - { - s_tabIndexList.Remove(this); - } } void SetUpFocus(VisualElement next, FocusDirection direction) @@ -251,36 +179,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen return FocusDirection.Next; } - static void ReorderTabIndex() - { - s_reorderTriggered = false; - var list = s_tabIndexList.Where((t) => t.IsTabStop && ElementIsVisible(t)).OrderBy(x => x.Element.TabIndex); - CustomFocusManager first = null; - CustomFocusManager last = null; - foreach (var item in list) - { - if (first == null) - first = item; - - if (last != null) - { - item.NextBackward = last.Element; - last.NextForward = item.Element; - } - last = item; - } - if (first != null && last != null) - { - first.NextBackward = last.Element; - last.NextForward = first.Element; - } - } - - static void TabIndexCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - StartReorderTabIndex(); - } - static bool PageIsVisible(Page page) { if (page == null) @@ -305,9 +203,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { return false; } -#pragma warning disable CS0618 // Type or member is obsolete - if (parentPage is MasterDetailPage mdPage && mdPage.Master == parent && !mdPage.IsPresented) -#pragma warning restore CS0618 // Type or member is obsolete + if (parentPage is FlyoutPage flyoutPage && flyoutPage.Flyout == parent && !flyoutPage.IsPresented) { return false; } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/DatePickerRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/DatePickerRenderer.cs index bf011cb5e3..ae6ea1aec0 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/DatePickerRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/DatePickerRenderer.cs @@ -1,11 +1,16 @@ using System; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; +using Microsoft.Maui.Devices; +using Microsoft.Maui.Graphics; +using NIEntery = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.IEntry; using EEntry = ElmSharp.Entry; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Application; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Application; using WatchDateTimePickerDialog = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch.WatchDateTimePickerDialog; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class DatePickerRenderer : ViewRenderer { //TODO need to add internationalization support @@ -42,7 +47,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen entry.SetVerticalTextAlignment(0.5); SetNativeControl(entry); - if (entry is IEntry ie) + if (entry is NIEntery ie) { ie.TextBlockFocused += OnTextBlockFocused; ie.EntryLayoutFocused += OnFocused; @@ -91,7 +96,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { if (Control != null) { - if (Control is IEntry ie) + if (Control is NIEntery ie) { ie.TextBlockFocused -= OnTextBlockFocused; ie.EntryLayoutFocused -= OnFocused; @@ -121,7 +126,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen dialog.MinimumDateTime = Element.MinimumDate; // You need to call Show() after ui thread occupation because of EFL problem. // Otherwise, the content of the popup will not receive focus. - Device.BeginInvokeOnMainThread(() => dialog.Show()); + Application.Current.Dispatcher.Dispatch(() => dialog.Show()); } } @@ -138,9 +143,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void UpdateTextColor() { - if (Control is IEntry ie) + if (Control is NIEntery ie) { - ie.TextColor = Element.TextColor.ToPlatform(); + ie.TextColor = Element.TextColor.ToPlatformEFL(); } } @@ -167,7 +172,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontSize() { - if (Control is IEntry ie) + if (Control is NIEntery ie) { ie.FontSize = Element.FontSize; } @@ -175,7 +180,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontFamily() { - if (Control is IEntry ie) + if (Control is NIEntery ie) { ie.FontFamily = Element.FontFamily; } @@ -183,7 +188,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontAttributes() { - if (Control is IEntry ie) + if (Control is NIEntery ie) { ie.FontAttributes = Element.FontAttributes; } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/DefaultRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/DefaultRenderer.cs index 210de2214b..bb6ef92f5d 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/DefaultRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/DefaultRenderer.cs @@ -1,9 +1,9 @@ -using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Shapes; +using Microsoft.Maui.Controls.Platform; using ELayout = ElmSharp.Layout; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete] public sealed class DefaultRenderer : VisualElementRenderer { protected override void OnElementChanged(ElementChangedEventArgs e) @@ -17,18 +17,25 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class EllipseRenderer : ShapeRenderer { } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class LineRenderer : ShapeRenderer { } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class PathRenderer : ShapeRenderer { } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class PolygonRenderer : ShapeRenderer { } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class PolylineRenderer : ShapeRenderer { } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class RectangleRenderer : ShapeRenderer { } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShapeRenderer : VisualElementRenderer { protected override void OnElementChanged(ElementChangedEventArgs e) diff --git a/src/Compatibility/Core/src/Tizen/Renderers/EditorRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/EditorRenderer.cs index 464e3d67f7..74946edd72 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/EditorRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/EditorRenderer.cs @@ -1,9 +1,14 @@ using System; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; +using Microsoft.Maui.Devices; +using Microsoft.Maui.Graphics; using EEntry = ElmSharp.Entry; +using NIEntry = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.IEntry; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class EditorRenderer : ViewRenderer { public EditorRenderer() @@ -30,7 +35,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen entry.Unfocused += OnEntryUnfocused; entry.Unfocused += OnCompleted; entry.PrependMarkUpFilter(MaxLengthFilter); - if (entry is IEntry ie) + if (entry is NIEntry ie) { ie.TextChanged += OnTextChanged; ie.EntryLayoutFocused += OnFocused; @@ -61,7 +66,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Control.BackButtonPressed -= OnCompleted; Control.Unfocused -= OnEntryUnfocused; Control.Focused -= OnEntryFocused; - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.TextChanged -= OnTextChanged; ie.EntryLayoutFocused -= OnFocused; @@ -79,9 +84,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void UpdateTextColor() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.TextColor = Element.TextColor.ToPlatform(); + ie.TextColor = Element.TextColor.ToPlatformEFL(); } } @@ -127,7 +132,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontSize() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontSize = Element.FontSize; } @@ -135,15 +140,15 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontFamily() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.FontFamily = Element.FontFamily.ToNativeFontFamily(); + ie.FontFamily = Element.FontFamily.ToNativeFontFamily(Element.RequireFontManager()); } } void UpdateFontAttributes() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontAttributes = Element.FontAttributes; } @@ -154,7 +159,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (initialize && Element.Keyboard == Keyboard.Default) return; - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.UpdateKeyboard(Element.Keyboard, Element.IsSpellCheckEnabled, true); } @@ -173,7 +178,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdatePlaceholder() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.Placeholder = Element.Placeholder; } @@ -181,9 +186,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdatePlaceholderColor() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.PlaceholderColor = Element.PlaceholderColor.ToPlatform(); + ie.PlaceholderColor = Element.PlaceholderColor.ToPlatformEFL(); } } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/EntryRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/EntryRenderer.cs index 12aa5a1770..08c9b39dce 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/EntryRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/EntryRenderer.cs @@ -1,11 +1,14 @@ using System; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using EEntry = ElmSharp.Entry; -using IEntry = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.IEntry; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Entry; +using NIEntry = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.IEntry; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Entry; +using Size = Microsoft.Maui.Graphics.Size; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class EntryRenderer : ViewRenderer { SmartEvent _selectionCleared; @@ -49,7 +52,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen _selectionCleared = new SmartEvent(entry, entry.RealHandle, ThemeConstants.Entry.Signals.SelectionCleared); _selectionCleared.On += OnSelectionCleared; - if (entry is IEntry ie) + if (entry is NIEntry ie) { ie.TextChanged += OnTextChanged; ie.EntryLayoutFocused += OnFocused; @@ -59,7 +62,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen SetNativeControl(entry); // An initial CursorPosition is set after layouting to avoid timing issue when the EditField entry is initialized. - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { UpdateSelectionLength(false); }); @@ -85,7 +88,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Control.Activated -= OnCompleted; Control.CursorChanged -= OnCursorChanged; - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.TextChanged -= OnTextChanged; ie.EntryLayoutFocused -= OnFocused; @@ -119,14 +122,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void OnCompleted(object sender, EventArgs e) { - if (Element.ReturnType == ReturnType.Next) - { - FocusSearch(true)?.SetFocus(true); - } - else - { - Control.SetFocus(false); - } + Control.SetFocus(false); ((IEntryController)Element).SendCompleted(); } @@ -146,15 +142,15 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void UpdateTextColor() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.TextColor = Element.TextColor.ToPlatform(); + ie.TextColor = Element.TextColor.ToPlatformEFL(); } } void UpdateFontSize() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontSize = Element.FontSize; } @@ -162,15 +158,15 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontFamily() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.FontFamily = Element.FontFamily.ToNativeFontFamily(); + ie.FontFamily = Element.FontFamily.ToNativeFontFamily(Element.RequireFontManager()); } } void UpdateFontAttributes() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontAttributes = Element.FontAttributes; } @@ -178,9 +174,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateHorizontalTextAlignment() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToPlatform(); + ie.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToNative(); } } @@ -195,7 +191,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (initialize && Element.Keyboard == Keyboard.Default) return; - (Control as IEntry)?.UpdateKeyboard(Element.Keyboard, Element.IsSpellCheckEnabled, Element.IsTextPredictionEnabled); + (Control as NIEntry)?.UpdateKeyboard(Element.Keyboard, Element.IsSpellCheckEnabled, Element.IsTextPredictionEnabled); } void UpdateIsSpellCheckEnabled() @@ -205,7 +201,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdatePlaceholder() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.Placeholder = Element.Placeholder; } @@ -213,15 +209,15 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdatePlaceholderColor() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.PlaceholderColor = Element.PlaceholderColor.ToPlatform(); + ie.PlaceholderColor = Element.PlaceholderColor.ToPlatformEFL(); } } void UpdateFontWeight() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontWeight = Specific.GetFontWeight(Element); } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/FastLayoutRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/FastLayoutRenderer.cs index 25ae0ff4bb..5d57c87b13 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/FastLayoutRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/FastLayoutRenderer.cs @@ -1,9 +1,11 @@ using System; using System.ComponentModel; using SkiaSharp.Views.Tizen; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class FastLayoutRenderer : ViewRenderer, SkiaSharp.IBackgroundCanvas, ILayoutRenderer { bool _layoutUpdatedRegistered = false; diff --git a/src/Compatibility/Core/src/Tizen/Renderers/FlyoutContainer.cs b/src/Compatibility/Core/src/Tizen/Renderers/FlyoutContainer.cs index d06655d1fc..1ea13ab43d 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/FlyoutContainer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/FlyoutContainer.cs @@ -2,6 +2,7 @@ using System; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Renderers { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class FlyoutContainer : ElmSharp.Box, IDisposable { readonly FlyoutPage _parent; @@ -51,7 +52,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Renderers if (_hasAppearedToParent) { - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { if (!_disposed && _hasAppearedToParent) PageController?.SendAppearing(); diff --git a/src/Compatibility/Core/src/Tizen/Renderers/FlyoutPageRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/FlyoutPageRenderer.cs index 2c75df587c..bf63fd79ed 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/FlyoutPageRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/FlyoutPageRenderer.cs @@ -1,8 +1,10 @@ using System; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Renderers; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class FlyoutPageRenderer : VisualElementRenderer { Native.FlyoutPage _flyoutPage; @@ -140,9 +142,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateIsPresented() { - // To update TabIndex order - CustomFocusManager.StartReorderTabIndex(); - _flyoutPage.IsPresented = Element.IsPresented; } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/FrameRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/FrameRenderer.cs index 8630e373fc..bf9b8f3eca 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/FrameRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/FrameRenderer.cs @@ -1,8 +1,10 @@ +using Microsoft.Maui.Controls.Platform; using EColor = ElmSharp.Color; using EPolygon = ElmSharp.Polygon; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class FrameRenderer : LayoutRenderer { const int _thickness = 2; @@ -104,10 +106,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateColor() { - if ((Element as Frame).BorderColor.IsDefault) + if ((Element as Frame).BorderColor.IsDefault()) _frame.Color = s_DefaultColor; else - _frame.Color = (Element as Frame).BorderColor.ToPlatform(); + _frame.Color = (Element as Frame).BorderColor.ToNative(); } void UpdateShadowVisibility() diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ILayoutRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ILayoutRenderer.cs index 9e587bcbb1..c11d922afe 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ILayoutRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ILayoutRenderer.cs @@ -1,5 +1,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public interface ILayoutRenderer { void RegisterOnLayoutUpdated(); diff --git a/src/Compatibility/Core/src/Tizen/Renderers/IVisualElementRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/IVisualElementRenderer.cs index e2e2de0809..df238d13ed 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/IVisualElementRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/IVisualElementRenderer.cs @@ -1,5 +1,6 @@ using System; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using ERect = ElmSharp.Rect; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen @@ -27,6 +28,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen get; } + event EventHandler ElementChanged; + /// /// Sets the VisualElement associated with this renderer. /// diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ImageButtonRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ImageButtonRenderer.cs index 4c135e2ff3..28bf84ee0c 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ImageButtonRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ImageButtonRenderer.cs @@ -1,10 +1,12 @@ using System; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using EButton = ElmSharp.Button; using ERect = ElmSharp.Rect; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ImageButtonRenderer : ViewRenderer { public ImageButtonRenderer() @@ -64,7 +66,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected override void UpdateBackgroundColor(bool initialize) { - _round.Color = Element.BackgroundColor.ToPlatform(); + _round.Color = Element.BackgroundColor.ToNative(); } protected override void Dispose(bool disposing) @@ -138,7 +140,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (!IsDisposed && success) { - (Element as IVisualElementController)?.NativeSizeChanged(); + (Element as IVisualElementController)?.PlatformSizeChanged(); UpdateAfterLoading(); } } @@ -184,7 +186,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateBorderColor() { - _border.Color = Element.BorderColor.ToPlatform(); + _border.Color = Element.BorderColor.ToNative(); } void UpdateAspect() diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ImageRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ImageRenderer.cs index 0706c464da..63c9c977d3 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ImageRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ImageRenderer.cs @@ -1,12 +1,13 @@ using System.ComponentModel; using System.Threading; using System.Threading.Tasks; +using Microsoft.Maui.Controls.Platform; using EImage = ElmSharp.Image; - -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Image; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Image; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ImageRenderer : ViewRenderer { public ImageRenderer() @@ -42,7 +43,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (!IsDisposed && success) { - ((IVisualElementController)Element).NativeSizeChanged(); + ((IVisualElementController)Element).PlatformSizeChanged(); UpdateAfterLoading(initialize); } } @@ -62,7 +63,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (!IsDisposed && success) { - ((IVisualElementController)Element).NativeSizeChanged(); + ((IVisualElementController)Element).PlatformSizeChanged(); UpdateAfterLoading(initialize); } } @@ -102,10 +103,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateBlendColor(bool initialize) { - if (initialize && Specific.GetBlendColor(Element).IsDefault) + if (initialize && Specific.GetBlendColor(Element) == null) return; - Control.Color = Specific.GetBlendColor(Element).ToPlatform(); + Control.Color = Specific.GetBlendColor(Element).ToPlatformEFL(); } } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/IndicatorViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/IndicatorViewRenderer.cs index e908a84ba6..b7f8b5f8b5 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/IndicatorViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/IndicatorViewRenderer.cs @@ -1,5 +1,8 @@ +using Microsoft.Maui.Controls.Platform; + namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class IndicatorViewRenderer : ViewRenderer { public IndicatorViewRenderer() diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ItemsViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ItemsViewRenderer.cs index 6ce1ea1624..4b7bb631f8 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ItemsViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ItemsViewRenderer.cs @@ -1,12 +1,13 @@ using System.Collections.Specialized; using System.Linq; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; - -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.ItemsView; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.ItemsView; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public abstract class ItemsViewRenderer : ViewRenderer where TItemsView : ItemsView where TNative : Native.CollectionView @@ -86,7 +87,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void OnLayoutPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(Microsoft.Maui.Controls.Compatibility.ItemsLayout.SnapPointsType)) + if (e.PropertyName == nameof(Microsoft.Maui.Controls.ItemsLayout.SnapPointsType)) { Control.SnapPointsType = (sender as ItemsLayout)?.SnapPointsType ?? SnapPointsType.None; } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/LabelRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/LabelRenderer.cs index 8e47cef0e5..0387c4dcd0 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/LabelRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/LabelRenderer.cs @@ -1,8 +1,11 @@ +using Microsoft.Maui.Graphics; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Label; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Label; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class LabelRenderer : ViewRenderer { @@ -52,8 +55,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen nativeSpan.FontAttributes = span.FontAttributes; nativeSpan.FontFamily = span.FontFamily; nativeSpan.FontSize = span.FontSize; - nativeSpan.ForegroundColor = span.TextColor.ToPlatform(); - nativeSpan.BackgroundColor = span.BackgroundColor.ToPlatform(); + nativeSpan.ForegroundColor = span.TextColor.ToPlatformEFL(); + nativeSpan.BackgroundColor = span.BackgroundColor.ToPlatformEFL(); nativeSpan.Underline = (textDecorations & TextDecorations.Underline) != 0; nativeSpan.Strikethrough = (textDecorations & TextDecorations.Strikethrough) != 0; nativeSpan.LineHeight = span.LineHeight; @@ -78,6 +81,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Control.FormattedText = ConvertFormattedText(Element.FormattedText); } + [PortHandler] void UpdateText() { Control.Text = Element.Text ?? ""; @@ -85,17 +89,17 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateTextColor() { - Control.TextColor = Element.TextColor.ToPlatform(); + Control.TextColor = Element.TextColor.ToPlatformEFL(); } void UpdateHorizontalTextAlignment() { - Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToPlatform(); + Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToNative(); } void UpdateVerticalTextAlignment() { - Control.VerticalTextAlignment = Element.VerticalTextAlignment.ToPlatform(); + Control.VerticalTextAlignment = Element.VerticalTextAlignment.ToNative(); } void UpdateFontProperties() @@ -104,7 +108,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Control.FontSize = Element.FontSize; Control.FontAttributes = Element.FontAttributes; - Control.FontFamily = Element.FontFamily.ToNativeFontFamily(); + Control.FontFamily = Element.FontFamily.ToNativeFontFamily(Element.RequireFontManager()); Control.BatchCommit(); } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/LayoutRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/LayoutRenderer.cs index e8b4dcb19a..37e2fce15a 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/LayoutRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/LayoutRenderer.cs @@ -1,9 +1,11 @@ using System; using System.ComponentModel; using SkiaSharp.Views.Tizen; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] /// /// Renderer of a Layout. /// @@ -67,7 +69,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen _layoutUpdatedRegistered = false; } - if (Forms.UseSkiaSharp) + if (Forms.UseSkiaSharp && Control != null) { Control.LayoutUpdated -= OnBackgroundLayoutUpdated; diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ListViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ListViewRenderer.cs index 69d29a71a7..e0220fff33 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ListViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ListViewRenderer.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Specialized; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Devices; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] /// /// Renderer class for Xamarin ListView class. This provides necessary logic translating /// Xamarin API to Tizen Native API. This is a derivate of a ViewRenderer base class. @@ -394,7 +397,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateSeparator() { - Control.BottomLineColor = Element.SeparatorVisibility == SeparatorVisibility.Default ? Element.SeparatorColor.ToPlatform() : EColor.Transparent; + Control.BottomLineColor = Element.SeparatorVisibility == SeparatorVisibility.Default ? Element.SeparatorColor.ToPlatformEFL() : EColor.Transparent; } } } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/MasterDetailContainer.cs b/src/Compatibility/Core/src/Tizen/Renderers/MasterDetailContainer.cs deleted file mode 100644 index 24228c62ef..0000000000 --- a/src/Compatibility/Core/src/Tizen/Renderers/MasterDetailContainer.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Renderers -{ - [Obsolete("MasterDetailContainer is obsolete as of version 5.0.0. Please use FlyoutContainer instead.")] - public class MasterDetailContainer : ElmSharp.Box, IDisposable - { -#pragma warning disable CS0618 // Type or member is obsolete - readonly MasterDetailPage _parent; -#pragma warning restore CS0618 // Type or member is obsolete - readonly bool _isMaster; - - VisualElement _childView; - bool _disposed; - bool _hasAppearedToParent; - - IPageController PageController => ChildView as IPageController; - - IMasterDetailPageController MasterDetailPageController => _parent as IMasterDetailPageController; - -#pragma warning disable CS0618 // Type or member is obsolete - public MasterDetailContainer(MasterDetailPage parentElement, bool isMaster) : base(Forms.NativeParent) -#pragma warning restore CS0618 // Type or member is obsolete - { - _parent = parentElement; - _isMaster = isMaster; - - SetLayoutCallback(OnLayoutUpdated); - Show(); - } - - ~MasterDetailContainer() - { - Dispose(false); - } - - public VisualElement ChildView - { - get { return _childView; } - set - { - if (_childView == value) - return; - - if (_childView != null) - { - RemoveChildView(); - } - - _childView = value; - - if (_childView == null) - return; - - AddChildView(_childView); - - if (_hasAppearedToParent) - { - Device.BeginInvokeOnMainThread(() => - { - if (!_disposed && _hasAppearedToParent) - PageController?.SendAppearing(); - }); - } - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected void RemoveChildView() - { - IVisualElementRenderer childRenderer = Platform.GetRenderer(_childView); - if (childRenderer != null) - { - UnPack(childRenderer.NativeView); - childRenderer.Dispose(); - } - } - - protected void AddChildView(VisualElement childView) - { - IVisualElementRenderer renderer = Platform.GetOrCreateRenderer(childView); - this.PackEnd(renderer.NativeView); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed) - return; - - if (disposing) - { - if (_childView != null) - { - RemoveChildView(); - } - SetLayoutCallback(null); - } - _disposed = true; - } - - void OnLayoutUpdated() - { - if (_childView != null) - { - if (_isMaster) - MasterDetailPageController.MasterBounds = this.Geometry.ToDP(); - else - MasterDetailPageController.DetailBounds = this.Geometry.ToDP(); - - IVisualElementRenderer renderer = Platform.GetRenderer(_childView); - renderer.NativeView.Geometry = this.Geometry; - } - } - - public void SendAppearing() - { - if (_hasAppearedToParent) - return; - - _hasAppearedToParent = true; - - PageController?.SendAppearing(); - } - - public void SendDisappearing() - { - if (!_hasAppearedToParent) - return; - - _hasAppearedToParent = false; - - PageController?.SendDisappearing(); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/Renderers/MasterDetailPageRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/MasterDetailPageRenderer.cs deleted file mode 100644 index db2708f7fc..0000000000 --- a/src/Compatibility/Core/src/Tizen/Renderers/MasterDetailPageRenderer.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Renderers; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ -#pragma warning disable CS0618 // Type or member is obsolete - [Obsolete("MasterDetailPage is obsolete as of version 5.0.0. Please use FlyoutPage instead.")] - public class MasterDetailPageRenderer : VisualElementRenderer - { - Native.FlyoutPage _mdpage; - MasterDetailContainer _masterContainer = null; - MasterDetailContainer _detailContainer = null; - - /// - /// Default constructor. - /// - public MasterDetailPageRenderer() - { - RegisterPropertyHandler(nameof(Element.Master), UpdateMasterPage); - RegisterPropertyHandler(nameof(Element.Detail), UpdateDetailPage); - RegisterPropertyHandler(MasterDetailPage.IsPresentedProperty, - UpdateIsPresented); - RegisterPropertyHandler(MasterDetailPage.MasterBehaviorProperty, - UpdateMasterBehavior); - RegisterPropertyHandler(MasterDetailPage.IsGestureEnabledProperty, - UpdateIsGestureEnabled); - } - - protected override void OnElementChanged(ElementChangedEventArgs e) - { - if (_mdpage == null) - { - _mdpage = new Native.FlyoutPage(Forms.NativeParent) - { - IsPresented = e.NewElement.IsPresented, - Flyout = _masterContainer = new MasterDetailContainer(Element, true), - Detail = _detailContainer = new MasterDetailContainer(Element, false), - }; - - _mdpage.IsPresentedChanged += (sender, ev) => - { - Element.IsPresented = ev.IsPresent; - }; - _mdpage.UpdateIsPresentChangeable += (sender, ev) => - { - (Element as IMasterDetailPageController).CanChangeIsPresented = ev.CanChange; - }; - SetNativeView(_mdpage); - } - - if (e.OldElement != null) - { - (e.OldElement as IMasterDetailPageController).BackButtonPressed -= OnBackButtonPressed; - e.OldElement.Appearing -= OnMasterDetailAppearing; - e.OldElement.Disappearing -= OnMasterDetailDisappearing; - } - - if (e.NewElement != null) - { - (e.NewElement as IMasterDetailPageController).BackButtonPressed += OnBackButtonPressed; - e.NewElement.Appearing += OnMasterDetailAppearing; - e.NewElement.Disappearing += OnMasterDetailDisappearing; - } - - UpdateMasterBehavior(); - base.OnElementChanged(e); - } - - void OnMasterDetailDisappearing(object sender, EventArgs e) - { - _masterContainer?.SendDisappearing(); - _detailContainer?.SendDisappearing(); - } - - void OnMasterDetailAppearing(object sender, EventArgs e) - { - _masterContainer?.SendAppearing(); - _detailContainer?.SendAppearing(); - } - - protected override void OnElementReady() - { - base.OnElementReady(); - UpdateMasterPage(false); - UpdateDetailPage(false); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (_masterContainer != null) - { - _masterContainer.Dispose(); - _masterContainer = null; - } - - if (_detailContainer != null) - { - _detailContainer.Dispose(); - _detailContainer = null; - } - - if (Element != null) - { - Element.Appearing -= OnMasterDetailAppearing; - Element.Disappearing -= OnMasterDetailDisappearing; - } - } - - base.Dispose(disposing); - } - - protected void UpdateMasterPageRatio(double popoverRatio, double splitRatio) - { - _mdpage.PopoverRatio = popoverRatio; - _mdpage.SplitRatio = splitRatio; - } - - void OnBackButtonPressed(object sender, BackButtonPressedEventArgs e) - { - if ((Element != null) && Element.IsPresented && !_mdpage.IsSplit) - { - Element.IsPresented = false; - e.Handled = true; - } - } - - void UpdateMasterBehavior() - { - _mdpage.FlyoutLayoutBehavior = (FlyoutLayoutBehavior)Element.MasterBehavior; - } - - void UpdateMasterPage(bool isInit) - { - if (!isInit) - _masterContainer.ChildView = Element.Master; - } - - void UpdateDetailPage(bool isInit) - { - if (!isInit) - _detailContainer.ChildView = Element.Detail; - } - - void UpdateIsPresented() - { - // To update TabIndex order - CustomFocusManager.StartReorderTabIndex(); - - _mdpage.IsPresented = Element.IsPresented; - } - - void UpdateIsGestureEnabled() - { - _mdpage.IsGestureEnabled = Element.IsGestureEnabled; - } - } -#pragma warning restore CS0618 // Type or member is obsolete -} diff --git a/src/Compatibility/Core/src/Tizen/Renderers/NativeViewWrapperRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/NativeViewWrapperRenderer.cs index 7132649ce0..ef868692bb 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/NativeViewWrapperRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/NativeViewWrapperRenderer.cs @@ -1,9 +1,12 @@ using ElmSharp; +using Microsoft.Maui.Controls.Platform; using ESize = ElmSharp.Size; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { +#pragma warning disable CS0618 // Type or member is obsolete public class NativeViewWrapperRenderer : ViewRenderer +#pragma warning disable CS0618 // Type or member is obsolete { protected override void OnElementChanged(ElementChangedEventArgs e) { diff --git a/src/Compatibility/Core/src/Tizen/Renderers/NavigationPageRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/NavigationPageRenderer.cs index 721100fe7c..1c765c06ff 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/NavigationPageRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/NavigationPageRenderer.cs @@ -3,16 +3,18 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; -using Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific; using EButton = ElmSharp.Button; using EToolbar = ElmSharp.Toolbar; using EToolbarItem = ElmSharp.ToolbarItem; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.NavigationPage; -using SpecificPage = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Page; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.NavigationPage; +using SpecificPage = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Page; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class NavigationPageRenderer : VisualElementRenderer { enum ToolbarButtonPosition @@ -117,7 +119,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (e.PropertyName == NavigationPage.CurrentPageProperty.PropertyName) { - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { (_previousPage as IPageController)?.SendDisappearing(); _previousPage = Element.CurrentPage; @@ -228,14 +230,14 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { Text = Title, HorizontalTextAlignment = Native.TextAlignment.Center, - ForegroundColor = Element.BarTextColor.ToPlatform() + ForegroundColor = Element.BarTextColor.ToPlatformEFL() }; return span.GetMarkupText(); } void UpdateBarBackgroundColor(NaviItem item) { - item.TitleBarBackgroundColor = Element.BarBackgroundColor.ToPlatform(); + item.TitleBarBackgroundColor = Element.BarBackgroundColor.ToPlatformEFL(); } void UpdateNavigationBar(Page page, NaviItem item = null) diff --git a/src/Compatibility/Core/src/Tizen/Renderers/PageRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/PageRenderer.cs index b76dca7378..fc15cad337 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/PageRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/PageRenderer.cs @@ -2,7 +2,9 @@ using System; using System.Collections.Specialized; using ElmSharp.Wearable; using SkiaSharp.Views.Tizen; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch; +using Microsoft.Maui.Devices; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen @@ -10,6 +12,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// /// Renderer of ContentPage. /// + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class PageRenderer : VisualElementRenderer, SkiaSharp.IBackgroundCanvas { Native.Page _page; @@ -102,14 +105,14 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected override void UpdateBackgroundColor(bool initialize) { - if (initialize && Element.BackgroundColor.IsDefault) + if (initialize && Element.BackgroundColor.IsDefault()) return; // base.UpdateBackgroundColor() is not called on purpose, we don't want the regular background setting - if (Element.BackgroundColor.IsDefault || Element.BackgroundColor.A == 0) + if (Element.BackgroundColor.IsDefault() || Element.BackgroundColor.Alpha == 0) _page.Color = EColor.Transparent; else - _page.Color = Element.BackgroundColor.ToPlatform(); + _page.Color = Element.BackgroundColor.ToNative(); } protected override void UpdateLayout() diff --git a/src/Compatibility/Core/src/Tizen/Renderers/PickerRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/PickerRenderer.cs index 06668f7ef8..3f6fa06615 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/PickerRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/PickerRenderer.cs @@ -1,12 +1,16 @@ using System; using System.Collections.Generic; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch; +using Microsoft.Maui.Devices; using EEntry = ElmSharp.Entry; +using NIEntry = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.IEntry; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class PickerRenderer : ViewRenderer { List _list; @@ -31,7 +35,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { if (Control != null) { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.TextBlockFocused -= OnTextBlockFocused; ie.EntryLayoutFocused -= OnFocused; @@ -54,7 +58,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { var entry = CreateNativeControl(); entry.SetVerticalTextAlignment(0.5); - if (entry is IEntry ie) + if (entry is NIEntry ie) { ie.TextBlockFocused += OnTextBlockFocused; ie.EntryLayoutFocused += OnFocused; @@ -90,23 +94,23 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void UpdateTitleColor() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.PlaceholderColor = Element.TitleColor.ToPlatform(); + ie.PlaceholderColor = Element.TitleColor.ToPlatformEFL(); } } protected virtual void UpdateTextColor() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.TextColor = Element.TextColor.ToPlatform(); + ie.TextColor = Element.TextColor.ToPlatformEFL(); } } void UpdateFontSize() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontSize = Element.FontSize; } @@ -114,7 +118,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontFamily() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontFamily = Element.FontFamily; } @@ -122,7 +126,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontAttributes() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontAttributes = Element.FontAttributes; } @@ -130,7 +134,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateTitle() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.Placeholder = Element.Title; } @@ -138,15 +142,15 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateHorizontalTextAlignment() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToPlatform(); + ie.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToNative(); } } void OnLayoutFocused(object sender, EventArgs e) { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontSize = ie.FontSize * 1.5; } @@ -154,7 +158,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void OnLayoutUnfocused(object sender, EventArgs e) { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontSize = ie.FontSize / 1.5; } @@ -178,7 +182,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen _dialog.AlignmentX = -1; _dialog.AlignmentY = -1; _dialog.Title = Element.Title; - _dialog.TitleColor = Element.TitleColor.ToPlatform(); + _dialog.TitleColor = Element.TitleColor.ToPlatformEFL(); _dialog.Dismissed += OnDialogDismissed; _dialog.BackButtonPressed += (object senders, EventArgs es) => { @@ -197,7 +201,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen // You need to call Show() after ui thread occupation because of EFL problem. // Otherwise, the content of the popup will not receive focus. - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { _dialog.Show(); _list.Show(); diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ProgressBarRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ProgressBarRenderer.cs index a20e61e8c9..486b165926 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ProgressBarRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ProgressBarRenderer.cs @@ -1,11 +1,13 @@ using System.ComponentModel; +using Microsoft.Maui.Controls.Platform; using EColor = ElmSharp.Color; using EProgressBar = ElmSharp.ProgressBar; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.ProgressBar; -using SpecificVE = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.VisualElement; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.ProgressBar; +using SpecificVE = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.VisualElement; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ProgressBarRenderer : ViewRenderer { static readonly EColor s_defaultColor = ThemeConstants.ProgressBar.ColorClass.Default; @@ -70,10 +72,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void UpdateProgressColor(bool initialize) { - if (initialize && Element.ProgressColor.IsDefault) + if (initialize && Element.ProgressColor.IsDefault()) return; - Control.Color = Element.ProgressColor == Color.Default ? s_defaultColor : Element.ProgressColor.ToPlatform(); + Control.Color = Element.ProgressColor.IsDefault() ? s_defaultColor : Element.ProgressColor.ToPlatformEFL(); } void UpdateProgress() diff --git a/src/Compatibility/Core/src/Tizen/Renderers/RadioButtonRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/RadioButtonRenderer.cs index dab5c0fec1..4b26a7c684 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/RadioButtonRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/RadioButtonRenderer.cs @@ -1,10 +1,12 @@ using System; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using ESize = ElmSharp.Size; using TSpan = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Span; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class RadioButtonRenderer : ViewRenderer { readonly TSpan _span = new TSpan(); @@ -41,7 +43,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen base.Dispose(disposing); } - protected override Size MinimumSize() + protected override Graphics.Size MinimumSize() { return Measure(Control.MinimumWidth, Control.MinimumHeight).ToDP(); } @@ -78,7 +80,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateTextColor(bool isInitialized) { - _span.ForegroundColor = Element.TextColor.ToPlatform(); + _span.ForegroundColor = Element.TextColor.ToNative(); if (!isInitialized) ApplyTextAndStyle(); } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/RefreshViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/RefreshViewRenderer.cs index 7b609d5a06..dd28917aa1 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/RefreshViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/RefreshViewRenderer.cs @@ -1,13 +1,21 @@ using System; using System.Reflection; using System.Threading.Tasks; -using ElmSharp; +using Microsoft.Maui.Layouts; +using Microsoft.Maui.Graphics; +using Microsoft.Maui.Controls.Platform; +using Rect = Microsoft.Maui.Graphics.Rect; using ERect = ElmSharp.Rect; +using EvasObject = ElmSharp.EvasObject; +using GestureLayer = ElmSharp.GestureLayer; +using Scroller = ElmSharp.Scroller; using TWebView = Tizen.WebView.WebView; +using XStackLayout = Microsoft.Maui.Controls.StackLayout; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { - class RefreshIcon : ContentView + [Obsolete] + class RefreshIcon : AbsoluteLayout { public const int IconSize = ThemeConstants.RefreshView.Resources.IconSize; static readonly Color DefaultColor = ThemeConstants.RefreshView.ColorClass.DefaultColor; @@ -20,25 +28,19 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { HeightRequest = IconSize; WidthRequest = IconSize; - var layout = new AbsoluteLayout() - { - HeightRequest = IconSize, - WidthRequest = IconSize, - }; - layout.Children.Add(new BoxView + Children.Add(new BoxView { - Color = Color.White, + Color = Color.FromRgb(200, 200, 200), CornerRadius = new CornerRadius(IconSize), - }, new Rectangle(0.5, 0.5, IconSize, IconSize), AbsoluteLayoutFlags.PositionProportional); + }, new Rect(0.5, 0.5, IconSize, IconSize), AbsoluteLayoutFlags.PositionProportional); _icon = new Image { Source = ImageSource.FromResource(IconPath, typeof(ShellItemRenderer).Assembly), }; - layout.Children.Add(_icon, new Rectangle(0.5, 0.5, IconSize - 8, IconSize - 8), AbsoluteLayoutFlags.PositionProportional); - Content = layout; + Children.Add(_icon, new Rect(0.5, 0.5, IconSize - 8, IconSize - 8), AbsoluteLayoutFlags.PositionProportional); IconColor = DefaultColor; } @@ -51,7 +53,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } set { - PlatformConfiguration.TizenSpecific.Image.SetBlendColor(_icon, value == Color.Default ? DefaultColor : value); + PlatformConfiguration.TizenSpecific.Image.SetBlendColor(_icon, value == null ? DefaultColor : value); } } @@ -88,14 +90,15 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } } - class RefreshLayout : StackLayout + [Obsolete] + class RefreshLayout : XStackLayout { static readonly int MaximumDistance = 100; public RefreshLayout() { HeightRequest = 200; - HorizontalOptions = LayoutOptions.FillAndExpand; + HorizontalOptions = LayoutOptions.Fill; RefreshIcon = new RefreshIcon { @@ -105,6 +108,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Opacity = 0.5, }; Children.Add(RefreshIcon); + Children.Add(new BoxView + { + HeightRequest = 200 + }); } RefreshIcon RefreshIcon { get; set; } @@ -161,9 +168,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Loading, } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class RefreshViewRenderer : LayoutRenderer { - GestureLayer _gestureLayer; + ElmSharp.GestureLayer _gestureLayer; RefreshLayout _refreshLayout; IVisualElementRenderer _refreshLayoutRenderer; @@ -198,6 +206,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateRefreshLayout() { _refreshLayout = new RefreshLayout(); + _refreshLayout.Parent = Element; _refreshLayout.RefreshIconColor = RefreshView.RefreshColor; _refreshLayoutRenderer = Platform.GetOrCreateRenderer(_refreshLayout); (_refreshLayoutRenderer as ILayoutRenderer).RegisterOnLayoutUpdated(); @@ -274,7 +283,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen int GetScrollYOnGenList(IntPtr handle) { +#pragma warning disable IL2026 var interop = typeof(EvasObject).Assembly.GetType("Interop"); +#pragma warning disable IL2026 var elementary = interop?.GetNestedType("Elementary", BindingFlags.NonPublic | BindingFlags.Static) ?? null; if (elementary != null) diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ScrollViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ScrollViewRenderer.cs index 922d635b1c..b0ff4ff10b 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ScrollViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ScrollViewRenderer.cs @@ -1,15 +1,18 @@ using System; using System.ComponentModel; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; +using Microsoft.Maui.Devices; using EContainer = ElmSharp.Container; using ERect = ElmSharp.Rect; using NBox = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Box; using NScroller = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Scroller; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.ScrollView; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.ScrollView; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ScrollViewRenderer : ViewRenderer { EContainer _scrollCanvas; @@ -145,6 +148,13 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void OnContentLayoutUpdated(object sender, Native.LayoutEventArgs e) { + // It is workaround, + // in some case, before set a size of ScrollView, if content of content was filled with sized items, + // after size of ScrollView was updated, a content position was moved to somewhere. + if (Element.Content != null) + { + Platform.GetRenderer(Element.Content)?.NativeView?.Move(e.Geometry.X, e.Geometry.Y); + } UpdateContentSize(); } @@ -176,7 +186,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen _scrollCanvas.MinimumHeight = Forms.ConvertToScaledPixel(Element.ContentSize.Height + Element.Padding.VerticalThickness); // elm-scroller updates the CurrentRegion after render - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { if (Control != null) { @@ -198,12 +208,12 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen var y = e.ScrollY; if (e.Mode == ScrollToMode.Element) { - Point itemPosition = (Element as IScrollViewController).GetScrollPositionForElement(e.Element as VisualElement, e.Position); + Graphics.Point itemPosition = (Element as IScrollViewController).GetScrollPositionForElement(e.Element as VisualElement, e.Position); x = itemPosition.X; y = itemPosition.Y; } - ERect region = new Rectangle(x, y, Element.Width, Element.Height).ToPixel(); + ERect region = new Graphics.Rect(x, y, Element.Width, Element.Height).ToEFLPixel(); await Control.ScrollToAsync(region, e.ShouldAnimate); Element.SendScrollFinished(); } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/SearchBarRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/SearchBarRenderer.cs index 0959612dce..0416c05755 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/SearchBarRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/SearchBarRenderer.cs @@ -1,8 +1,10 @@ using System; +using Microsoft.Maui.Controls.Platform; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class SearchBarRenderer : ViewRenderer { @@ -64,7 +66,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen base.OnElementChanged(e); } - protected override Size MinimumSize() + protected override Graphics.Size MinimumSize() { return Control.Measure(Control.MinimumWidth, Control.MinimumHeight).ToDP(); } @@ -75,10 +77,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// void CancelButtonColorPropertyHandler(bool initialize) { - if (initialize && Element.CancelButtonColor.IsDefault) + if (initialize && Element.CancelButtonColor.IsDefault()) return; - Control.SetClearButtonColor(Element.CancelButtonColor.ToPlatform()); + Control.SetClearButtonColor(Element.CancelButtonColor.ToNative()); } /// @@ -97,7 +99,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// void FontFamilyPropertyHandler() { - Control.FontFamily = Element.FontFamily.ToNativeFontFamily(); + Control.FontFamily = Element.FontFamily.ToNativeFontFamily(Element.RequireFontManager()); } /// @@ -116,7 +118,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// void HorizontalTextAlignmentPropertyHandler() { - Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToPlatform(); + Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToNative(); } /// @@ -126,10 +128,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// void PlaceholderColorPropertyHandler(bool initialize) { - if (initialize && Element.TextColor.IsDefault) + if (initialize && Element.TextColor.IsDefault()) return; - Control.PlaceholderColor = Element.PlaceholderColor.ToPlatform(); + Control.PlaceholderColor = Element.PlaceholderColor.ToNative(); } /// @@ -168,10 +170,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// void TextColorPropertyHandler(bool initialize) { - if (initialize && Element.TextColor.IsDefault) + if (initialize && Element.TextColor.IsDefault()) return; - Control.TextColor = Element.TextColor.ToPlatform(); + Control.TextColor = Element.TextColor.ToNative(); } /// diff --git a/src/Compatibility/Core/src/Tizen/Renderers/SliderRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/SliderRenderer.cs index 290855dd0c..8536bc3138 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/SliderRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/SliderRenderer.cs @@ -1,11 +1,13 @@ using System; using System.ComponentModel; +using Microsoft.Maui.Controls.Platform; using EColor = ElmSharp.Color; using ESize = ElmSharp.Size; using ESlider = ElmSharp.Slider; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class SliderRenderer : ViewRenderer { EColor _defaultMinColor; @@ -117,18 +119,18 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void UpdateMinimumTrackColor() { - var color = Element.MinimumTrackColor.IsDefault ? _defaultMinColor : Element.MinimumTrackColor.ToPlatform(); + var color = Element.MinimumTrackColor.IsDefault() ? _defaultMinColor : Element.MinimumTrackColor.ToNative(); Control.SetBarColor(color); } protected virtual void UpdateMaximumTrackColor() { - Control.SetBackgroundColor(Element.MaximumTrackColor.IsDefault ? _defaultMaxColor : Element.MaximumTrackColor.ToPlatform()); + Control.SetBackgroundColor(Element.MaximumTrackColor.IsDefault() ? _defaultMaxColor : Element.MaximumTrackColor.ToNative()); } protected virtual void UpdateThumbColor() { - var color = Element.ThumbColor.IsDefault ? _defaultThumbColor : Element.ThumbColor.ToPlatform(); + var color = Element.ThumbColor.IsDefault() ? _defaultThumbColor : Element.ThumbColor.ToNative(); Control.SetHandlerColor(color); } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/StepperRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/StepperRenderer.cs index fcf565161d..5f0fed9929 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/StepperRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/StepperRenderer.cs @@ -1,9 +1,12 @@ using System; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch; +using Microsoft.Maui.Devices; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class StepperRenderer : ViewRenderer { diff --git a/src/Compatibility/Core/src/Tizen/Renderers/StructuredItemsViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/StructuredItemsViewRenderer.cs index 6a57d9f9b8..fd6e09193b 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/StructuredItemsViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/StructuredItemsViewRenderer.cs @@ -1,7 +1,9 @@ +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class StructuredItemsViewRenderer : ItemsViewRenderer { public StructuredItemsViewRenderer() diff --git a/src/Compatibility/Core/src/Tizen/Renderers/SwipeViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/SwipeViewRenderer.cs index 5ffa087724..b891670b07 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/SwipeViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/SwipeViewRenderer.cs @@ -1,8 +1,10 @@ using System; using System.Threading.Tasks; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Controls.Platform; using ERect = ElmSharp.Rect; +using XStackLayout = Microsoft.Maui.Controls.StackLayout; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -12,6 +14,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Closed } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class SwipeViewRenderer : LayoutRenderer { static readonly double SwipeItemWidth = Forms.ConvertToScaledDP(100); @@ -81,7 +84,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { if (SwipeDirection == 0) { - var direction = SwipeDirectionHelper.GetSwipeDirection(new Point(moment.X1, moment.Y1), new Point(moment.X2, moment.Y2)); + var direction = SwipeDirectionHelper.GetSwipeDirection(new Graphics.Point(moment.X1, moment.Y1), new Graphics.Point(moment.X2, moment.Y2)); if (HasRightItems && direction == SwipeDirection.Left) { @@ -243,7 +246,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateItems() { CurrentItems = GetSwipedItems(); - var itemsLayout = new StackLayout + var itemsLayout = new XStackLayout { Spacing = 0, Orientation = IsHorizontalSwipe ? StackOrientation.Horizontal : StackOrientation.Vertical, @@ -271,7 +274,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen tap.CommandParameter = item.CommandParameter; tap.Tapped += (s, e) => { - if (item is SwipeItem swipeItem) + if (item is ISwipeItem swipeItem) swipeItem.OnInvoked(); if (item is SwipeItemView customSwipeItem) @@ -279,7 +282,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (CurrentItems.SwipeBehaviorOnInvoked != SwipeBehaviorOnInvoked.RemainOpen) { - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { _ = SwipeCloseAsync(); }); @@ -290,12 +293,12 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (IsHorizontalSwipe) { itemView.HorizontalOptions = LayoutOptions.Start; - itemView.VerticalOptions = LayoutOptions.FillAndExpand; + itemView.VerticalOptions = LayoutOptions.Fill; } else { itemView.VerticalOptions = LayoutOptions.Start; - itemView.HorizontalOptions = LayoutOptions.FillAndExpand; + itemView.HorizontalOptions = LayoutOptions.Fill; } itemsLayout.Children.Add(itemView); } @@ -344,10 +347,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen static View CreateItemView(SwipeItemView item) { - return new StackLayout + return new XStackLayout { - VerticalOptions = LayoutOptions.FillAndExpand, - HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.Fill, + HorizontalOptions = LayoutOptions.Fill, Children = { item.Content @@ -365,34 +368,38 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { Text = item.Text, HorizontalTextAlignment = TextAlignment.Center, +#pragma warning disable CS0612 // Type or member is obsolete FontSize = Device.GetNamedSize(NamedSize.Default, typeof(Label)), +#pragma warning disable CS0612 // Type or member is obsolete }; if (horizontal) { - image.VerticalOptions = LayoutOptions.FillAndExpand; + image.VerticalOptions = LayoutOptions.Fill; image.HorizontalOptions = LayoutOptions.Start; - label.VerticalOptions = LayoutOptions.CenterAndExpand; - label.HorizontalOptions = LayoutOptions.CenterAndExpand; + label.VerticalOptions = LayoutOptions.Center; + label.HorizontalOptions = LayoutOptions.Center; label.VerticalTextAlignment = TextAlignment.Center; +#pragma warning disable CS0612 // Type or member is obsolete label.FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)); +#pragma warning disable CS0612 // Type or member is obsolete } else { - image.VerticalOptions = LayoutOptions.FillAndExpand; - image.HorizontalOptions = LayoutOptions.FillAndExpand; + image.VerticalOptions = LayoutOptions.Fill; + image.HorizontalOptions = LayoutOptions.Fill; - label.VerticalOptions = LayoutOptions.EndAndExpand; - label.HorizontalOptions = LayoutOptions.CenterAndExpand; + label.VerticalOptions = LayoutOptions.End; + label.HorizontalOptions = LayoutOptions.Center; label.VerticalTextAlignment = TextAlignment.End; } - var layout = new StackLayout + var layout = new XStackLayout { Padding = 5, BackgroundColor = item.BackgroundColor, - VerticalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.Fill, Orientation = horizontal ? StackOrientation.Horizontal : StackOrientation.Vertical, Children = { diff --git a/src/Compatibility/Core/src/Tizen/Renderers/SwitchRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/SwitchRenderer.cs index 1932c6d88d..38973d228e 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/SwitchRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/SwitchRenderer.cs @@ -1,12 +1,14 @@ using System; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific; +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific; using EColor = ElmSharp.Color; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.VisualElement; -using SpecificSwitch = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Switch; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.VisualElement; +using SpecificSwitch = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Switch; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class SwitchRenderer : ViewRenderer { public SwitchRenderer() @@ -61,7 +63,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Control.Style = SwitchStyle.Toggle; break; } - ((IVisualElementController)Element).NativeSizeChanged(); + ((IVisualElementController)Element).PlatformSizeChanged(); UpdateBackgroundColor(false); UpdateOnColor(false); UpdateColor(); @@ -70,24 +72,24 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void UpdateColor() { var color = SpecificSwitch.GetColor(Element); - if (color != Color.Default) + if (color != null) { - Control.Color = color.ToPlatform(); + Control.Color = color.ToPlatformEFL(); } } protected void UpdateOnColor(bool initialize) { - if (initialize && Element.OnColor.IsDefault) + if (initialize && Element.OnColor.IsDefault()) return; - if (Element.OnColor.IsDefault) + if (Element.OnColor.IsDefault()) { Control.DeleteOnColors(); } else { - Control.SetOnColors(Element.OnColor.ToPlatform()); + Control.SetOnColors(Element.OnColor.ToPlatformEFL()); } } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/TabbedPageRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/TabbedPageRenderer.cs index 1ad9198615..8e0711ecfd 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/TabbedPageRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/TabbedPageRenderer.cs @@ -3,20 +3,24 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Linq; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific; +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific; +using Microsoft.Maui.Devices; using EColor = ElmSharp.Color; using ERect = ElmSharp.Rect; +using EToolbar = ElmSharp.Toolbar; using EToolbarItem = ElmSharp.ToolbarItem; using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class TabbedPageRenderer : VisualElementRenderer { Box _outterLayout; Box _innerBox; Scroller _scroller; - Toolbar _toolbar; + EToolbar _toolbar; Dictionary _itemToItemPage = new Dictionary(); List _toolbarItemList = new List(); bool _isResettingToolbarItems = false; @@ -51,7 +55,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen _outterLayout.Show(); //Create toolbar that is placed inside the _outterLayout - _toolbar = new Toolbar(Forms.NativeParent) + _toolbar = new EToolbar(Forms.NativeParent) { AlignmentX = -1, WeightX = 1, @@ -155,7 +159,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (!string.IsNullOrEmpty(style)) { _toolbar.Style = style; - ((IVisualElementController)Element).NativeSizeChanged(); + ((IVisualElementController)Element).PlatformSizeChanged(); UpdateBackgroundColor(false); UpdateBarBackgroundColor(false); UpdateSelectedTabColor(false); @@ -210,10 +214,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateBarBackgroundColor(bool initialize) { - if (initialize && Element.BarBackgroundColor.IsDefault) + if (initialize && Element.BarBackgroundColor.IsDefault()) return; - EColor bgColor = Element.BarBackgroundColor.ToPlatform(); + EColor bgColor = Element.BarBackgroundColor.ToPlatformEFL(); _toolbar.BackgroundColor = bgColor; foreach (EToolbarItem item in _itemToItemPage.Keys) { @@ -223,34 +227,34 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateBarTextColor(bool initialize) { - if (initialize && Element.BarTextColor.IsDefault) + if (initialize && Element.BarTextColor.IsDefault()) return; foreach (EToolbarItem item in _itemToItemPage.Keys) { - ApplyBarItemColors(item, BarItemColorType.Text, Element.BarTextColor.ToPlatform()); + ApplyBarItemColors(item, BarItemColorType.Text, Element.BarTextColor.ToPlatformEFL()); } } void UpdateSelectedTabColor(bool initialize) { - if (initialize && Element.SelectedTabColor.IsDefault) + if (initialize && Element.SelectedTabColor.IsDefault()) return; foreach (EToolbarItem item in _itemToItemPage.Keys) { - ApplyBarItemColors(item, BarItemColorType.SelectedTab, Element.SelectedTabColor.ToPlatform()); + ApplyBarItemColors(item, BarItemColorType.SelectedTab, Element.SelectedTabColor.ToPlatformEFL()); } } void UpdateUnselectedTabColor(bool initialize) { - if (initialize && Element.UnselectedTabColor.IsDefault) + if (initialize && Element.UnselectedTabColor.IsDefault()) return; foreach (EToolbarItem item in _itemToItemPage.Keys) { - ApplyBarItemColors(item, BarItemColorType.UnselectedTab, Element.UnselectedTabColor.ToPlatform()); + ApplyBarItemColors(item, BarItemColorType.UnselectedTab, Element.UnselectedTabColor.ToPlatformEFL()); } } @@ -322,10 +326,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen _toolbarItemList.Insert(index, toolbarItem); _itemToItemPage.Add(toolbarItem, newItem); - ApplyBarItemColors(toolbarItem, BarItemColorType.Background, Element.BarBackgroundColor.ToPlatform()); - ApplyBarItemColors(toolbarItem, BarItemColorType.Text, Element.BarTextColor.ToPlatform()); - ApplyBarItemColors(toolbarItem, BarItemColorType.SelectedTab, Element.SelectedTabColor.ToPlatform()); - ApplyBarItemColors(toolbarItem, BarItemColorType.UnselectedTab, Element.UnselectedTabColor.ToPlatform()); + ApplyBarItemColors(toolbarItem, BarItemColorType.Background, Element.BarBackgroundColor.ToPlatformEFL()); + ApplyBarItemColors(toolbarItem, BarItemColorType.Text, Element.BarTextColor.ToPlatformEFL()); + ApplyBarItemColors(toolbarItem, BarItemColorType.SelectedTab, Element.SelectedTabColor.ToPlatformEFL()); + ApplyBarItemColors(toolbarItem, BarItemColorType.UnselectedTab, Element.UnselectedTabColor.ToPlatformEFL()); var childContent = Platform.GetOrCreateRenderer(newItem).NativeView; _innerBox.PackEnd(childContent); @@ -416,9 +420,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void OnCurrentPageChanged() { - // To update TabIndex order - CustomFocusManager.StartReorderTabIndex(); - if (_isUpdateByScroller || _isUpdateByToolbar || !_isInitialized) return; diff --git a/src/Compatibility/Core/src/Tizen/Renderers/TableViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/TableViewRenderer.cs index 6da95e76ff..b849441efd 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/TableViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/TableViewRenderer.cs @@ -1,9 +1,12 @@ using System; using ElmSharp; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; +using Microsoft.Maui.Devices; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class TableViewRenderer : ViewRenderer { internal static BindableProperty PresentationProperty = BindableProperty.Create("Presentation", typeof(View), typeof(TableSectionBase), null, BindingMode.OneWay, null, null, null, null, null as BindableProperty.CreateDefaultValueDelegate); diff --git a/src/Compatibility/Core/src/Tizen/Renderers/TimePickerRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/TimePickerRenderer.cs index e4d0b8c167..b9e91f3898 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/TimePickerRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/TimePickerRenderer.cs @@ -1,12 +1,17 @@ using System; using System.Globalization; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; +using Microsoft.Maui.Devices; +using Microsoft.Maui.Graphics; using EEntry = ElmSharp.Entry; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Application; +using NIEntry = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.IEntry; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Application; using WatchDateTimePickerDialog = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.Watch.WatchDateTimePickerDialog; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class TimePickerRenderer : ViewRenderer { //TODO need to add internationalization support @@ -47,7 +52,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen entry.SetVerticalTextAlignment(0.5); SetNativeControl(entry); - if (entry is IEntry ie) + if (entry is NIEntry ie) { ie.TextBlockFocused += OnTextBlockFocused; ie.EntryLayoutFocused += OnFocused; @@ -85,7 +90,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { if (Control != null) { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.TextBlockFocused -= OnTextBlockFocused; ie.EntryLayoutFocused -= OnFocused; @@ -128,7 +133,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen // You need to call Show() after ui thread occupation because of EFL problem. // Otherwise, the content of the popup will not receive focus. - Device.BeginInvokeOnMainThread(() => dialog.Show()); + Application.Current.Dispatcher.Dispatch(() => dialog.Show()); } } @@ -144,9 +149,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } protected virtual void UpdateTextColor() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { - ie.TextColor = Element.TextColor.ToPlatform(); + ie.TextColor = Element.TextColor.ToPlatformEFL(); } } @@ -158,7 +163,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontSize() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontSize = Element.FontSize; } @@ -166,7 +171,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontFamily() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontFamily = Element.FontFamily; } @@ -174,7 +179,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFontAttributes() { - if (Control is IEntry ie) + if (Control is NIEntry ie) { ie.FontAttributes = Element.FontAttributes; } diff --git a/src/Compatibility/Core/src/Tizen/Renderers/ViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/ViewRenderer.cs index 736b7fa4a8..23385e9449 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/ViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/ViewRenderer.cs @@ -5,10 +5,12 @@ using System.Diagnostics; using System.Linq; using ElmSharp; using ElmSharp.Wearable; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Application; +using Microsoft.Maui.Controls.Platform; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Application; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete("Use Microsoft.Maui.Controls.Handlers.Compatibility.ViewRenderer instead")] /// /// Base class for view renderers. /// diff --git a/src/Compatibility/Core/src/Tizen/Renderers/VisualElementRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/VisualElementRenderer.cs index 12eb446d6e..2ad6d99ff3 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/VisualElementRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/VisualElementRenderer.cs @@ -4,19 +4,25 @@ using System.ComponentModel; using System.Linq; using ElmSharp; using ElmSharp.Accessible; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Controls.Internals; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; +using Tizen.UIExtensions.ElmSharp; +using Size = Microsoft.Maui.Graphics.Size; +using Rect = Microsoft.Maui.Graphics.Rect; +using Point = Microsoft.Maui.Graphics.Point; using EFocusDirection = ElmSharp.FocusDirection; using ERect = ElmSharp.Rect; using ESize = ElmSharp.Size; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.VisualElement; -using XFocusDirection = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.FocusDirection; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.VisualElement; +using XFocusDirection = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.FocusDirection; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { /// /// Base class for rendering of a Xamarin element. /// + [Obsolete("Use Microsoft.Maui.Controls.Handlers.Compatibility.VisualElementRenderer instead")] public abstract class VisualElementRenderer : IVisualElementRenderer, IEffectControlProvider where TElement : VisualElement { readonly List> _elementChangedHandlers = new List>(); @@ -70,8 +76,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen RegisterPropertyHandler(VisualElement.RotationYProperty, UpdateTransformation); RegisterPropertyHandler(VisualElement.TranslationXProperty, UpdateTransformation); RegisterPropertyHandler(VisualElement.TranslationYProperty, UpdateTransformation); - RegisterPropertyHandler(VisualElement.TabIndexProperty, UpdateTabIndex); - RegisterPropertyHandler(VisualElement.IsTabStopProperty, UpdateIsTabStop); RegisterPropertyHandler(AutomationProperties.NameProperty, SetAccessibilityName); RegisterPropertyHandler(AutomationProperties.HelpTextProperty, SetAccessibilityDescription); @@ -89,7 +93,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Dispose(false); } - event EventHandler ElementChanged + event EventHandler IVisualElementRenderer.ElementChanged { add { @@ -120,6 +124,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public EvasObject NativeView { get; private set; } + public event EventHandler> ElementChanged; + protected bool IsDisposed => _flags.HasFlag(VisualElementRendererFlags.Disposed); /// @@ -295,7 +301,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } // Reset Element geometry, to re-calculate when Renderer was re-attached - Element.Layout(new Rectangle(0, 0, -1, -1)); + Element.Layout(new Rect(0, 0, -1, -1)); Element = default(TElement); } @@ -338,6 +344,12 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } } + var args = new VisualElementChangedEventArgs(e.OldElement, e.NewElement); + for (var i = 0; i < _elementChangedHandlers.Count; i++) + _elementChangedHandlers[i](this, args); + + ElementChanged?.Invoke(this, e); + if (null != e.NewElement) { e.NewElement.PropertyChanged += OnElementPropertyChanged; @@ -496,29 +508,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } } - protected Widget FocusSearch(bool forwardDirection) - { - VisualElement element = Element as VisualElement; - int maxAttempts = 0; - var tabIndexes = element?.GetTabIndexesOnParentPage(out maxAttempts); - if (tabIndexes == null) - return null; - - int tabIndex = Element.TabIndex; - int attempt = 0; - - do - { - element = element.FindNextElement(forwardDirection, tabIndexes, ref tabIndex) as VisualElement; - var renderer = Platform.GetRenderer(element); - if (renderer?.NativeView is Widget widget && widget.IsFocusAllowed) - { - return widget; - } - } while (!(element.IsFocused || ++attempt >= maxAttempts)); - return null; - } - internal virtual void SendVisualElementInitialized(VisualElement element, EvasObject nativeView) { element.SendViewInitialized(nativeView); @@ -526,7 +515,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateNativeGeometry() { - var updatedGeometry = new Rectangle(ComputeAbsolutePoint(Element), new Size(Element.Width, Element.Height)).ToPixel(); + var updatedGeometry = new Rect(ComputeAbsolutePoint(Element), new Size(Element.Width, Element.Height)).ToEFLPixel(); if (NativeView.Geometry != updatedGeometry) { @@ -644,12 +633,12 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void UpdateBackgroundColor(bool initialize) { - if (initialize && Element.BackgroundColor.IsDefault) + if (initialize && Element.BackgroundColor.IsDefault()) return; if (NativeView is Widget) { - (NativeView as Widget).BackgroundColor = Element.BackgroundColor.ToPlatform(); + (NativeView as Widget).BackgroundColor = Element.BackgroundColor.ToPlatformEFL(); } else { @@ -702,15 +691,23 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen static double ComputeAbsoluteX(VisualElement e) { var parentX = 0.0; - if (e.RealParent is VisualElement ve) + if (e.RealParent is VisualElement parent) { if (CompressedLayout.GetIsHeadless(e.RealParent)) { - parentX = ComputeAbsoluteX(ve); + parentX = ComputeAbsoluteX(parent); } else { - parentX = Forms.ConvertToScaledDP(Platform.GetRenderer(e.RealParent).GetNativeContentGeometry().X); + if (parent.Handler is IPlatformViewHandler nativeHandler) + { + + parentX = nativeHandler.GetPlatformContentGeometry().X.ToScaledDP(); + } + else + { + parentX = Forms.ConvertToScaledDP(Platform.GetRenderer(e.RealParent).GetNativeContentGeometry().X); + } } } return e.X + parentX; @@ -719,15 +716,22 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen static double ComputeAbsoluteY(VisualElement e) { var parentY = 0.0; - if (e.RealParent is VisualElement ve) + if (e.RealParent is VisualElement parent) { if (CompressedLayout.GetIsHeadless(e.RealParent)) { - parentY = ComputeAbsoluteY(ve); + parentY = ComputeAbsoluteY(parent); } else { - parentY = Forms.ConvertToScaledDP(Platform.GetRenderer(e.RealParent).GetNativeContentGeometry().Y); + if (parent.Handler is IPlatformViewHandler nativeHandler) + { + parentY = nativeHandler.GetPlatformContentGeometry().Y.ToScaledDP(); + } + else + { + parentY = Forms.ConvertToScaledDP(Platform.GetRenderer(e.RealParent).GetNativeContentGeometry().Y); + } } } return e.Y + parentY; @@ -787,7 +791,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void AddHeadlessChild(VisualElement element, IContainable parent) { - foreach (var child in element.LogicalChildren) + foreach (var child in (element as IVisualTreeElement).GetVisualChildren()) { if (child is VisualElement visualChild) { @@ -875,8 +879,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen /// The effect to register. void OnRegisterEffect(PlatformEffect effect) { - effect.SetContainer(Element.Parent == null ? null : Platform.GetRenderer(Element.Parent)?.NativeView); - effect.SetControl(NativeView); + effect.Container = Element.Parent == null ? null : Platform.GetRenderer(Element.Parent)?.NativeView; + effect.Control = NativeView; } void OnMoved(object sender, EventArgs e) @@ -1185,32 +1189,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } } - void UpdateTabIndex() - { - if (!Forms.Flags.Contains(Flags.DisableTabIndex)) - { - if (Element is View && NativeView is Widget widget && widget.IsFocusAllowed) - { - _customFocusManager.Value.TabIndex = Element.TabIndex; - } - } - } - - void UpdateIsTabStop(bool init) - { - if (init && Element.IsTabStop) - { - return; - } - if (!Forms.Flags.Contains(Flags.DisableTabIndex)) - { - if (Element is View && NativeView is Widget widget && widget.IsFocusAllowed) - { - _customFocusManager.Value.IsTabStop = Element.IsTabStop; - } - } - } - EFocusDirection ConvertToNativeFocusDirection(string direction) { if (direction == XFocusDirection.Back) diff --git a/src/Compatibility/Core/src/Tizen/Renderers/WebViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/WebViewRenderer.cs index c6d1750f2b..97dd1345c2 100644 --- a/src/Compatibility/Core/src/Tizen/Renderers/WebViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Renderers/WebViewRenderer.cs @@ -1,13 +1,15 @@ using System; using System.ComponentModel; using System.Threading.Tasks; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; using TChromium = Tizen.WebView.Chromium; using TWebView = Tizen.WebView.WebView; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class WebViewRenderer : ViewRenderer, IWebViewDelegate { bool _isUpdating; @@ -44,11 +46,11 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (Element != null) { - Element.EvalRequested -= OnEvalRequested; - Element.EvaluateJavaScriptRequested -= OnEvaluateJavaScriptRequested; - Element.GoBackRequested -= OnGoBackRequested; - Element.GoForwardRequested -= OnGoForwardRequested; - Element.ReloadRequested -= OnReloadRequested; + ((IWebViewController)Element).EvalRequested -= OnEvalRequested; + ((IWebViewController)Element).EvaluateJavaScriptRequested -= OnEvaluateJavaScriptRequested; + ((IWebViewController)Element).GoBackRequested -= OnGoBackRequested; + ((IWebViewController)Element).GoForwardRequested -= OnGoForwardRequested; + ((IWebViewController)Element).ReloadRequested -= OnReloadRequested; } } base.Dispose(disposing); @@ -68,19 +70,19 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (e.OldElement != null) { - e.OldElement.EvalRequested -= OnEvalRequested; - e.OldElement.GoBackRequested -= OnGoBackRequested; - e.OldElement.GoForwardRequested -= OnGoForwardRequested; - e.OldElement.ReloadRequested -= OnReloadRequested; + ((IWebViewController)e.OldElement).EvalRequested -= OnEvalRequested; + ((IWebViewController)e.OldElement).GoBackRequested -= OnGoBackRequested; + ((IWebViewController)e.OldElement).GoForwardRequested -= OnGoForwardRequested; + ((IWebViewController)e.OldElement).ReloadRequested -= OnReloadRequested; } if (e.NewElement != null) { - e.NewElement.EvalRequested += OnEvalRequested; - e.NewElement.EvaluateJavaScriptRequested += OnEvaluateJavaScriptRequested; - e.NewElement.GoForwardRequested += OnGoForwardRequested; - e.NewElement.GoBackRequested += OnGoBackRequested; - e.NewElement.ReloadRequested += OnReloadRequested; + ((IWebViewController)e.NewElement).EvalRequested += OnEvalRequested; + ((IWebViewController)e.NewElement).EvaluateJavaScriptRequested += OnEvaluateJavaScriptRequested; + ((IWebViewController)e.NewElement).GoForwardRequested += OnGoForwardRequested; + ((IWebViewController)e.NewElement).GoBackRequested += OnGoBackRequested; + ((IWebViewController)e.NewElement).ReloadRequested += OnReloadRequested; Load(); } base.OnElementChanged(e); @@ -107,7 +109,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (!string.IsNullOrEmpty(url)) { var args = new WebNavigatingEventArgs(_eventState, new UrlWebViewSource { Url = url }, url); - Element.SendNavigating(args); + ElementController.SendNavigating(args); if (args.Cancel) { @@ -180,15 +182,16 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void SendNavigated(UrlWebViewSource source, WebNavigationEvent evnt, WebNavigationResult result) { _isUpdating = true; - ((IElementController)Element).SetValueFromRenderer(WebView.SourceProperty, source); + ElementController.SetValueFromRenderer(WebView.SourceProperty, source); _isUpdating = false; - Element.SendNavigated(new WebNavigatedEventArgs(evnt, source, source.Url, result)); + ElementController.SendNavigated(new WebNavigatedEventArgs(evnt, source, source.Url, result)); UpdateCanGoBackForward(); _eventState = WebNavigationEvent.NewPage; } + [PortHandler] void UpdateCanGoBackForward() { ElementController.CanGoBack = NativeWebView.CanGoBack(); diff --git a/src/Compatibility/Core/src/Tizen/Resource/arrow_left.png b/src/Compatibility/Core/src/Tizen/Resource/arrow_left.png deleted file mode 100644 index 923dfeb34f..0000000000 Binary files a/src/Compatibility/Core/src/Tizen/Resource/arrow_left.png and /dev/null differ diff --git a/src/Compatibility/Core/src/Tizen/Resource/dots_horizontal.png b/src/Compatibility/Core/src/Tizen/Resource/dots_horizontal.png deleted file mode 100644 index 63d0f4be88..0000000000 Binary files a/src/Compatibility/Core/src/Tizen/Resource/dots_horizontal.png and /dev/null differ diff --git a/src/Compatibility/Core/src/Tizen/Resource/menu.png b/src/Compatibility/Core/src/Tizen/Resource/menu.png deleted file mode 100644 index 6dcfc0575a..0000000000 Binary files a/src/Compatibility/Core/src/Tizen/Resource/menu.png and /dev/null differ diff --git a/src/Compatibility/Core/src/Tizen/Resource/refresh_48dp.png b/src/Compatibility/Core/src/Tizen/Resource/refresh_48dp.png deleted file mode 100644 index 2f76cd47dd..0000000000 Binary files a/src/Compatibility/Core/src/Tizen/Resource/refresh_48dp.png and /dev/null differ diff --git a/src/Compatibility/Core/src/Tizen/Resource/wc_visual_cue.png b/src/Compatibility/Core/src/Tizen/Resource/wc_visual_cue.png deleted file mode 100644 index beddbb7ffc..0000000000 Binary files a/src/Compatibility/Core/src/Tizen/Resource/wc_visual_cue.png and /dev/null differ diff --git a/src/Compatibility/Core/src/Tizen/Shapes/EllipseRenderer.cs b/src/Compatibility/Core/src/Tizen/Shapes/EllipseRenderer.cs index 025fc204a4..4c045d06ba 100644 --- a/src/Compatibility/Core/src/Tizen/Shapes/EllipseRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shapes/EllipseRenderer.cs @@ -1,8 +1,10 @@ using SkiaSharp; -using Microsoft.Maui.Controls.Compatibility.Shapes; +using Microsoft.Maui.Controls.Shapes; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class EllipseRenderer : ShapeRenderer { protected override void OnElementChanged(ElementChangedEventArgs e) diff --git a/src/Compatibility/Core/src/Tizen/Shapes/LineRenderer.cs b/src/Compatibility/Core/src/Tizen/Shapes/LineRenderer.cs index c1bbd1f064..c7c4213610 100644 --- a/src/Compatibility/Core/src/Tizen/Shapes/LineRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shapes/LineRenderer.cs @@ -1,8 +1,10 @@ using SkiaSharp; -using Microsoft.Maui.Controls.Compatibility.Shapes; +using Microsoft.Maui.Controls.Shapes; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class LineRenderer : ShapeRenderer { public LineRenderer() : base() diff --git a/src/Compatibility/Core/src/Tizen/Shapes/PathRenderer.cs b/src/Compatibility/Core/src/Tizen/Shapes/PathRenderer.cs index 03b79a8f01..5655a460e5 100644 --- a/src/Compatibility/Core/src/Tizen/Shapes/PathRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shapes/PathRenderer.cs @@ -1,8 +1,10 @@ using SkiaSharp; -using Path = Microsoft.Maui.Controls.Compatibility.Shapes.Path; +using Microsoft.Maui.Controls.Platform; +using Path = Microsoft.Maui.Controls.Shapes.Path; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class PathRenderer : ShapeRenderer { public PathRenderer() : base() diff --git a/src/Compatibility/Core/src/Tizen/Shapes/PolygonRenderer.cs b/src/Compatibility/Core/src/Tizen/Shapes/PolygonRenderer.cs index 5eafb47b29..b9e140fdd4 100644 --- a/src/Compatibility/Core/src/Tizen/Shapes/PolygonRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shapes/PolygonRenderer.cs @@ -1,9 +1,11 @@ using System.Collections.Specialized; using SkiaSharp; -using Microsoft.Maui.Controls.Compatibility.Shapes; +using Microsoft.Maui.Controls.Shapes; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class PolygonRenderer : ShapeRenderer { public PolygonRenderer() : base() diff --git a/src/Compatibility/Core/src/Tizen/Shapes/PolylineRenderer.cs b/src/Compatibility/Core/src/Tizen/Shapes/PolylineRenderer.cs index a498f74c8f..46766f2302 100644 --- a/src/Compatibility/Core/src/Tizen/Shapes/PolylineRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shapes/PolylineRenderer.cs @@ -1,9 +1,11 @@ using System.ComponentModel; using SkiaSharp; -using Microsoft.Maui.Controls.Compatibility.Shapes; +using Microsoft.Maui.Controls.Shapes; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class PolylineRenderer : ShapeRenderer { public PolylineRenderer() : base() diff --git a/src/Compatibility/Core/src/Tizen/Shapes/RectangleRenderer.cs b/src/Compatibility/Core/src/Tizen/Shapes/RectangleRenderer.cs index a7492df9e7..5fc3973d87 100644 --- a/src/Compatibility/Core/src/Tizen/Shapes/RectangleRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shapes/RectangleRenderer.cs @@ -1,9 +1,11 @@ using SkiaSharp; -using FormsRectangle = Microsoft.Maui.Controls.Compatibility.Shapes.Rectangle; +using Microsoft.Maui.Controls.Platform; +using FormsRectangle = Microsoft.Maui.Controls.Shapes.Rectangle; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class RectangleRenderer : ShapeRenderer { public RectangleRenderer() : base() diff --git a/src/Compatibility/Core/src/Tizen/Shapes/ShapeRenderer.cs b/src/Compatibility/Core/src/Tizen/Shapes/ShapeRenderer.cs index f34c3cf56d..50f74f6ccf 100644 --- a/src/Compatibility/Core/src/Tizen/Shapes/ShapeRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shapes/ShapeRenderer.cs @@ -1,10 +1,11 @@ using System.Linq; using SkiaSharp; -using Microsoft.Maui.Controls.Compatibility.Shapes; -using Shape = Microsoft.Maui.Controls.Compatibility.Shapes.Shape; +using Microsoft.Maui.Controls.Shapes; +using Shape = Microsoft.Maui.Controls.Shapes.Shape; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShapeRenderer : ViewRenderer where TShape : Shape where TNativeShape : ShapeView diff --git a/src/Compatibility/Core/src/Tizen/Shell/IShellTabs.cs b/src/Compatibility/Core/src/Tizen/Shell/IShellTabs.cs index 7cd54531fd..a8f195df61 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/IShellTabs.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/IShellTabs.cs @@ -2,6 +2,7 @@ using System; using ElmSharp; using EColor = ElmSharp.Color; using EToolbarItem = ElmSharp.ToolbarItem; +using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -15,7 +16,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen EToolbarItem SelectedItem { get; } - event EventHandler Selected; + event EventHandler Selected; EToolbarItem Append(string label, string icon); EToolbarItem Append(string label); diff --git a/src/Compatibility/Core/src/Tizen/Shell/NavigationDrawer.cs b/src/Compatibility/Core/src/Tizen/Shell/NavigationDrawer.cs index 57d5ab5a69..5963f308c6 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/NavigationDrawer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/NavigationDrawer.cs @@ -7,6 +7,7 @@ using ERect = ElmSharp.Rect; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class NavigationDrawer : EBox, INavigationDrawer, IAnimatable { EvasObject _navigationView; diff --git a/src/Compatibility/Core/src/Tizen/Shell/NavigationView.cs b/src/Compatibility/Core/src/Tizen/Shell/NavigationView.cs index a0b4d129dc..8690c53616 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/NavigationView.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/NavigationView.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; using EColor = ElmSharp.Color; using EImage = ElmSharp.Image; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class NavigationView : Background, INavigationView { static EColor s_defaultBackgroundColor = EColor.White; @@ -311,7 +312,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { FontSize = this.GetFlyoutItemFontSize(), VerticalTextAlignment = TextAlignment.Center, - TextColor = Microsoft.Maui.Controls.Compatibility.Color.Black.MultiplyAlpha(0.87), + TextColor = Graphics.Color.FromRgb(0,0,0).MultiplyAlpha(0.87f), Margin = new Thickness(this.GetFlyoutMargin(), 0, 0, 0), }; label.SetBinding(Label.TextProperty, new Binding(textBinding)); @@ -333,7 +334,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen selectedState.Setters.Add(new Setter { Property = VisualElement.BackgroundColorProperty, - Value = new Color(0.95) + Value = new Graphics.Color(0.95f) }); commonGroup.States.Add(selectedState); @@ -467,7 +468,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } else { - Device.BeginInvokeOnMainThread(OnLayout); + Application.Current.Dispatcher.Dispatch(OnLayout); } } diff --git a/src/Compatibility/Core/src/Tizen/Shell/SearchHandlerRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/SearchHandlerRenderer.cs index 3465bc6ea1..a252fa2fbd 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/SearchHandlerRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/SearchHandlerRenderer.cs @@ -6,6 +6,7 @@ using NSearchBar = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.S namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class SearchHandlerRenderer : IDisposable { bool disposedValue; @@ -152,7 +153,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { var data = (e.Item.Data as View).BindingContext; SearchHandlerController.ItemSelected(data); - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { DeinitializeSearchResultList(); }); @@ -222,18 +223,18 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateBackgroundColor() { - var color = Element.BackgroundColor.ToPlatform(); + var color = Element.BackgroundColor.ToNative(); Control.BackgroundColor = color == EColor.Default ? EColor.White : color; } void UpdateTextColor() { - Control.TextColor = Element.TextColor.ToPlatform(); + Control.TextColor = Element.TextColor.ToNative(); } void UpdateHorizontalTextAlignment() { - Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToPlatform(); + Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToNative(); } void OnFocusChangedRequested(object sender, VisualElement.FocusRequestArgs e) @@ -244,7 +245,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateKeyboard() { - Control.Keyboard = Element.Keyboard.ToPlatform(); + Control.Keyboard = Element.Keyboard.ToNative(); } void UpdatePlaceholder() @@ -253,7 +254,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } void UpdatePlaceholderColor() { - Control.PlaceholderColor = Element.PlaceholderColor.ToPlatform(); + Control.PlaceholderColor = Element.PlaceholderColor.ToNative(); } void OnFocused(object sender, EventArgs e) @@ -269,14 +270,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { _searchResultList.Hide(); } - Device.BeginInvokeOnMainThread(() => - { - Device.StartTimer(TimeSpan.FromMilliseconds(100), () => - { - DeinitializeSearchResultList(); - return false; - }); - }); + Application.Current.Dispatcher.DispatchDelayed(TimeSpan.FromMilliseconds(100), () => DeinitializeSearchResultList()); } } diff --git a/src/Compatibility/Core/src/Tizen/Shell/SearchResultList.cs b/src/Compatibility/Core/src/Tizen/Shell/SearchResultList.cs index dfcc3d748a..8f7c70c60b 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/SearchResultList.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/SearchResultList.cs @@ -4,6 +4,7 @@ using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete] public class SearchResultList : GenList { GenItemClass _defaultClass = null; diff --git a/src/Compatibility/Core/src/Tizen/Shell/ShellItemRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/ShellItemRenderer.cs index fcca304173..95f38abd0e 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/ShellItemRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/ShellItemRenderer.cs @@ -9,9 +9,11 @@ using EBox = ElmSharp.Box; using EColor = ElmSharp.Color; using EImage = ElmSharp.Image; using EToolbarItem = ElmSharp.ToolbarItem; +using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShellItemRenderer : IAppearanceObserver, IDisposable { // The source of icon resources is https://materialdesignicons.com/ @@ -32,8 +34,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen List _tabsItems = new List(); bool _disposed = false; - EColor _tabBarBackgroudColor = ShellRenderer.DefaultBackgroundColor.ToPlatform(); - EColor _tabBarTitleColor = ShellRenderer.DefaultTitleColor.ToPlatform(); + EColor _tabBarBackgroudColor = ShellRenderer.DefaultBackgroundColor.ToNative(); + EColor _tabBarTitleColor = ShellRenderer.DefaultTitleColor.ToNative(); public ShellItemRenderer(ShellItem item) { @@ -282,10 +284,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance) { - var tabBarBackgroudColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarBackgroundColor ?? Color.Default; - var tabBarTitleColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarTitleColor ?? Color.Default; - TabBarBackgroundColor = tabBarBackgroudColor.IsDefault ? ShellRenderer.DefaultBackgroundColor.ToPlatform() : tabBarBackgroudColor.ToPlatform(); - TabBarTitleColor = tabBarTitleColor.IsDefault ? ShellRenderer.DefaultTitleColor.ToPlatform() : tabBarTitleColor.ToPlatform(); + var tabBarBackgroudColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarBackgroundColor; + var tabBarTitleColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarTitleColor; + TabBarBackgroundColor = tabBarBackgroudColor.IsDefault() ? ShellRenderer.DefaultBackgroundColor.ToNative() : tabBarBackgroudColor.ToNative(); + TabBarTitleColor = tabBarTitleColor.IsDefault() ? ShellRenderer.DefaultTitleColor.ToNative() : tabBarTitleColor.ToNative(); } void UpdateTabsBackgroudColor(EColor color) @@ -388,7 +390,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen _contentHolder.PackEnd(_currentStack); } - void OnTabsSelected(object sender, ToolbarItemEventArgs e) + void OnTabsSelected(object sender, EToolbarItemEventArgs e) { if (_tabs.SelectedItem == null) return; diff --git a/src/Compatibility/Core/src/Tizen/Shell/ShellMoreToolbar.cs b/src/Compatibility/Core/src/Tizen/Shell/ShellMoreToolbar.cs index 47b15be3cd..edee7e2b55 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/ShellMoreToolbar.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/ShellMoreToolbar.cs @@ -5,6 +5,7 @@ using EImage = ElmSharp.Image; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class ShellMoreToolbar : GenList { GenItemClass _defaultClass = null; @@ -15,7 +16,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen SetWeight(1, 1); Homogeneous = true; SelectionMode = GenItemSelectionMode.Always; - BackgroundColor = ShellRenderer.DefaultBackgroundColor.ToPlatform(); + BackgroundColor = ShellRenderer.DefaultBackgroundColor.ToNative(); _defaultClass = new GenItemClass(ThemeConstants.GenItemClass.Styles.Full) { GetContentHandler = GetContent, diff --git a/src/Compatibility/Core/src/Tizen/Shell/ShellNavBar.cs b/src/Compatibility/Core/src/Tizen/Shell/ShellNavBar.cs index 30f1546ae9..3cceea6169 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/ShellNavBar.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/ShellNavBar.cs @@ -1,5 +1,6 @@ using System; using System.Reflection; +using Microsoft.Maui.Devices; using ElmSharp; using EBox = ElmSharp.Box; using EButton = ElmSharp.Button; @@ -8,6 +9,7 @@ using EImage = ElmSharp.Image; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class ShellNavBar : EBox, IFlyoutBehaviorObserver, IDisposable { EImage _menuIcon = null; @@ -22,9 +24,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen FlyoutBehavior _flyoutBehavior = FlyoutBehavior.Flyout; - EColor _backgroudColor = ShellRenderer.DefaultBackgroundColor.ToPlatform(); - EColor _foregroudColor = ShellRenderer.DefaultForegroundColor.ToPlatform(); - EColor _titleColor = ShellRenderer.DefaultTitleColor.ToPlatform(); + EColor _backgroudColor = ShellRenderer.DefaultBackgroundColor.ToNative(); + EColor _foregroudColor = ShellRenderer.DefaultForegroundColor.ToNative(); + EColor _titleColor = ShellRenderer.DefaultTitleColor.ToNative(); // The source of icon resources is https://materialdesignicons.com/ const string _menuIconRes = ThemeConstants.Shell.Resources.MenuIcon; diff --git a/src/Compatibility/Core/src/Tizen/Shell/ShellRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/ShellRenderer.cs index 729bb4356b..3237ad9464 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/ShellRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/ShellRenderer.cs @@ -1,7 +1,10 @@ using System; +using Microsoft.Maui.Graphics; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShellRenderer : VisualElementRenderer, IFlyoutController { INavigationDrawer _drawer; @@ -119,7 +122,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void UpdateFlyoutBackgroundColor() { - _navigationView.BackgroundColor = Element.FlyoutBackgroundColor.ToPlatform(); + _navigationView.BackgroundColor = Element.FlyoutBackgroundColor.ToPlatformEFL(); } void UpdateFlyoutBackgroundImageAspect() @@ -135,7 +138,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen protected virtual void UpdateFlyoutIsPresented() { // It is workaround of Panel.IsOpen bug, Panel.IsOpen property is not working when layouting was triggered - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { _drawer.IsOpen = Element.FlyoutIsPresented; }); diff --git a/src/Compatibility/Core/src/Tizen/Shell/ShellSectionRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/ShellSectionRenderer.cs index b04a0877ab..3cc160c230 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/ShellSectionRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/ShellSectionRenderer.cs @@ -6,6 +6,7 @@ using ElmSharp; using EBox = ElmSharp.Box; using EColor = ElmSharp.Color; using EToolbarItem = ElmSharp.ToolbarItem; +using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -14,6 +15,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen EvasObject NativeView { get; } } + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShellSectionRenderer : IAppearanceObserver, IShellSectionRenderer { EBox _mainLayout = null; @@ -27,8 +29,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Dictionary _itemToContent = new Dictionary(); List _tabsItems = new List(); - EColor _backgroundColor = ShellRenderer.DefaultBackgroundColor.ToPlatform(); - EColor _foregroundColor = ShellRenderer.DefaultForegroundColor.ToPlatform(); + EColor _backgroundColor = ShellRenderer.DefaultBackgroundColor.ToNative(); + EColor _foregroundColor = ShellRenderer.DefaultForegroundColor.ToNative(); bool _disposed = false; @@ -127,10 +129,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance) { - var backgroundColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarBackgroundColor ?? Color.Default; - var foregroundColor = appearance?.ForegroundColor ?? Color.Default; - ToolbarBackgroundColor = backgroundColor.IsDefault ? ShellRenderer.DefaultBackgroundColor.ToPlatform() : backgroundColor.ToPlatform(); - ToolbarForegroundColor = foregroundColor.IsDefault ? ShellRenderer.DefaultForegroundColor.ToPlatform() : foregroundColor.ToPlatform(); + var backgroundColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarBackgroundColor; + var foregroundColor = appearance?.ForegroundColor; + ToolbarBackgroundColor = backgroundColor.IsDefault() ? ShellRenderer.DefaultBackgroundColor.ToNative() : backgroundColor.ToNative(); + ToolbarForegroundColor = foregroundColor.IsDefault() ? ShellRenderer.DefaultForegroundColor.ToNative() : foregroundColor.ToNative(); } void UpdateDisplayedPage(Page page) @@ -296,7 +298,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen UpdateTabsItem(); } - void OnTabsSelected(object sender, ToolbarItemEventArgs e) + void OnTabsSelected(object sender, EToolbarItemEventArgs e) { if (_tabs.SelectedItem == null) { diff --git a/src/Compatibility/Core/src/Tizen/Shell/ShellSectionStack.cs b/src/Compatibility/Core/src/Tizen/Shell/ShellSectionStack.cs index bce506b0da..ecd126a3ec 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/ShellSectionStack.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/ShellSectionStack.cs @@ -1,11 +1,13 @@ using System; using System.ComponentModel; using System.Threading.Tasks; +using Microsoft.Maui.Devices; using ElmSharp; using EBox = ElmSharp.Box; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class ShellSectionStack : EBox, IAppearanceObserver, IDisposable { ShellNavBar _navBar = null; @@ -110,7 +112,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen _shellSectionRenderer.NativeView.Show(); _viewStack.Push(_shellSectionRenderer.NativeView); - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { (_shellSectionRenderer.NativeView as Widget)?.SetFocus(true); }); @@ -137,13 +139,13 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen if (_navBar == null) return; - var titleColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarTitleColor ?? Microsoft.Maui.Controls.Compatibility.Color.Default; - var backgroundColor = appearance?.BackgroundColor ?? Microsoft.Maui.Controls.Compatibility.Color.Default; - var foregroundColor = appearance?.ForegroundColor ?? Microsoft.Maui.Controls.Compatibility.Color.Default; + var titleColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarTitleColor; + var backgroundColor = appearance?.BackgroundColor; + var foregroundColor = appearance?.ForegroundColor; - _navBar.TitleColor = titleColor.IsDefault ? ShellRenderer.DefaultTitleColor.ToPlatform() : titleColor.ToPlatform(); - _navBar.BackgroundColor = backgroundColor.IsDefault ? ShellRenderer.DefaultBackgroundColor.ToPlatform() : backgroundColor.ToPlatform(); - _navBar.ForegroundColor = foregroundColor.IsDefault ? ShellRenderer.DefaultForegroundColor.ToPlatform() : foregroundColor.ToPlatform(); + _navBar.TitleColor = titleColor.IsDefault() ? ShellRenderer.DefaultTitleColor.ToPlatformEFL() : titleColor.ToPlatformEFL(); + _navBar.BackgroundColor = backgroundColor.IsDefault() ? ShellRenderer.DefaultBackgroundColor.ToPlatformEFL() : backgroundColor.ToPlatformEFL(); + _navBar.ForegroundColor = foregroundColor.IsDefault() ? ShellRenderer.DefaultForegroundColor.ToPlatformEFL() : foregroundColor.ToPlatformEFL(); } @@ -221,7 +223,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen var renderer = Platform.GetOrCreateRenderer(request.Page); _viewStack.Push(renderer.NativeView); request.Task = Task.FromResult(true); - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { (renderer.NativeView as Widget)?.SetFocus(true); }); diff --git a/src/Compatibility/Core/src/Tizen/Shell/ShellTabs.cs b/src/Compatibility/Core/src/Tizen/Shell/ShellTabs.cs index a1230ca5e8..7626804c9b 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/ShellTabs.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/ShellTabs.cs @@ -1,8 +1,9 @@ using ElmSharp; +using EToolbar = ElmSharp.Toolbar; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { - public class ShellTabs : Toolbar, IShellTabs + public class ShellTabs : EToolbar, IShellTabs { ShellTabsType _type; diff --git a/src/Compatibility/Core/src/Tizen/Shell/SimpleViewStack.cs b/src/Compatibility/Core/src/Tizen/Shell/SimpleViewStack.cs index c7f2a1c779..1245231cb1 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/SimpleViewStack.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/SimpleViewStack.cs @@ -36,7 +36,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen UpdateTopView(); // if Pop was called by removed page, // Unrealize cause deletation of NativeCallback, it could be a cause of crash - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { tobeRemoved.Unrealize(); }); @@ -65,7 +65,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen InternalStack.Remove(view); UnPack(view); UpdateTopView(); - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { view?.Unrealize(); }); diff --git a/src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateAdaptor.cs b/src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateAdaptor.cs index e36306c54c..a6f7cc5c14 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateAdaptor.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateAdaptor.cs @@ -1,8 +1,9 @@ using System.Collections; -using Xamarin.Forms.Platform.Tizen.Native; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.TV { + [System.Obsolete] public class FlyoutItemTemplateAdaptor : ItemTemplateAdaptor { public FlyoutItemTemplateAdaptor(Element itemsView, IEnumerable items, DataTemplate template, bool hasHeader) diff --git a/src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateSelector.cs b/src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateSelector.cs index 76e2b2a587..ede79b5c20 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateSelector.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/TV/FlyoutItemTemplateSelector.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using Microsoft.Maui.Graphics; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.TV { @@ -138,25 +139,25 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.TV { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (value is Color c && c == Color.Transparent) + if (value is Color c && c == KnownColor.Transparent) { - return Color.White; + return Color.FromRgb(255, 255, 255); } else { - return Color.Black; + return Color.FromRgb(0, 0, 0); } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - if (value is Color c && c == Color.White) + if (value is Color c && c.Equals(Color.FromRgb(255, 255, 255))) { - return Color.Transparent; + return KnownColor.Transparent; } else { - return Color.Black; + return Color.FromRgb(0, 0, 0); } } } diff --git a/src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationDrawer.cs b/src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationDrawer.cs index 1231c11dda..68bc76c832 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationDrawer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationDrawer.cs @@ -6,6 +6,7 @@ using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.TV { + [Obsolete] public class TVNavigationDrawer : EBox, INavigationDrawer, IAnimatable, IFlyoutBehaviorObserver { EBox _drawerBox; diff --git a/src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationView.cs b/src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationView.cs index c16335246a..80cdd7bd07 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationView.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/TV/TVNavigationView.cs @@ -10,6 +10,7 @@ using NCollectionView = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Nat namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class TVNavigationView : Background, INavigationView { static EColor s_defaultBackgroundColor = EColor.Black; @@ -349,7 +350,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen void OnHeaderSizeChanged(object sender, EventArgs e) { - Device.BeginInvokeOnMainThread(OnLayout); + Application.Current.Dispatcher.Dispatch(OnLayout); } void OnLayout() diff --git a/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellItemRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellItemRenderer.cs index 613f5295f1..2ab47af829 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellItemRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellItemRenderer.cs @@ -2,6 +2,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.TV { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class TVShellItemRenderer : ShellItemRenderer { public TVShellItemRenderer(ShellItem item) : base(item) diff --git a/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellRenderer.cs index 0225a2a71e..a94c5343d5 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellRenderer.cs @@ -2,6 +2,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.TV { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class TVShellRenderer : ShellRenderer { protected override INavigationDrawer CreateNavigationDrawer() diff --git a/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionRenderer.cs index e1d544d38f..ff1838fa4b 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionRenderer.cs @@ -7,6 +7,7 @@ using EBox = ElmSharp.Box; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class TVShellSectionRenderer : IShellSectionRenderer, IDisposable { EBox _mainLayout = null; diff --git a/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionStack.cs b/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionStack.cs index 7ba2652b73..784244db91 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionStack.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/TV/TVShellSectionStack.cs @@ -2,6 +2,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.TV { + [System.Obsolete] public class TVShellSectionStack : ShellSectionStack { diff --git a/src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationDrawer.cs b/src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationDrawer.cs index 7ffb5f322a..8e0ee78412 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationDrawer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationDrawer.cs @@ -12,6 +12,7 @@ using EWidget = ElmSharp.Widget; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch { + [Obsolete] public class NavigationDrawer : ELayout, IAnimatable { static readonly int TouchWidth = ThemeConstants.Shell.Resources.Watch.DefaultDrawerTouchWidth; diff --git a/src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationView.cs b/src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationView.cs index 4928ec11de..efba6fe375 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationView.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/Watch/NavigationView.cs @@ -10,6 +10,7 @@ using ELayout = ElmSharp.Layout; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch { + [Obsolete] public class NavigationView : ELayout { readonly int _defaultIconSize = ThemeConstants.Shell.Resources.Watch.DefaultNavigationViewIconSize; diff --git a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellContentRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellContentRenderer.cs index 07b8ae5c43..a6ccb674aa 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellContentRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellContentRenderer.cs @@ -2,6 +2,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShellContentRenderer : IShellItemRenderer { public ShellContentRenderer(ShellContent content) diff --git a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellItemRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellItemRenderer.cs index 9de2756b3d..11db455ffb 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellItemRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellItemRenderer.cs @@ -4,6 +4,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShellItemRenderer : IShellItemRenderer { Box _mainLayout; diff --git a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRenderer.cs index f855615a69..b54cba9647 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRenderer.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using ElmSharp; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShellRenderer : VisualElementRenderer { NavigationDrawer _drawer; @@ -185,12 +187,12 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch void UpdateFlyoutBackgroundColor(bool init) { - if (init && Element.FlyoutBackgroundColor.IsDefault) + if (init && Element.FlyoutBackgroundColor.IsDefault()) return; if (_navigationView != null) { - _navigationView.BackgroundColor = Element.FlyoutBackgroundColor.ToPlatform(); + _navigationView.BackgroundColor = Element.FlyoutBackgroundColor.ToNative(); } } diff --git a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRendererFactory.cs b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRendererFactory.cs index 44bd11e5b2..820c90d03c 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRendererFactory.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellRendererFactory.cs @@ -1,5 +1,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch { + [System.Obsolete] public class ShellRendererFactory { static ShellRendererFactory _instance; diff --git a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionItemsRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionItemsRenderer.cs index cbccbfecd4..21d3fb523c 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionItemsRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionItemsRenderer.cs @@ -5,9 +5,11 @@ using System.ComponentModel; using ElmSharp; using ElmSharp.Wearable; using ERect = ElmSharp.Rect; +using Index = ElmSharp.Index; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShellSectionItemsRenderer : IShellItemRenderer { const int ItemMaxCount = 20; diff --git a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionNavigationRenderer.cs b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionNavigationRenderer.cs index c0e5341fbc..6cd67841ac 100644 --- a/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionNavigationRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/Shell/Watch/ShellSectionNavigationRenderer.cs @@ -1,12 +1,11 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; +using Microsoft.Maui.Controls.Internals; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ShellSectionNavigationRenderer : IShellItemRenderer { SimpleViewStack _viewStack; @@ -48,7 +47,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch _rootPageRenderer = ShellRendererFactory.Default.CreateItemRenderer(ShellSection); _viewStack.Push(_rootPageRenderer.NativeView); - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { (_rootPageRenderer.NativeView as Widget)?.SetFocus(true); }); @@ -72,7 +71,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Watch var renderer = Platform.GetOrCreateRenderer(request.Page); _viewStack.Push(renderer.NativeView); request.Task = Task.FromResult(true); - Device.BeginInvokeOnMainThread(() => + Application.Current.Dispatcher.Dispatch(() => { (renderer.NativeView as Widget)?.SetFocus(true); }); diff --git a/src/Compatibility/Core/src/Tizen/SkiaSharp/BoxViewRenderer.cs b/src/Compatibility/Core/src/Tizen/SkiaSharp/BoxViewRenderer.cs index f9d79b9f4f..afcc8f2167 100644 --- a/src/Compatibility/Core/src/Tizen/SkiaSharp/BoxViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/SkiaSharp/BoxViewRenderer.cs @@ -1,8 +1,10 @@ +using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; using EColor = ElmSharp.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class BoxViewRenderer : CanvasViewRenderer { public BoxViewRenderer() @@ -23,10 +25,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp protected override void UpdateBackgroundColor(bool initialize) { - if (initialize && Element.BackgroundColor.IsDefault) + if (initialize && Element.BackgroundColor.IsDefault()) return; - if (Element.Color.IsDefault) + if (Element.Color.IsDefault()) { UpdateColor(); } @@ -62,9 +64,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp void UpdateColor() { - if (Element.Color.IsDefault) + if (Element.Color.IsDefault()) { - if (Element.BackgroundColor.IsDefault) + if (Element.BackgroundColor.IsDefault()) { // Set to default color. (Transparent) RealControl.Color = EColor.Transparent; @@ -72,13 +74,13 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp else { // Use BackgroundColor only if color is default and background color is not default. - RealControl.Color = Element.BackgroundColor.MultiplyAlpha(Element.Opacity).ToPlatform(); + RealControl.Color = Element.BackgroundColor.MultiplyAlpha((float)Element.Opacity).ToNative(); } } else { // Color has higer priority than BackgroundColor. - RealControl.Color = Element.Color.MultiplyAlpha(Element.Opacity).ToPlatform(); + RealControl.Color = Element.Color.MultiplyAlpha((float)Element.Opacity).ToNative(); } } } diff --git a/src/Compatibility/Core/src/Tizen/SkiaSharp/CanvasViewRenderer.cs b/src/Compatibility/Core/src/Tizen/SkiaSharp/CanvasViewRenderer.cs index 91e1c2137c..ff079661bd 100644 --- a/src/Compatibility/Core/src/Tizen/SkiaSharp/CanvasViewRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/SkiaSharp/CanvasViewRenderer.cs @@ -3,10 +3,12 @@ using System.Diagnostics; using ElmSharp; using SkiaSharp; using SkiaSharp.Views.Tizen; -using Microsoft.Maui.Controls.Compatibility.Shapes; +using Microsoft.Maui.Controls.Shapes; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public abstract class CanvasViewRenderer : ViewRenderer, IBackgroundCanvas, IClipperCanvas, ICanvasRenderer where TView : View where TNativeView : EvasObject diff --git a/src/Compatibility/Core/src/Tizen/SkiaSharp/FrameRenderer.cs b/src/Compatibility/Core/src/Tizen/SkiaSharp/FrameRenderer.cs index aa4a03b659..1f13ba5a90 100644 --- a/src/Compatibility/Core/src/Tizen/SkiaSharp/FrameRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/SkiaSharp/FrameRenderer.cs @@ -1,8 +1,10 @@ using SkiaSharp; using SkiaSharp.Views.Tizen; +using Microsoft.Maui.Controls.Platform; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class FrameRenderer : LayoutRenderer { static float s_borderWidth = 1.0f; @@ -32,7 +34,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp protected override void UpdateBackgroundColor(bool initialize) { - if (initialize && Element.BackgroundColor.IsDefault) + if (initialize && Element.BackgroundColor.IsDefault()) return; else BackgroundCanvas.Invalidate(); @@ -50,8 +52,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp var canvas = e.Surface.Canvas; var bound = e.Info.Rect; canvas.Clear(); - var bgColor = Element.BackgroundColor == Color.Default ? s_defaultColor : SKColor.Parse(Element.BackgroundColor.ToHex()); - var borderColor = Element.BorderColor == Color.Default ? s_defaultColor : SKColor.Parse(Element.BorderColor.ToHex()); + var bgColor = Element.BackgroundColor.IsDefault() ? s_defaultColor : SKColor.Parse(Element.BackgroundColor.ToHex()); + var borderColor = Element.BorderColor.IsDefault() ? s_defaultColor : SKColor.Parse(Element.BorderColor.ToHex()); var roundRect = CreateRoundRect(bound); using (var paint = new SKPaint diff --git a/src/Compatibility/Core/src/Tizen/SkiaSharp/ImageRenderer.cs b/src/Compatibility/Core/src/Tizen/SkiaSharp/ImageRenderer.cs index 088f4335c9..b38057ea0f 100644 --- a/src/Compatibility/Core/src/Tizen/SkiaSharp/ImageRenderer.cs +++ b/src/Compatibility/Core/src/Tizen/SkiaSharp/ImageRenderer.cs @@ -1,8 +1,10 @@ +using Microsoft.Maui.Controls.Platform; using ESize = ElmSharp.Size; -using Specific = Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific.Image; +using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.Image; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { + [System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)] public class ImageRenderer : CanvasViewRenderer { public ImageRenderer() @@ -42,7 +44,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp bool success = await RealControl.LoadFromImageSourceAsync(source); if (!IsDisposed && success) { - ((IVisualElementController)Element).NativeSizeChanged(); + ((IVisualElementController)Element).PlatformSizeChanged(); UpdateAfterLoading(initialize); } } @@ -61,7 +63,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp bool success = RealControl.LoadFromFile(Specific.GetFile(Element)); if (!IsDisposed && success) { - ((IVisualElementController)Element).NativeSizeChanged(); + ((IVisualElementController)Element).PlatformSizeChanged(); UpdateAfterLoading(initialize); } } @@ -101,10 +103,10 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp void UpdateBlendColor(bool initialize) { - if (initialize && Specific.GetBlendColor(Element).IsDefault) + if (initialize && Specific.GetBlendColor(Element) == null) return; - RealControl.Color = Specific.GetBlendColor(Element).ToPlatform(); + RealControl.Color = Specific.GetBlendColor(Element).ToPlatformEFL(); } } } diff --git a/src/Compatibility/Core/src/Tizen/SkiaSharp/SKClipperView.cs b/src/Compatibility/Core/src/Tizen/SkiaSharp/SKClipperView.cs index 40d64d0d93..f664466e45 100644 --- a/src/Compatibility/Core/src/Tizen/SkiaSharp/SKClipperView.cs +++ b/src/Compatibility/Core/src/Tizen/SkiaSharp/SKClipperView.cs @@ -25,7 +25,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen.SkiaSharp { if (target != null && clipper.ClippingRequired) { +#pragma warning disable CS0612 // Type or member is obsolete var nativeView = Platform.GetOrCreateRenderer(target)?.NativeView; +#pragma warning disable CS0612 // Type or member is obsolete var realHandle = elm_object_part_content_get(clipper, "elm.swallow.content"); nativeView?.SetClip(null); // To restore original image diff --git a/src/Compatibility/Core/src/Tizen/StaticRegistrar.cs b/src/Compatibility/Core/src/Tizen/StaticRegistrar.cs index e3874f195d..53480c9687 100644 --- a/src/Compatibility/Core/src/Tizen/StaticRegistrar.cs +++ b/src/Compatibility/Core/src/Tizen/StaticRegistrar.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; using System.Reflection; -using Microsoft.Maui.Controls.Compatibility.Internals; -using Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native; -using Microsoft.Maui.Controls.Compatibility.PlatformConfiguration.TizenSpecific; -using Microsoft.Maui.Controls.Compatibility.Shapes; -using Microsoft.Maui.Controls.Compatibility.Xaml.Internals; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Controls.Shapes; +using Microsoft.Maui.Controls.Xaml.Internals; +using Microsoft.Maui.Devices; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class StaticRegistrar where TRegistrable : class { readonly Dictionary> _handlers = new Dictionary>(); @@ -58,6 +58,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen } } + [Obsolete] public static class StaticRegistrar { public static StaticRegistrar Registered { get; internal set; } @@ -82,9 +83,6 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Registered.Register(typeof(CarouselPage), () => new CarouselPageRenderer()); Registered.Register(typeof(Page), () => new PageRenderer()); Registered.Register(typeof(NavigationPage), () => new NavigationPageRenderer()); -#pragma warning disable CS0618 // Type or member is obsolete - Registered.Register(typeof(MasterDetailPage), () => new MasterDetailPageRenderer()); -#pragma warning restore CS0618 // Type or member is obsolete Registered.Register(typeof(FlyoutPage), () => new FlyoutPageRenderer()); Registered.Register(typeof(TabbedPage), () => new TabbedPageRenderer()); Registered.Register(typeof(Label), () => new LabelRenderer()); @@ -142,11 +140,12 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen Registered.Register(typeof(ViewCell), () => new ViewCellRenderer()); //Font Loaders - Registered.Register(typeof(EmbeddedFont), () => new EmbeddedFontLoader()); + Registered.Register(typeof(EmbeddedFont), () => new CompatibilityEmbeddedFontLoader()); //Dependencies +#pragma warning disable CS0612 // Type or member is obsolete DependencyService.Register(); - DependencyService.Register(); +#pragma warning disable CS0612 // Type or member is obsolete DependencyService.Register(); DependencyService.Register(); diff --git a/src/Compatibility/Core/src/Tizen/SwipeGestureHandler.cs b/src/Compatibility/Core/src/Tizen/SwipeGestureHandler.cs index b9116928bf..e34d3b6f72 100644 --- a/src/Compatibility/Core/src/Tizen/SwipeGestureHandler.cs +++ b/src/Compatibility/Core/src/Tizen/SwipeGestureHandler.cs @@ -2,6 +2,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [System.Obsolete] public class SwipeGestureHandler : GestureHandler { public SwipeGestureHandler(IGestureRecognizer recognizer) : base(recognizer) diff --git a/src/Compatibility/Core/src/Tizen/TapGestureHandler.cs b/src/Compatibility/Core/src/Tizen/TapGestureHandler.cs index 66eaf78c98..5d23d8370c 100644 --- a/src/Compatibility/Core/src/Tizen/TapGestureHandler.cs +++ b/src/Compatibility/Core/src/Tizen/TapGestureHandler.cs @@ -4,6 +4,7 @@ using ElmSharp; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public class TapGestureHandler : GestureHandler { public TapGestureHandler(IGestureRecognizer recognizer) : base(recognizer) diff --git a/src/Compatibility/Core/src/Tizen/ThemeConstants.cs b/src/Compatibility/Core/src/Tizen/ThemeConstants.cs index 4bfe44f30c..95b1cd1591 100644 --- a/src/Compatibility/Core/src/Tizen/ThemeConstants.cs +++ b/src/Compatibility/Core/src/Tizen/ThemeConstants.cs @@ -1,5 +1,7 @@ +using Microsoft.Maui.Devices; using Tizen.Common; using EColor = ElmSharp.Color; +using Color = Microsoft.Maui.Graphics.Color; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { @@ -516,7 +518,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public class Resources { public const int IconSize = 48; - public const string IconPath = "Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Resource.refresh_48dp.png"; + public const string IconPath = "Microsoft.Maui.Controls.Compatibility.Tizen.Resources.refresh_48dp.png"; } public class ColorClass @@ -565,16 +567,16 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public class Resources { // The source of icon resources is https://materialdesignicons.com/ - public const string MenuIcon = "Resource.menu.png"; - public const string BackIcon = "Resource.arrow_left.png"; - public const string DotsIcon = "Resource.dots_horizontal.png"; + public const string MenuIcon = "Resources.menu.png"; + public const string BackIcon = "Resources.arrow_left.png"; + public const string DotsIcon = "Resources.dots_horizontal.png"; public class Watch { public const int DefaultNavigationViewIconSize = 60; public const int DefaultDrawerTouchWidth = 50; public const int DefaultDrawerIconSize = 40; - public const string DefaultDrawerIcon = "Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Resource.wc_visual_cue.png"; + public const string DefaultDrawerIcon = "Microsoft.Maui.Controls.Compatibility.Tizen.Resources.wc_visual_cue.png"; } public class TV @@ -588,8 +590,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public class ColorClass { public static readonly Color DefaultBackgroundColor = Color.FromRgb(33, 150, 243); - public static readonly Color DefaultForegroundColor = Color.White; - public static readonly Color DefaultTitleColor = Color.White; + public static readonly Color DefaultForegroundColor = Color.FromRgb(255, 255, 255); + public static readonly Color DefaultTitleColor = Color.FromRgb(0, 0, 0); public static readonly EColor DefaultNavigationViewBackgroundColor = EColor.White; public static readonly EColor DefaultDrawerDimBackgroundColor = new EColor(0, 0, 0, 82); @@ -618,8 +620,8 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { public class Resources { - public const string PlayImagePath = "Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Resource.img_button_play.png"; - public const string PauseImagePath = "Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Resource.img_button_pause.png"; + public const string PlayImagePath = "Microsoft.Maui.Controls.Compatibility.Tizen.Resources.img_button_play.png"; + public const string PauseImagePath = "Microsoft.Maui.Controls.Compatibility.Tizen.Resources.img_button_pause.png"; } public class ColorClass diff --git a/src/Compatibility/Core/src/Tizen/ThemeManager.cs b/src/Compatibility/Core/src/Tizen/ThemeManager.cs index 51c755a47c..ae51278f36 100644 --- a/src/Compatibility/Core/src/Tizen/ThemeManager.cs +++ b/src/Compatibility/Core/src/Tizen/ThemeManager.cs @@ -1,8 +1,10 @@ using System; +using Microsoft.Maui.Devices; using ElmSharp; using ElmSharp.Wearable; -using Microsoft.Maui.Controls.Compatibility.Platform.TV; +#pragma warning disable CS0612 // Type or member is obsolete using static Microsoft.Maui.Controls.Compatibility.Platform.Tizen.Native.TableView; +#pragma warning disable CS0612 // Type or member is obsolete using EButton = ElmSharp.Button; using EColor = ElmSharp.Color; using EEntry = ElmSharp.Entry; @@ -11,10 +13,13 @@ using ELayout = ElmSharp.Layout; using EProgressBar = ElmSharp.ProgressBar; using ESize = ElmSharp.Size; using ESlider = ElmSharp.Slider; +using EToolbar = ElmSharp.Toolbar; using EToolbarItem = ElmSharp.ToolbarItem; +using Index = ElmSharp.Index; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] public static class ThemeManager { #region Layout @@ -216,9 +221,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public static EButton SetWatchPopupRightStyle(this EButton button) { - if (Device.Idiom != TargetIdiom.Watch) + if (DeviceInfo.Idiom != DeviceIdiom.Watch) { - Log.Error($"ToWatchPopupRightStyleButton is only supported on TargetIdiom.Watch : {0}", Device.Idiom); + Log.Error($"ToWatchPopupRightStyleButton is only supported on DeviceIdiom.Watch : {0}", DeviceInfo.Idiom); return button; } button.Style = ThemeConstants.Button.Styles.Watch.PopupRight; @@ -227,9 +232,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public static EButton SetWatchPopupLeftStyle(this EButton button) { - if (Device.Idiom != TargetIdiom.Watch) + if (DeviceInfo.Idiom != DeviceIdiom.Watch) { - Log.Error($"WatchPopupLeftStyleButton is only supported on TargetIdiom.Watch : {0}", Device.Idiom); + Log.Error($"WatchPopupLeftStyleButton is only supported on DeviceIdiom.Watch : {0}", DeviceInfo.Idiom); return button; } button.Style = ThemeConstants.Button.Styles.Watch.PopupLeft; @@ -238,9 +243,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public static EButton SetWatchTextStyle(this EButton button) { - if (Device.Idiom != TargetIdiom.Watch) + if (DeviceInfo.Idiom != DeviceIdiom.Watch) { - Log.Error($"ToWatchPopupRightStyleButton is only supported on TargetIdiom.Watch : {0}", Device.Idiom); + Log.Error($"ToWatchPopupRightStyleButton is only supported on DeviceIdiom.Watch : {0}", DeviceInfo.Idiom); return button; } button.Style = ThemeConstants.Button.Styles.Watch.Text; @@ -291,9 +296,9 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen #region Popup public static Popup SetWatchCircleStyle(this Popup popup) { - if (Device.Idiom != TargetIdiom.Watch) + if (DeviceInfo.Idiom != DeviceIdiom.Watch) { - Log.Error($"WatchCircleStylePopup is only supported on TargetIdiom.Watch : {0}", Device.Idiom); + Log.Error($"WatchCircleStylePopup is only supported on DeviceIdiom.Watch : {0}", DeviceInfo.Idiom); return popup; } popup.Style = ThemeConstants.Popup.Styles.Watch.Circle; @@ -419,7 +424,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen for (int i = 0; i < ret.Length; i++) { - ret[i] = check.ClassName.ToLower().Replace("elm_", "") + "/" + ret[i]; + ret[i] = check.ClassName.ToLower().Replace("elm_", "", StringComparison.Ordinal) + "/" + ret[i]; } return ret; } @@ -473,17 +478,17 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen #endregion #region Toolbar - public static Toolbar SetNavigationBarStyle(this Toolbar toolbar) + public static EToolbar SetNavigationBarStyle(this EToolbar toolbar) { toolbar.Style = ThemeConstants.Toolbar.Styles.NavigationBar; return toolbar; } - public static Toolbar SetTVTabBarWithTitleStyle(this Toolbar toolbar) + public static EToolbar SetTVTabBarWithTitleStyle(this EToolbar toolbar) { - if (Device.Idiom != TargetIdiom.TV) + if (DeviceInfo.Idiom != DeviceIdiom.TV) { - Log.Error($"TabBarWithTitleStyle is only supported on TargetIdiom.TV : {0}", Device.Idiom); + Log.Error($"TabBarWithTitleStyle is only supported on DeviceIdiom.TV : {0}", DeviceInfo.Idiom); return toolbar; } toolbar.Style = ThemeConstants.Toolbar.Styles.TV.TabbarWithTitle; @@ -636,7 +641,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen public static void SendSignalToItem(this Cell cell, GenListItem item) { // This is only required for TV profile. - if (Device.Idiom != TargetIdiom.TV) + if (DeviceInfo.Idiom != DeviceIdiom.TV) return; if (cell is ImageCell) @@ -960,24 +965,24 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen return s_navigationViewFlyoutItemFontSize = CalculateDoubleScaledSizeInLargeScreen(25); } - public static Color GetTvFlyoutItemDefaultColor(this INavigationView nav) + public static Graphics.Color GetTvFlyoutItemDefaultColor(this INavigationView nav) { - return Color.Transparent; + return new Graphics.Color(0f); } - public static Color GetTvFlyoutItemFocusedColor(this INavigationView nav) + public static Graphics.Color GetTvFlyoutItemFocusedColor(this INavigationView nav) { - return new Color(0.95); + return new Graphics.Color(0.95f); } - public static Color GetTvFlyoutItemTextDefaultColor(this INavigationView nav) + public static Graphics.Color GetTvFlyoutItemTextDefaultColor(this INavigationView nav) { - return Color.White; + return Graphics.Color.FromRgb(255, 255, 255); } - public static Color GetTvFlyoutItemTextFocusedColor(this INavigationView nav) + public static Graphics.Color GetTvFlyoutItemTextFocusedColor(this INavigationView nav) { - return Color.Black; + return Graphics.Color.FromRgb(0, 0, 0); } #endregion diff --git a/src/Compatibility/Core/src/Tizen/TizenIsolatedStorageFile.cs b/src/Compatibility/Core/src/Tizen/TizenIsolatedStorageFile.cs deleted file mode 100644 index 7ecb5d5985..0000000000 --- a/src/Compatibility/Core/src/Tizen/TizenIsolatedStorageFile.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.Maui.Controls.Compatibility.Internals; -using IOPath = System.IO.Path; -using TApplication = Tizen.Applications.Application; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - internal class TizenIsolatedStorageFile : IIsolatedStorageFile - { - readonly string _rootPath; - - internal TizenIsolatedStorageFile() - { - _rootPath = TApplication.Current.DirectoryInfo.Data; - } - - public void CreateDirectory(string path) - { - if (path == null) - throw new ArgumentNullException(nameof(path)); - Directory.CreateDirectory(IOPath.Combine(_rootPath, path)); - } - - public Task CreateDirectoryAsync(string path) - { - CreateDirectory(path); - return Task.FromResult(true); - } - - public void MoveFile(string source, string dest) - { - if (source == null) - throw new ArgumentNullException(nameof(source)); - if (dest == null) - throw new ArgumentNullException(nameof(dest)); - - File.Move(IOPath.Combine(_rootPath, source), IOPath.Combine(_rootPath, dest)); - } - - public void DeleteFile(string path) - { - if (path == null) - throw new ArgumentNullException(nameof(path)); - if (path.Trim().Length == 0) - throw new ArgumentException("An empty path is not valid."); - - File.Delete(IOPath.Combine(_rootPath, path)); - } - - public bool DirectoryExists(string path) - { - if (path == null) - throw new ArgumentNullException(nameof(path)); - return Directory.Exists(IOPath.Combine(_rootPath, path)); - } - - public Task GetDirectoryExistsAsync(string path) - { - return Task.FromResult(DirectoryExists(path)); - } - - public bool FileExists(string path) - { - if (path == null) - throw new ArgumentNullException(nameof(path)); - return File.Exists(IOPath.Combine(_rootPath, path)); - } - - public Task GetFileExistsAsync(string path) - { - return Task.FromResult(FileExists(path)); - } - - public DateTimeOffset GetLastWriteTime(string path) - { - if (path == null) - throw new ArgumentNullException(nameof(path)); - if (path.Trim().Length == 0) - throw new ArgumentException("An empty path is not valid."); - - string fullPath = IOPath.Combine(_rootPath, path); - if (File.Exists(fullPath)) - return File.GetLastWriteTime(fullPath); - - return Directory.GetLastWriteTime(fullPath); - } - - public Task GetLastWriteTimeAsync(string path) - { - return Task.FromResult(GetLastWriteTime(path)); - } - - public Stream OpenFile(string path, FileMode mode) - { - return OpenFile(path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite)); - } - - public Stream OpenFile(string path, FileMode mode, FileAccess access) - { - return OpenFile(path, mode, access, FileShare.Read); - } - - public Stream OpenFile(string path, FileMode mode, FileAccess access, FileShare share) - { - if (path == null) - throw new ArgumentNullException(nameof(path)); - if (path.Trim().Length == 0) - throw new ArgumentException("An empty path is not valid."); - - string fullPath = IOPath.Combine(_rootPath, path); - return new FileStream(fullPath, mode, access, share); - } - - public Task OpenFileAsync(string path, FileMode mode, FileAccess access) - { - return Task.FromResult(OpenFile(path, mode, access)); - } - - public Task OpenFileAsync(string path, FileMode mode, FileAccess access, FileShare share) - { - return Task.FromResult(OpenFile(path, mode, access, share)); - } - - } -} diff --git a/src/Compatibility/Core/src/Tizen/TizenPlatformServices.cs b/src/Compatibility/Core/src/Tizen/TizenPlatformServices.cs deleted file mode 100644 index 208c8fa63f..0000000000 --- a/src/Compatibility/Core/src/Tizen/TizenPlatformServices.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Reflection; -using System.Security.Cryptography; -using System.Threading; -using System.Threading.Tasks; -using ElmSharp; -using Microsoft.Maui.Controls.Compatibility.Internals; -using TAppControl = Tizen.Applications.AppControl; - -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - internal class TizenPlatformServices : IPlatformServices - { - static SynchronizationContext s_context; - - public TizenPlatformServices() - { - s_context = SynchronizationContext.Current; - } - - public class TizenTicker : Ticker - { - readonly Timer _timer; - - public TizenTicker() - { - _timer = new Timer((object o) => HandleElapsed(o), this, Timeout.Infinite, Timeout.Infinite); - } - - protected override void EnableTimer() - { - _timer.Change(16, 16); - } - - protected override void DisableTimer() - { - _timer.Change(-1, -1); - } - - void HandleElapsed(object state) - { - s_context.Post((o) => SendSignals(-1), null); - } - } - #region IPlatformServices implementation - - public void BeginInvokeOnMainThread(Action action) - { - s_context.Post((o) => action(), null); - } - - public Ticker CreateTicker() - { - return new TizenTicker(); - } - - public void StartTimer(TimeSpan interval, Func callback) - { - Timer timer = null; - bool invoking = false; - TimerCallback onTimeout = o => - { - if (!invoking) - { - invoking = true; - BeginInvokeOnMainThread(() => - { - if (!callback()) - { - timer.Dispose(); - } - invoking = false; - } - ); - } - }; - timer = new Timer(onTimeout, null, Timeout.Infinite, Timeout.Infinite); - // set interval separarately to prevent calling onTimeout before `timer' is assigned - timer.Change(interval, interval); - } - - public async Task GetStreamAsync(Uri uri, CancellationToken cancellationToken) - { - using (var client = new HttpClient()) - using (HttpResponseMessage response = await client.GetAsync(uri, cancellationToken)) - return await response.Content.ReadAsStreamAsync(); - } - - public IIsolatedStorageFile GetUserStoreForApplication() - { - return new TizenIsolatedStorageFile(); - } - - public void QuitApplication() - { - Forms.Context.Exit(); - } - - public bool IsInvokeRequired => !EcoreMainloop.IsMainThread; - - #endregion - - public SizeRequest GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint) - { - return Platform.GetNativeSize(view, widthConstraint, heightConstraint); - } - - public AppTheme RequestedTheme => AppTheme.Unspecified; - - static MD5 CreateChecksum() - { - return MD5.Create(); - } - } -} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/VisualElementChangedEventArgs.cs b/src/Compatibility/Core/src/Tizen/VisualElementChangedEventArgs.cs deleted file mode 100644 index 229309021c..0000000000 --- a/src/Compatibility/Core/src/Tizen/VisualElementChangedEventArgs.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen -{ - /// - /// Represents the arguments passed to every VisualElement change event. - /// - public class VisualElementChangedEventArgs : ElementChangedEventArgs - { - /// - /// Initializes a new instance of the class. - /// - /// Old element. - /// New element. - public VisualElementChangedEventArgs(VisualElement oldElement, VisualElement newElement) : base(oldElement, newElement) - { - } - } -} diff --git a/src/Compatibility/Maps/src/Tizen/Compatibility.Maps.Tizen.csproj b/src/Compatibility/Maps/src/Tizen/Compatibility.Maps.Tizen.csproj index 36da7799b3..86f48042c3 100644 --- a/src/Compatibility/Maps/src/Tizen/Compatibility.Maps.Tizen.csproj +++ b/src/Compatibility/Maps/src/Tizen/Compatibility.Maps.Tizen.csproj @@ -1,17 +1,17 @@ - tizen40 - Tizen - v4.0 + $(_MauiDotNetTfm)-tizen + Microsoft.Maui.Controls.Compatibility.Maps.Tizen + Microsoft.Maui.Controls.Compatibility.Maps.Tizen + false + disable - - - - - - + + + + diff --git a/src/Compatibility/Maps/src/Tizen/FormsMaps.cs b/src/Compatibility/Maps/src/Tizen/FormsMaps.cs index 96e22d17e5..5ab23bb4a9 100644 --- a/src/Compatibility/Maps/src/Tizen/FormsMaps.cs +++ b/src/Compatibility/Maps/src/Tizen/FormsMaps.cs @@ -1,9 +1,9 @@ using System; using System.Diagnostics; using System.Threading.Tasks; -using Tizen.Maps; using Microsoft.Maui.Controls.Compatibility.Maps.Tizen; -using Microsoft.Maui.Controls.Platform.Tizen; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +using Tizen.Maps; namespace Microsoft.Maui.Controls { @@ -28,13 +28,14 @@ namespace Microsoft.Maui.Controls return; _mapService = new MapService(provider, authenticationToken); - +#pragma warning disable CS0612 // Type or member is obsolete FormsApplication.RequestingUserConsentFunc = new Func(() => { TaskCompletionSource userConsentWaiter = new TaskCompletionSource(); UserConsentAction(userConsentWaiter); return userConsentWaiter.Task; }); +#pragma warning disable CS0612 // Type or member is obsolete } static async void UserConsentAction(TaskCompletionSource tcs) diff --git a/src/Compatibility/Maps/src/Tizen/GeocoderBackend.cs b/src/Compatibility/Maps/src/Tizen/GeocoderBackend.cs index 3ec3ef394e..ec9f93515c 100644 --- a/src/Compatibility/Maps/src/Tizen/GeocoderBackend.cs +++ b/src/Compatibility/Maps/src/Tizen/GeocoderBackend.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.Maui.Controls.Maps; namespace Microsoft.Maui.Controls.Compatibility.Maps.Tizen { diff --git a/src/Compatibility/Maps/src/Tizen/MapRenderer.cs b/src/Compatibility/Maps/src/Tizen/MapRenderer.cs index bc3f6a7f20..cf85f72afc 100644 --- a/src/Compatibility/Maps/src/Tizen/MapRenderer.cs +++ b/src/Compatibility/Maps/src/Tizen/MapRenderer.cs @@ -4,14 +4,19 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; +using Microsoft.Maui.Controls.Maps; +using Microsoft.Maui.Controls.Platform; using Tizen.Location; using Tizen.Maps; -using Microsoft.Maui.Controls.Platform.Tizen; +using Pin = Microsoft.Maui.Controls.Maps.Pin; using TPin = Tizen.Maps.Pin; namespace Microsoft.Maui.Controls.Compatibility.Maps.Tizen { +#pragma warning disable CS0618 // Type or member is obsolete public class MapRenderer : ViewRenderer +#pragma warning disable CS0618 // Type or member is obsolete { const string MoveMessageName = "MapMoveToRegion"; const int BaseZoomLevel = 2; diff --git a/src/Compatibility/Maps/src/Tizen/Properties/AssemblyInfo.cs b/src/Compatibility/Maps/src/Tizen/Properties/AssemblyInfo.cs index 61fbc3f25a..16531064d6 100644 --- a/src/Compatibility/Maps/src/Tizen/Properties/AssemblyInfo.cs +++ b/src/Compatibility/Maps/src/Tizen/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ -using Microsoft.Maui.Controls; -using Microsoft.Maui.Controls.Compatibility.Maps; +using Microsoft.Maui.Controls.Compatibility; using Microsoft.Maui.Controls.Compatibility.Maps.Tizen; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Controls.Maps; [assembly: ExportRenderer(typeof(Map), typeof(MapRenderer))] \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Tizen/Main.cs b/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Tizen/Main.cs new file mode 100644 index 0000000000..fc21470992 --- /dev/null +++ b/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Tizen/Main.cs @@ -0,0 +1,17 @@ +using System; +using Microsoft.Maui; +using Microsoft.Maui.Hosting; + +namespace Maui.Controls.Sample.Tizen +{ + class Program : MauiApplication + { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Tizen/tizen-manifest.xml b/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 0000000000..f46ad9bf73 --- /dev/null +++ b/src/Controls/samples/Controls.Sample.Sandbox/Platforms/Tizen/tizen-manifest.xml @@ -0,0 +1,29 @@ + + + + + xhdpi/appicon.xhigh.png + xhdpi/appicon.xhigh.png + hdpi/appicon.high.png + + + + + + + + + + + + + + + + + + + + http://tizen.org/privilege/internet + + \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Tizen/Main.cs b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Tizen/Main.cs new file mode 100644 index 0000000000..5fc566fbb1 --- /dev/null +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Tizen/Main.cs @@ -0,0 +1,17 @@ +using System; +using Microsoft.Maui; +using Microsoft.Maui.Hosting; + +namespace Maui.Controls.Sample.SingleProject +{ + class Program : MauiApplication + { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Tizen/tizen-manifest.xml b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 0000000000..0cae846153 --- /dev/null +++ b/src/Controls/samples/Controls.Sample.SingleProject/Platforms/Tizen/tizen-manifest.xml @@ -0,0 +1,27 @@ + + + + + + appicon.xhigh.png + + + + + + + + + + + + + + + + + + + http://tizen.org/privilege/internet + + diff --git a/src/Controls/samples/Controls.Sample.Tizen/Controls.Sample.Tizen.csproj b/src/Controls/samples/Controls.Sample.Tizen/Controls.Sample.Tizen.csproj new file mode 100644 index 0000000000..4fd7ad8f82 --- /dev/null +++ b/src/Controls/samples/Controls.Sample.Tizen/Controls.Sample.Tizen.csproj @@ -0,0 +1,17 @@ + + + + Exe + tizen40 + Maui.Controls.Sample.Tizen + Maui.Controls.Sample.Tizen + + + + + + + + + + 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 0000000000..5ac254c7f6 --- /dev/null +++ b/src/Controls/samples/Controls.Sample.Tizen/Main.cs @@ -0,0 +1,21 @@ +using Microsoft.Maui; +using Microsoft.Maui.Hosting; + +namespace Maui.Controls.Sample.Tizen +{ + class Program : MauiApplication + { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + + protected override void OnCreate() + { + base.OnCreate(); + } + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/src/Controls/samples/Controls.Sample.Tizen/res/dokdo_regular.ttf b/src/Controls/samples/Controls.Sample.Tizen/res/dokdo_regular.ttf new file mode 100644 index 0000000000..051a88fe37 Binary files /dev/null and b/src/Controls/samples/Controls.Sample.Tizen/res/dokdo_regular.ttf differ diff --git a/src/Controls/samples/Controls.Sample.Tizen/shared/res/icon.png b/src/Controls/samples/Controls.Sample.Tizen/shared/res/icon.png new file mode 100644 index 0000000000..8f56909cdd Binary files /dev/null and b/src/Controls/samples/Controls.Sample.Tizen/shared/res/icon.png differ 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 0000000000..fcc191b94a --- /dev/null +++ b/src/Controls/samples/Controls.Sample.Tizen/tizen-manifest.xml @@ -0,0 +1,27 @@ + + + + + + appicon.xhigh.png + + + + + + + + + + + + + + + + + http://tizen.org/privilege/internet + + + + \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs index 66b818b1eb..6cf29c51de 100644 --- a/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs +++ b/src/Controls/samples/Controls.Sample/Controls/BordelessEntry/BordelessEntryHandler.cs @@ -34,6 +34,10 @@ namespace Maui.Controls.Sample.Controls public static void MapBorder(BordelessEntryHandler handler, BordelessEntry borderlessEntry) { } +#elif TIZEN + public static void MapBorder(BordelessEntryHandler handler, BordelessEntry borderlessEntry) + { + } #else public static void MapBorder(BordelessEntryHandler handler, BordelessEntry borderlessEntry) { diff --git a/src/Controls/samples/Controls.Sample/Controls/FocusEffect/FocusPlatformEffect.cs b/src/Controls/samples/Controls.Sample/Controls/FocusEffect/FocusPlatformEffect.cs index 8883f67e4f..5af77c22fb 100644 --- a/src/Controls/samples/Controls.Sample/Controls/FocusEffect/FocusPlatformEffect.cs +++ b/src/Controls/samples/Controls.Sample/Controls/FocusEffect/FocusPlatformEffect.cs @@ -15,6 +15,8 @@ namespace Maui.Controls.Sample.Controls Android.Graphics.Color backgroundColor; #elif __IOS__ UIKit.UIColor backgroundColor; +#elif TIZEN + ElmSharp.Color backgroundColor; #endif public FocusPlatformEffect() @@ -33,6 +35,8 @@ namespace Maui.Controls.Sample.Controls Control.SetBackgroundColor(backgroundColor); #elif __IOS__ Control.BackgroundColor = backgroundColor = UIKit.UIColor.FromRGB(204, 153, 255); +#elif TIZEN + (Control as ElmSharp.Widget).BackgroundColor = backgroundColor = ElmSharp.Color.FromRgb(204, 153, 255); #endif } catch (Exception ex) @@ -75,6 +79,21 @@ namespace Maui.Controls.Sample.Controls Control.BackgroundColor = backgroundColor; } } +#elif TIZEN + if (args.PropertyName == "IsFocused") + { + if (Control is ElmSharp.Widget widget) + { + if (widget.BackgroundColor == backgroundColor) + { + widget.BackgroundColor = ElmSharp.Color.White; + } + else + { + widget.BackgroundColor = backgroundColor; + } + } + } #endif } catch (Exception ex) diff --git a/src/Controls/samples/Controls.Sample/Controls/SkiaSharpHandlers/SkiaGraphicsViewHandler.cs b/src/Controls/samples/Controls.Sample/Controls/SkiaSharpHandlers/SkiaGraphicsViewHandler.cs index ae2feabdfe..1dca399d22 100644 --- a/src/Controls/samples/Controls.Sample/Controls/SkiaSharpHandlers/SkiaGraphicsViewHandler.cs +++ b/src/Controls/samples/Controls.Sample/Controls/SkiaSharpHandlers/SkiaGraphicsViewHandler.cs @@ -27,6 +27,8 @@ namespace Maui.Controls.Sample.Controls { #if __ANDROID__ return new SkiaGraphicsView(Context); +#elif TIZEN + return new SkiaGraphicsView(NativeParent); #else return new SkiaGraphicsView(); #endif diff --git a/src/Controls/samples/Controls.Sample/Controls/SkiaSharpHandlers/SkiaShapeViewHandler.cs b/src/Controls/samples/Controls.Sample/Controls/SkiaSharpHandlers/SkiaShapeViewHandler.cs index b42c950a56..934bede1c9 100644 --- a/src/Controls/samples/Controls.Sample/Controls/SkiaSharpHandlers/SkiaShapeViewHandler.cs +++ b/src/Controls/samples/Controls.Sample/Controls/SkiaSharpHandlers/SkiaShapeViewHandler.cs @@ -36,6 +36,8 @@ namespace Maui.Controls.Sample.Controls { #if __ANDROID__ return new SkiaGraphicsView(Context); +#elif TIZEN + return new SkiaGraphicsView(NativeParent); #else return new SkiaGraphicsView(); #endif diff --git a/src/Controls/samples/Controls.Sample/Startup.cs b/src/Controls/samples/Controls.Sample/Startup.cs index 51a0be4071..cff2edeb56 100644 --- a/src/Controls/samples/Controls.Sample/Startup.cs +++ b/src/Controls/samples/Controls.Sample/Startup.cs @@ -39,6 +39,9 @@ namespace Maui.Controls.Sample var appBuilder = MauiApp.CreateBuilder(); appBuilder.UseMauiApp(); +#if TIZEN + appBuilder.UseMauiCompatibility(); +#endif var services = appBuilder.Services; if (UseMauiGraphicsSkia) @@ -72,7 +75,10 @@ namespace Maui.Controls.Sample //#elif WINDOWS // handlers.AddCompatibilityRenderer(typeof(CustomButton), // typeof(Microsoft.Maui.Controls.Compatibility.Platform.UWP.ButtonRenderer)); -//#endif +// #elif TIZEN +// handlers.AddCompatibilityRenderer(typeof(CustomButton), +// typeof(Microsoft.Maui.Controls.Compatibility.Platform.Tizen.ButtonRenderer)); +// #endif //#pragma warning restore CS0618 // Type or member is obsolete // }); @@ -228,6 +234,19 @@ namespace Maui.Controls.Sample .OnClosed((a, b) => LogEvent(nameof(WindowsLifecycle.OnClosed))) .OnLaunched((a, b) => LogEvent(nameof(WindowsLifecycle.OnLaunched))) .OnVisibilityChanged((a, b) => LogEvent(nameof(WindowsLifecycle.OnVisibilityChanged)))); +#elif TIZEN + events.AddTizen(tizen => tizen + .OnAppControlReceived((a, b) => LogEvent(nameof(TizenLifecycle.OnAppControlReceived))) + .OnCreate((a) => LogEvent(nameof(TizenLifecycle.OnCreate))) + .OnDeviceOrientationChanged((a, b) => LogEvent(nameof(TizenLifecycle.OnDeviceOrientationChanged))) + .OnLocaleChanged((a, b) => LogEvent(nameof(TizenLifecycle.OnLocaleChanged))) + .OnLowBattery((a, b) => LogEvent(nameof(TizenLifecycle.OnLowBattery))) + .OnLowMemory((a, b) => LogEvent(nameof(TizenLifecycle.OnLowMemory))) + .OnPause((a) => LogEvent(nameof(TizenLifecycle.OnPause))) + .OnPreCreate((a) => LogEvent(nameof(TizenLifecycle.OnPreCreate))) + .OnRegionFormatChanged((a, b) => LogEvent(nameof(TizenLifecycle.OnRegionFormatChanged))) + .OnResume((a) => LogEvent(nameof(TizenLifecycle.OnResume))) + .OnTerminate((a) => LogEvent(nameof(TizenLifecycle.OnTerminate)))); #endif static bool LogEvent(string eventName, string type = null) diff --git a/src/Compatibility/Core/src/Tizen/FontNamedSizeService.cs b/src/Controls/src/Core/Compatibility/Tizen/FontNamedSizeService.cs similarity index 89% rename from src/Compatibility/Core/src/Tizen/FontNamedSizeService.cs rename to src/Controls/src/Core/Compatibility/Tizen/FontNamedSizeService.cs index b1fa20fe34..b182ce2c06 100644 --- a/src/Compatibility/Core/src/Tizen/FontNamedSizeService.cs +++ b/src/Controls/src/Core/Compatibility/Tizen/FontNamedSizeService.cs @@ -1,10 +1,14 @@ using System; using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Devices; +#pragma warning disable CS0612 // Type or member is obsolete [assembly: Microsoft.Maui.Controls.Dependency(typeof(Microsoft.Maui.Controls.Compatibility.Platform.Tizen.FontNamedSizeService))] +#pragma warning disable CS0612 // Type or member is obsolete namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] class FontNamedSizeService : IFontNamedSizeService { public double GetNamedSize(NamedSize size, Type targetElementType, bool useOldSizes) @@ -44,7 +48,7 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen default: throw new ArgumentOutOfRangeException(nameof(size)); } - return Forms.ConvertToDPFont(pt); + return DPExtensions.ConvertToDPFont(pt); } } } \ No newline at end of file diff --git a/src/Controls/src/Core/Compatibility/Tizen/PlatformInvalidate.cs b/src/Controls/src/Core/Compatibility/Tizen/PlatformInvalidate.cs new file mode 100644 index 0000000000..773a913d2e --- /dev/null +++ b/src/Controls/src/Core/Compatibility/Tizen/PlatformInvalidate.cs @@ -0,0 +1,19 @@ +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) + { + if (visualElement.Handler?.PlatformView == null) + { + return; + } + + visualElement.ToPlatform().MarkChanged(); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Compatibility/Tizen/PlatformSizeService.cs b/src/Controls/src/Core/Compatibility/Tizen/PlatformSizeService.cs new file mode 100644 index 0000000000..62298693fb --- /dev/null +++ b/src/Controls/src/Core/Compatibility/Tizen/PlatformSizeService.cs @@ -0,0 +1,20 @@ +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) + { + if (widthConstraint > 0 && heightConstraint > 0) + { + return view.Handler?.GetDesiredSize(widthConstraint, heightConstraint) ?? + new SizeRequest(); + } + + return new SizeRequest(); + } + } +} \ No newline at end of file diff --git a/src/Compatibility/Core/src/Tizen/ResourcesProvider.cs b/src/Controls/src/Core/Compatibility/Tizen/ResourcesProvider.cs similarity index 91% rename from src/Compatibility/Core/src/Tizen/ResourcesProvider.cs rename to src/Controls/src/Core/Compatibility/Tizen/ResourcesProvider.cs index 31bf6af6ec..1a48a80ff0 100644 --- a/src/Compatibility/Core/src/Tizen/ResourcesProvider.cs +++ b/src/Controls/src/Core/Compatibility/Tizen/ResourcesProvider.cs @@ -1,7 +1,10 @@ -using Microsoft.Maui.Controls.Compatibility.Internals; +using System; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen { + [Obsolete] internal class ResourcesProvider : ISystemResourcesProvider { ResourceDictionary _dictionary; @@ -56,14 +59,14 @@ namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen return style; } - Style GetStyle(int? fontSize = null, Color? textColor = null) + Style GetStyle(int? fontSize = null, Color textColor = null) { Style style = new Style(typeof(Label)); if (fontSize.HasValue) { style.Setters.Add(new Setter { Property = Label.FontSizeProperty, Value = fontSize }); } - if (textColor.HasValue) + if (textColor != null) { style.Setters.Add(new Setter { Property = Label.TextColorProperty, Value = textColor }); } diff --git a/src/Controls/src/Core/HandlerImpl/Button/Button.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Button/Button.Tizen.cs new file mode 100644 index 0000000000..b5eab66e32 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Button/Button.Tizen.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Maui.Controls.Platform; + +namespace Microsoft.Maui.Controls +{ + public partial class Button + { + public static void MapText(ButtonHandler handler, Button button) + { + handler.PlatformView?.UpdateText(button); + } + + [MissingMapper] + public static void MapLineBreakMode(IButtonHandler handler, Button button) {} + } +} diff --git a/src/Controls/src/Core/HandlerImpl/Editor/Editor.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Editor/Editor.Tizen.cs new file mode 100644 index 0000000000..c7c657b378 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Editor/Editor.Tizen.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Maui.Controls +{ + public partial class Editor + { + public static void MapText(EditorHandler handler, Editor editor) + { + Platform.TextExtensions.UpdateText(handler.PlatformView, editor); + } + } +} diff --git a/src/Controls/src/Core/HandlerImpl/Element/Element.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Element/Element.Tizen.cs new file mode 100644 index 0000000000..1155fee413 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Element/Element.Tizen.cs @@ -0,0 +1,19 @@ +#nullable enable + +using Microsoft.Maui.Controls.Platform; + +namespace Microsoft.Maui.Controls +{ + public partial class Element + { + public static void MapAutomationPropertiesIsInAccessibleTree(IElementHandler handler, Element element) + { + //TODO : Need to impl + } + + public static void MapAutomationPropertiesExcludedWithChildren(IElementHandler handler, Element element) + { + //TODO : Need to impl + } + } +} diff --git a/src/Controls/src/Core/HandlerImpl/Entry/Entry.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Entry/Entry.Tizen.cs new file mode 100644 index 0000000000..7b1ed44178 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Entry/Entry.Tizen.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Maui.Controls +{ + public partial class Entry + { + public static void MapText(EntryHandler handler, Entry entry) + { + Platform.TextExtensions.UpdateText(handler.PlatformView, entry); + } + } +} diff --git a/src/Controls/src/Core/HandlerImpl/Label/Label.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Label/Label.Tizen.cs new file mode 100644 index 0000000000..37c0f6347a --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Label/Label.Tizen.cs @@ -0,0 +1,57 @@ +using Microsoft.Maui; +using Microsoft.Maui.Handlers; +using Microsoft.Maui.Controls.Platform; + +namespace Microsoft.Maui.Controls +{ + public partial class Label + { + public static void MapTextType(LabelHandler handler, Label label) + { + handler.PlatformView?.UpdateText(label); + } + + public static void MapText(LabelHandler handler, Label label) + { + handler.PlatformView?.UpdateText(label); + } + + public static void MapTextDecorations(LabelHandler handler, Label label) + { + if (label?.TextType == TextType.Html) + { + return; + } + + LabelHandler.MapTextDecorations(handler, label); + } + + public static void MapFont(LabelHandler handler, Label label) + { + if (label?.TextType == TextType.Html) + { + return; + } + + LabelHandler.MapFont(handler, label); + } + + public static void MapTextColor(LabelHandler handler, Label label) + { + if (label?.TextType == TextType.Html) + { + return; + } + + LabelHandler.MapTextColor(handler, label); + } + + public static void MapLineBreakMode(ILabelHandler handler, Label label) + { + handler.PlatformView?.UpdateLineBreakMode(label); + } + + [MissingMapper] + public static void MapMaxLines(ILabelHandler handler, Label label) { } + } +} diff --git a/src/Controls/src/Core/HandlerImpl/Layout/Layout.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Layout/Layout.Tizen.cs new file mode 100644 index 0000000000..18df92e580 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Layout/Layout.Tizen.cs @@ -0,0 +1,11 @@ +namespace Microsoft.Maui.Controls +{ + public partial class Layout + { + public static void MapInputTransparent(LayoutHandler handler, Layout layout) + { + handler.PlatformView?.UpdateInputTransparent(handler, layout); + layout.UpdateDescendantInputTransparent(); + } + } +} diff --git a/src/Controls/src/Core/HandlerImpl/NavigationPage/NavigationPage.Impl.cs b/src/Controls/src/Core/HandlerImpl/NavigationPage/NavigationPage.Impl.cs index aa369445a8..d5cfb498b6 100644 --- a/src/Controls/src/Core/HandlerImpl/NavigationPage/NavigationPage.Impl.cs +++ b/src/Controls/src/Core/HandlerImpl/NavigationPage/NavigationPage.Impl.cs @@ -285,7 +285,7 @@ namespace Microsoft.Maui.Controls p.Toolbar = null; } - if (InternalChildren.Count > 0) + if (Navigation is MauiNavigationImpl && InternalChildren.Count > 0) { var navStack = Navigation.NavigationStack; var visiblePage = Navigation.NavigationStack[NavigationStack.Count - 1]; diff --git a/src/Controls/src/Core/HandlerImpl/SearchBar/SearchBar.Tizen.cs b/src/Controls/src/Core/HandlerImpl/SearchBar/SearchBar.Tizen.cs new file mode 100644 index 0000000000..ce19b366a5 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/SearchBar/SearchBar.Tizen.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Maui.Controls +{ + public partial class SearchBar + { + public static void MapText(SearchBarHandler handler, SearchBar searchBar) + { + Platform.TextExtensions.UpdateText(handler.PlatformView, searchBar); + } + } +} diff --git a/src/Controls/src/Core/HandlerImpl/Shape/Shape.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Shape/Shape.Tizen.cs new file mode 100644 index 0000000000..770c08010c --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Shape/Shape.Tizen.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Handlers; + +namespace Microsoft.Maui.Controls.Shapes +{ + public partial class Shape + { + public static void MapStrokeDashArray(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + } +} diff --git a/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPage.Tizen.cs b/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPage.Tizen.cs new file mode 100644 index 0000000000..2f8b57ca02 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/TabbedPage/TabbedPage.Tizen.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Maui.Handlers; + +namespace Microsoft.Maui.Controls +{ + public partial class TabbedPage + { + internal static void MapBarBackground(ITabbedViewHandler handler, TabbedPage view) + { + } + internal static void MapBarBackgroundColor(ITabbedViewHandler handler, TabbedPage view) + { + } + internal static void MapBarTextColor(ITabbedViewHandler handler, TabbedPage view) + { + } + internal static void MapUnselectedTabColor(ITabbedViewHandler handler, TabbedPage view) + { + } + internal static void MapSelectedTabColor(ITabbedViewHandler handler, TabbedPage view) + { + } + + internal static void MapItemsSource(ITabbedViewHandler handler, TabbedPage view) + { + } + internal static void MapItemTemplate(ITabbedViewHandler handler, TabbedPage view) + { + } + internal static void MapSelectedItem(ITabbedViewHandler handler, TabbedPage view) + { + } + internal static void MapCurrentPage(ITabbedViewHandler handler, TabbedPage view) + { + + } + } +} diff --git a/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Platform.cs b/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Platform.cs index 540247b82e..88058852a1 100644 --- a/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Platform.cs +++ b/src/Controls/src/Core/HandlerImpl/VisualElement/VisualElement.Platform.cs @@ -8,6 +8,8 @@ using PlatformView = UIKit.UIView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; #endif namespace Microsoft.Maui.Controls diff --git a/src/Controls/src/Core/HandlerImpl/Window/Window.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Window/Window.Tizen.cs new file mode 100644 index 0000000000..8c27288b79 --- /dev/null +++ b/src/Controls/src/Core/HandlerImpl/Window/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?.PlatformView 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/Handlers/Items/CarouselViewHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Tizen.cs new file mode 100644 index 0000000000..73542dc5b8 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Tizen.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Maui.Handlers; + +namespace Microsoft.Maui.Controls.Handlers.Items +{ + public partial class CarouselViewHandler : ItemsViewHandler + { + //TODO : Need to impl + public static void MapCurrentItem(CarouselViewHandler handler, CarouselView carouselView) { } + public static void MapPosition(CarouselViewHandler handler, CarouselView carouselView) { } + public static void MapIsBounceEnabled(CarouselViewHandler handler, CarouselView carouselView) { } + public static void MapIsSwipeEnabled(CarouselViewHandler handler, CarouselView carouselView) { } + public static void MapPeekAreaInsets(CarouselViewHandler handler, CarouselView carouselView) { } + public static void MapLoop(CarouselViewHandler handler, CarouselView carouselView) { } + } +} diff --git a/src/Controls/src/Core/Handlers/Items/CollectionViewHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Items/CollectionViewHandler.Tizen.cs new file mode 100644 index 0000000000..1dd9e7e8c8 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/CollectionViewHandler.Tizen.cs @@ -0,0 +1,6 @@ +namespace Microsoft.Maui.Controls.Handlers.Items +{ + public partial class CollectionViewHandler : ReorderableItemsViewHandler + { + } +} diff --git a/src/Controls/src/Core/Handlers/Items/GroupableItemsViewHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Items/GroupableItemsViewHandler.Tizen.cs new file mode 100644 index 0000000000..ccbc69c5dd --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/GroupableItemsViewHandler.Tizen.cs @@ -0,0 +1,9 @@ +namespace Microsoft.Maui.Controls.Handlers.Items +{ + public partial class GroupableItemsViewHandler : SelectableItemsViewHandler where TItemsView : GroupableItemsView + { + public static void MapIsGrouped(GroupableItemsViewHandler handler, GroupableItemsView itemsView) + { + } + } +} diff --git a/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs new file mode 100644 index 0000000000..6809198715 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Tizen.cs @@ -0,0 +1,60 @@ +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Graphics; +using Microsoft.Maui.Handlers; +using TCollectionView = Tizen.UIExtensions.ElmSharp.CollectionView; + +namespace Microsoft.Maui.Controls.Handlers.Items +{ + public abstract partial class ItemsViewHandler : ViewHandler where TItemsView : ItemsView + { + protected ItemsViewHandler(PropertyMapper mapper, CommandMapper commandMapper = null) : base(mapper, commandMapper) + { + } + + protected override TCollectionView CreatePlatformView() + { + return new TCollectionView(NativeParent); + } + + public static void MapItemsSource(ItemsViewHandler handler, ItemsView itemsView) + { + handler.PlatformView.UpdateItemsSource(itemsView); + } + + public static void MapHorizontalScrollBarVisibility(ItemsViewHandler handler, ItemsView itemsView) + { + handler.PlatformView.HorizontalScrollBarVisiblePolicy = itemsView.HorizontalScrollBarVisibility.ToPlatform(); + } + + public static void MapVerticalScrollBarVisibility(ItemsViewHandler handler, ItemsView itemsView) + { + handler.PlatformView.VerticalScrollBarVisiblePolicy = itemsView.VerticalScrollBarVisibility.ToPlatform(); + } + + public static void MapItemTemplate(ItemsViewHandler handler, ItemsView itemsView) + { + handler.PlatformView.UpdateAdaptor(itemsView); + } + + public static void MapEmptyView(ItemsViewHandler handler, ItemsView itemsView) + { + handler.PlatformView.UpdateAdaptor(itemsView); + } + + public static void MapEmptyViewTemplate(ItemsViewHandler handler, ItemsView itemsView) + { + handler.PlatformView.UpdateAdaptor(itemsView); + } + + public static void MapFlowDirection(ItemsViewHandler handler, ItemsView itemsView) + { + } + public static void MapIsVisible(ItemsViewHandler handler, ItemsView itemsView) + { + handler.PlatformView.UpdateVisibility(itemsView); + } + public static void MapItemsUpdatingScrollMode(ItemsViewHandler handler, ItemsView itemsView) + { + } + } +} diff --git a/src/Controls/src/Core/Handlers/Items/ReorderableItemsViewHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Items/ReorderableItemsViewHandler.Tizen.cs new file mode 100644 index 0000000000..a1ae82bece --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/ReorderableItemsViewHandler.Tizen.cs @@ -0,0 +1,12 @@ +using System; + +namespace Microsoft.Maui.Controls.Handlers.Items +{ + public partial class ReorderableItemsViewHandler : GroupableItemsViewHandler where TItemsView : ReorderableItemsView + { + public static void MapCanReorderItems(ReorderableItemsViewHandler handler, ReorderableItemsView itemsView) + { + //TODO : Need to impl + } + } +} diff --git a/src/Controls/src/Core/Handlers/Items/SelectableItemsViewHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Items/SelectableItemsViewHandler.Tizen.cs new file mode 100644 index 0000000000..acd21c8465 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/SelectableItemsViewHandler.Tizen.cs @@ -0,0 +1,25 @@ +using Microsoft.Maui.Controls.Platform; + +namespace Microsoft.Maui.Controls.Handlers.Items +{ + public partial class SelectableItemsViewHandler : StructuredItemsViewHandler where TItemsView : SelectableItemsView + { + public static void MapSelectedItem(SelectableItemsViewHandler handler, SelectableItemsView itemsView) + { + if (itemsView.SelectionMode != SelectionMode.None && itemsView.SelectedItem != null) + { + var index = handler.PlatformView.Adaptor.GetItemIndex(itemsView.SelectedItem); + handler.PlatformView.SelectedItemIndex = index; + } + } + + public static void MapSelectedItems(SelectableItemsViewHandler handler, SelectableItemsView itemsView) + { + } + + public static void MapSelectionMode(SelectableItemsViewHandler handler, SelectableItemsView itemsView) + { + handler.PlatformView.SelectionMode = itemsView.SelectionMode.ToPlatform(); + } + } +} diff --git a/src/Controls/src/Core/Handlers/Items/StructuredItemsViewHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Items/StructuredItemsViewHandler.Tizen.cs new file mode 100644 index 0000000000..3e124d71e6 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/StructuredItemsViewHandler.Tizen.cs @@ -0,0 +1,27 @@ +using Microsoft.Maui.Controls.Platform; + +namespace Microsoft.Maui.Controls.Handlers.Items +{ + public partial class StructuredItemsViewHandler : ItemsViewHandler where TItemsView : StructuredItemsView + { + public static void MapHeaderTemplate(StructuredItemsViewHandler handler, StructuredItemsView itemsView) + { + handler.PlatformView.UpdateAdaptor(itemsView); + } + + public static void MapFooterTemplate(StructuredItemsViewHandler handler, StructuredItemsView itemsView) + { + handler.PlatformView.UpdateAdaptor(itemsView); + } + + public static void MapItemsLayout(StructuredItemsViewHandler handler, StructuredItemsView itemsView) + { + handler.PlatformView.UpdateItemsLayout(itemsView); + } + + public static void MapItemSizingStrategy(StructuredItemsViewHandler handler, StructuredItemsView itemsView) + { + handler.PlatformView.UpdateItemsLayout(itemsView); + } + } +} diff --git a/src/Controls/src/Core/Handlers/Items/Tizen/EmptyItemAdaptor.cs b/src/Controls/src/Core/Handlers/Items/Tizen/EmptyItemAdaptor.cs new file mode 100644 index 0000000000..ca3a4c9a67 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/Tizen/EmptyItemAdaptor.cs @@ -0,0 +1,105 @@ +#nullable enable + +using System; +using System.Collections; +using System.Collections.Generic; +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Controls.Handlers.Items +{ + public class EmptyItemAdaptor : ItemTemplateAdaptor, IEmptyAdaptor + { + static DataTemplate s_defaultEmptyTemplate = new DataTemplate(typeof(EmptyView)); + + IMauiContext _context; + + public EmptyItemAdaptor(ItemsView itemsView) : this(itemsView, itemsView.ItemsSource, itemsView.ItemTemplate) { } + + public EmptyItemAdaptor(ItemsView itemsView, IEnumerable items, DataTemplate template) : base(itemsView, items, template) + { + _context = itemsView.Handler!.MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + } + + public static EmptyItemAdaptor Create(ItemsView itemsView) + { + DataTemplate? template = null; + if (itemsView.EmptyView is View emptyView) + { + template = new DataTemplate(() => + { + return emptyView; + }); + } + else + { + template = itemsView.EmptyViewTemplate ?? s_defaultEmptyTemplate; + } + var empty = new List + { + itemsView.EmptyView ?? new object() + }; + return new EmptyItemAdaptor(itemsView, empty, template); + } + + public override Size MeasureItem(int widthConstraint, int heightConstraint) + { + return new Size(widthConstraint, heightConstraint); + } + + public override EvasObject CreateNativeView(int index, EvasObject parent) + { + View? emptyView = null; + if (ItemTemplate is DataTemplateSelector selector) + { + emptyView = selector.SelectTemplate(this[index], Element).CreateContent() as View; + } + else + { + emptyView = ItemTemplate.CreateContent() as View; + } + + var header = CreateHeaderView(); + var footer = CreateFooterView(); + var layout = new StackLayout(); + + if (header != null) + { + layout.Children.Add(header); + } + layout.Children.Add(emptyView); + if (footer != null) + { + layout.Children.Add(footer); + } + + layout.Parent = Element; + + return layout.ToPlatform(_context); + } + + public override void RemoveNativeView(EvasObject native) + { + native.Unrealize(); + } + + class EmptyView : StackLayout + { + public EmptyView() + { + HorizontalOptions = LayoutOptions.Fill; + VerticalOptions = LayoutOptions.Fill; + Children.Add( + new Label + { + Text = "No items found", + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + HorizontalTextAlignment = TextAlignment.Center, + VerticalTextAlignment = TextAlignment.Center, + } + ); + } + } + } +} diff --git a/src/Controls/src/Core/Handlers/Items/Tizen/ItemDefaultTemplateAdaptor.cs b/src/Controls/src/Core/Handlers/Items/Tizen/ItemDefaultTemplateAdaptor.cs new file mode 100644 index 0000000000..cc572273b3 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/Tizen/ItemDefaultTemplateAdaptor.cs @@ -0,0 +1,42 @@ +#nullable enable + +using System; +using System.Globalization; + +namespace Microsoft.Maui.Controls.Handlers.Items +{ + 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 Label + { + TextColor = Graphics.Colors.Black, + }; + label.SetBinding(Label.TextProperty, new Binding(".", converter: new ToTextConverter())); + + return new StackLayout + { + BackgroundColor = Graphics.Colors.White, + Padding = 30, + Children = + { + label + } + }; + }); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Handlers/Items/Tizen/ItemTemplateAdaptor.cs b/src/Controls/src/Core/Handlers/Items/Tizen/ItemTemplateAdaptor.cs new file mode 100644 index 0000000000..5265f15a53 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Items/Tizen/ItemTemplateAdaptor.cs @@ -0,0 +1,307 @@ +#nullable enable + +using System; +using System.Collections; +using System.Collections.Generic; +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; +using DPExtensions = Microsoft.Maui.Platform.DPExtensions; + +namespace Microsoft.Maui.Controls.Handlers.Items +{ + public class ItemTemplateAdaptor : ItemAdaptor + { + Dictionary _nativeTable = new Dictionary(); + Dictionary _dataBindedViewTable = new Dictionary(); + protected View? _headerCache; + protected View? _footerCache; + IMauiContext _context; + + public ItemTemplateAdaptor(ItemsView itemsView) : this(itemsView, itemsView.ItemsSource, itemsView.ItemTemplate) { } + + protected ItemTemplateAdaptor(ItemsView itemsView, IEnumerable items, DataTemplate template) : base(items) + { + ItemTemplate = template; + Element = itemsView; + IsSelectable = itemsView is SelectableItemsView; + _context = itemsView.Handler!.MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + } + + protected DataTemplate ItemTemplate { get; set; } + + protected Element Element { get; set; } + + protected virtual bool IsSelectable { get; } + + + public View GetTemplatedView(EvasObject evasObject) + { + return _nativeTable[evasObject]; + } + + public View? GetTemplatedView(int index) + { + var item = this[index]; + if (item != null && Count > index && _dataBindedViewTable.TryGetValue(item, out View? view)) + { + return view; + } + return null; + } + + public override object GetViewCategory(int index) + { + if (ItemTemplate is DataTemplateSelector selector) + { + return selector.SelectTemplate(this[index], Element); + } + return base.GetViewCategory(index); + } + + public override EvasObject? CreateNativeView(EvasObject parent) + { + return CreateNativeView(0, parent); + } + + public override EvasObject? CreateNativeView(int index, EvasObject parent) + { + View? view = null; + if (ItemTemplate is DataTemplateSelector selector) + { + view = selector.SelectTemplate(this[index], Element).CreateContent() as View; + } + else + { + view = ItemTemplate.CreateContent() as View; + } + + if (view != null) + { + var native = view.ToPlatform(_context); + view.Parent = Element; + _nativeTable[native] = view; + return native; + } + return null; + } + + public override EvasObject? GetFooterView(EvasObject parent) + { + _footerCache = CreateFooterView(); + if (_footerCache != null) + { + _footerCache.Parent = Element; + return _footerCache.ToPlatform(_context); + } + return null; + } + + public override EvasObject? GetHeaderView(EvasObject parent) + { + _headerCache = CreateHeaderView(); + if (_headerCache != null) + { + _headerCache.Parent = Element; + return _headerCache.ToPlatform(_context); + } + return null; + } + + public override Size MeasureFooter(int widthConstraint, int heightConstraint) + { + return _footerCache?.Measure(DPExtensions.ConvertToScaledDP(widthConstraint), DPExtensions.ConvertToScaledDP(heightConstraint)).Request.ToEFLPixel() ?? new Size(0, 0); + } + + public override Size MeasureHeader(int widthConstraint, int heightConstraint) + { + return _headerCache?.Measure(DPExtensions.ConvertToScaledDP(widthConstraint), DPExtensions.ConvertToScaledDP(heightConstraint)).Request.ToEFLPixel() ?? new Size(0, 0); + } + + public override Size MeasureItem(int widthConstraint, int heightConstraint) + { + return MeasureItem(0, widthConstraint, heightConstraint); + } + + public override Size MeasureItem(int index, int widthConstraint, int heightConstraint) + { + if (widthConstraint > heightConstraint) + { + widthConstraint = int.MaxValue; + } + if (heightConstraint > widthConstraint) + { + heightConstraint = int.MaxValue; + } + + var item = this[index]; + if (item != null && _dataBindedViewTable.TryGetValue(item, out View? createdView) && createdView != null) + { + return createdView.Measure(DPExtensions.ConvertToScaledDP(widthConstraint), DPExtensions.ConvertToScaledDP(heightConstraint), MeasureFlags.IncludeMargins).Request.ToEFLPixel(); + } + + View? view = null; + if (ItemTemplate is DataTemplateSelector selector) + { + view = selector.SelectTemplate(this[index], Element).CreateContent() as View; + } + else + { + view = ItemTemplate.CreateContent() as View; + } + + if (view != null) + { + view.Parent = Element; + if (Count > index) + view.BindingContext = this[index]; + var request = view.Measure(DPExtensions.ConvertToScaledDP(widthConstraint), DPExtensions.ConvertToScaledDP(heightConstraint), MeasureFlags.IncludeMargins).Request; + return request.ToEFLPixel(); + } + return new Size(0, 0); + } + + public override void RemoveNativeView(EvasObject native) + { + UnBinding(native); + if (_nativeTable.TryGetValue(native, out View? view)) + { + native.Unrealize(); + _nativeTable.Remove(native); + } + } + + public override void SetBinding(EvasObject native, int index) + { + if (_nativeTable.TryGetValue(native, out View? view)) + { + ResetBindedView(view); + var item = this[index]; + if (item != null) + { + view.BindingContext = item; + _dataBindedViewTable[item] = view; + } + view.MeasureInvalidated += OnItemMeasureInvalidated; + AddLogicalChild(view); + } + } + + public override void UnBinding(EvasObject native) + { + if (_nativeTable.TryGetValue(native, out View? view)) + { + view.MeasureInvalidated -= OnItemMeasureInvalidated; + ResetBindedView(view); + } + } + + public void SendItemSelected(object selectedItem) + { + if (Element is SelectableItemsView selectable) + { + selectable.SelectedItem = selectedItem; + } + } + + protected virtual View? CreateHeaderView() + { + if (Element is StructuredItemsView structuredItemsView) + { + if (structuredItemsView.Header != null) + { + View? header = null; + if (structuredItemsView.Header is View view) + { + header = view; + } + else if (structuredItemsView.HeaderTemplate != null) + { + header = structuredItemsView.HeaderTemplate.CreateContent() as View; + if (header != null) + header.BindingContext = structuredItemsView.Header; + } + else if (structuredItemsView.Header is String str) + { + header = new Label { Text = str, }; + } + return header; + } + } + return null; + } + + protected virtual View? CreateFooterView() + { + if (Element is StructuredItemsView structuredItemsView) + { + if (structuredItemsView.Footer != null) + { + View? footer = null; + if (structuredItemsView.Footer is View view) + { + footer = view; + } + else if (structuredItemsView.FooterTemplate != null) + { + footer = structuredItemsView.FooterTemplate.CreateContent() as View; + if (footer != null) + footer.BindingContext = structuredItemsView.Footer; + } + else if (structuredItemsView.Footer is String str) + { + footer = new Label { Text = str, }; + } + return footer; + } + } + return null; + } + + void ResetBindedView(View view) + { + if (view.BindingContext != null && _dataBindedViewTable.ContainsKey(view.BindingContext)) + { + _dataBindedViewTable[view.BindingContext] = null; + RemoveLogicalChild(view); + view.BindingContext = null; + } + } + + void OnItemMeasureInvalidated(object? sender, EventArgs e) + { + var data = (sender as View)?.BindingContext ?? null; + if (data != null) + { + int index = GetItemIndex(data); + if (index != -1) + { + CollectionView?.ItemMeasureInvalidated(index); + } + } + } + + void AddLogicalChild(Element element) + { + if (Element is ItemsView iv) + { + iv.AddLogicalChild(element); + } + else + { + element.Parent = Element; + } + } + + void RemoveLogicalChild(Element element) + { + if (Element is ItemsView iv) + { + iv.RemoveLogicalChild(element); + } + else + { + element.Parent = null; + } + } + } +} diff --git a/src/Controls/src/Core/Handlers/Shapes/Line/LineHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Shapes/Line/LineHandler.Tizen.cs new file mode 100644 index 0000000000..1494179e4b --- /dev/null +++ b/src/Controls/src/Core/Handlers/Shapes/Line/LineHandler.Tizen.cs @@ -0,0 +1,27 @@ +using Microsoft.Maui.Controls.Shapes; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class LineHandler + { + public static void MapX1(IShapeViewHandler handler, Line line) + { + handler.PlatformView?.InvalidateShape(line); + } + + public static void MapY1(IShapeViewHandler handler, Line line) + { + handler.PlatformView?.InvalidateShape(line); + } + + public static void MapX2(IShapeViewHandler handler, Line line) + { + handler.PlatformView?.InvalidateShape(line); + } + + public static void MapY2(IShapeViewHandler handler, Line line) + { + handler.PlatformView?.InvalidateShape(line); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Handlers/Shapes/Path/PathHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Shapes/Path/PathHandler.Tizen.cs new file mode 100644 index 0000000000..f4ef45d6d5 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Shapes/Path/PathHandler.Tizen.cs @@ -0,0 +1,17 @@ +using Microsoft.Maui.Controls.Shapes; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class PathHandler + { + public static void MapData(IShapeViewHandler handler, Path path) + { + handler.PlatformView?.InvalidateShape(path); + } + + public static void MapRenderTransform(IShapeViewHandler handler, Path path) + { + handler.PlatformView?.InvalidateShape(path); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Handlers/Shapes/Polygon/PolygonHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Shapes/Polygon/PolygonHandler.Tizen.cs new file mode 100644 index 0000000000..51635c23a1 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Shapes/Polygon/PolygonHandler.Tizen.cs @@ -0,0 +1,52 @@ +using Microsoft.Maui.Controls.Shapes; +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class PolygonHandler + { + protected override void ConnectHandler(MauiShapeView nativeView) + { + if (VirtualView is Polygon polygon) + polygon.Points.CollectionChanged += OnPointsCollectionChanged; + + base.ConnectHandler(nativeView); + } + + protected override void DisconnectHandler(MauiShapeView nativeView) + { + if (VirtualView is Polygon polygon) + polygon.Points.CollectionChanged -= OnPointsCollectionChanged; + + base.DisconnectHandler(nativeView); + } + + public static void MapShape(IShapeViewHandler handler, Polygon polygon) + { + handler.PlatformView?.UpdateShape(polygon); + } + + public static void MapPoints(IShapeViewHandler handler, Polygon polygon) + { + handler.PlatformView?.InvalidateShape(polygon); + } + + public static void MapFillRule(IShapeViewHandler 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); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Handlers/Shapes/Polyline/PolylineHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Shapes/Polyline/PolylineHandler.Tizen.cs new file mode 100644 index 0000000000..69fa54c1a0 --- /dev/null +++ b/src/Controls/src/Core/Handlers/Shapes/Polyline/PolylineHandler.Tizen.cs @@ -0,0 +1,52 @@ +using Microsoft.Maui.Controls.Shapes; +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class PolylineHandler + { + protected override void ConnectHandler(MauiShapeView nativeView) + { + if (VirtualView is Polyline polyline) + polyline.Points.CollectionChanged += OnPointsCollectionChanged; + + base.ConnectHandler(nativeView); + } + + protected override void DisconnectHandler(MauiShapeView nativeView) + { + if (VirtualView is Polyline polyline) + polyline.Points.CollectionChanged -= OnPointsCollectionChanged; + + base.DisconnectHandler(nativeView); + } + + public static void MapShape(IShapeViewHandler handler, Polyline polyline) + { + handler.PlatformView?.UpdateShape(polyline); + } + + public static void MapPoints(IShapeViewHandler handler, Polyline polyline) + { + handler.PlatformView?.InvalidateShape(polyline); + } + + public static void MapFillRule(IShapeViewHandler 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); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Handlers/Shapes/Rectangle/RectangleHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Shapes/Rectangle/RectangleHandler.Tizen.cs new file mode 100644 index 0000000000..ced3c8e08a --- /dev/null +++ b/src/Controls/src/Core/Handlers/Shapes/Rectangle/RectangleHandler.Tizen.cs @@ -0,0 +1,17 @@ +using Microsoft.Maui.Controls.Shapes; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class RectangleHandler + { + public static void MapRadiusX(IShapeViewHandler handler, Rectangle rectangle) + { + handler.PlatformView?.InvalidateShape(rectangle); + } + + public static void MapRadiusY(IShapeViewHandler handler, Rectangle rectangle) + { + handler.PlatformView?.InvalidateShape(rectangle); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Handlers/Shapes/RoundRectangle/RoundRectangleHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Shapes/RoundRectangle/RoundRectangleHandler.Tizen.cs new file mode 100644 index 0000000000..56c443511c --- /dev/null +++ b/src/Controls/src/Core/Handlers/Shapes/RoundRectangle/RoundRectangleHandler.Tizen.cs @@ -0,0 +1,12 @@ +using Microsoft.Maui.Controls.Shapes; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class RoundRectangleHandler + { + public static void MapCornerRadius(IShapeViewHandler handler, RoundRectangle roundRectangle) + { + handler.PlatformView?.InvalidateShape(roundRectangle); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Handlers/Shell/ShellHandler.Tizen.cs b/src/Controls/src/Core/Handlers/Shell/ShellHandler.Tizen.cs new file mode 100644 index 0000000000..de1e02121a --- /dev/null +++ b/src/Controls/src/Core/Handlers/Shell/ShellHandler.Tizen.cs @@ -0,0 +1,37 @@ +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Handlers; +using Tizen.UIExtensions.Common; + +namespace Microsoft.Maui.Controls.Handlers +{ + public partial class ShellHandler : ViewHandler + { + public static PropertyMapper Mapper = + new PropertyMapper(ElementMapper); + + public static CommandMapper CommandMapper = + new CommandMapper(ElementCommandMapper); + + public ShellHandler() : base(Mapper, CommandMapper) + { + } + + public override void SetVirtualView(IView view) + { + base.SetVirtualView(view); + PlatformView?.SetElement((Shell)view, MauiContext); + } + + protected override ShellView CreatePlatformView() + { + if (DeviceInfo.GetDeviceType() == DeviceType.TV) + { + return new TVShellView(NativeParent); + } + else + { + return new ShellView(NativeParent); + } + } + } +} diff --git a/src/Controls/src/Core/Interactivity/PlatformBehavior.cs b/src/Controls/src/Core/Interactivity/PlatformBehavior.cs index eb3f46f7c8..e7ae465102 100644 --- a/src/Controls/src/Core/Interactivity/PlatformBehavior.cs +++ b/src/Controls/src/Core/Interactivity/PlatformBehavior.cs @@ -8,6 +8,8 @@ using PlatformView = AppKit.NSView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; #elif NET6_0 || NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/Controls/src/Core/Platform/AlertManager/AlertManager.Tizen.cs b/src/Controls/src/Core/Platform/AlertManager/AlertManager.Tizen.cs new file mode 100644 index 0000000000..0862df7d90 --- /dev/null +++ b/src/Controls/src/Core/Platform/AlertManager/AlertManager.Tizen.cs @@ -0,0 +1,331 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ElmSharp; +using Microsoft.Maui.Controls.Internals; +using Tizen.UIExtensions.ElmSharp; +using EBox = ElmSharp.Box; +using EButton = ElmSharp.Button; +using EColor = ElmSharp.Color; +using EProgressBar = ElmSharp.ProgressBar; +using EWindow = ElmSharp.Window; +using GColor = Microsoft.Maui.Graphics.Color; +using TButton = Tizen.UIExtensions.ElmSharp.Button; +using TColor = Tizen.UIExtensions.Common.Color; + +namespace Microsoft.Maui.Controls.Platform +{ + internal partial class AlertManager + { + readonly List Subscriptions = new List(); + + internal void Subscribe(Window window) + { + IMauiContext mauiContext = window?.MauiContext; + EWindow nativeWindow = mauiContext.GetNativeWindow(); + + if (mauiContext == null || nativeWindow == null) + return; + + if (Subscriptions.Any(s => s.Window == nativeWindow)) + { + return; + } + + Subscriptions.Add(new AlertRequestHelper(nativeWindow, mauiContext)); + } + + internal void Unsubscribe(Window window) + { + IMauiContext mauiContext = window?.MauiContext; + EWindow nativeWindow = mauiContext.GetNativeWindow(); + + var toRemove = Subscriptions.Where(s => s.Window == nativeWindow).ToList(); + + foreach (AlertRequestHelper alertRequestHelper in toRemove) + { + alertRequestHelper.Dispose(); + Subscriptions.Remove(alertRequestHelper); + } + } + } + + internal sealed class AlertRequestHelper : IDisposable + { + int _busyCount; + Dialog _pageBusyDialog; + readonly HashSet _alerts = new HashSet(); + + internal AlertRequestHelper(EWindow window, IMauiContext mauiContext) + { + Window = window; + MauiContext = mauiContext; + + MessagingCenter.Subscribe(Window, Page.BusySetSignalName, OnBusySetRequest); + MessagingCenter.Subscribe(Window, Page.AlertSignalName, OnAlertRequest); + MessagingCenter.Subscribe(Window, Page.ActionSheetSignalName, OnActionSheetRequest); + MessagingCenter.Subscribe(Window, Page.PromptSignalName, OnPromptRequested); + } + + public EWindow Window { get; } + public IMauiContext MauiContext { get; } + + public void Dispose() + { + MessagingCenter.Unsubscribe(Window, Page.AlertSignalName); + MessagingCenter.Unsubscribe(Window, Page.BusySetSignalName); + MessagingCenter.Unsubscribe(Window, Page.ActionSheetSignalName); + MessagingCenter.Unsubscribe(Window, Page.PromptSignalName); + } + + void OnBusySetRequest(Page sender, bool enabled) + { + // Verify that the page making the request is child of this platform + if (!PageIsInThisContext(sender)) + { + return; + } + _busyCount = Math.Max(0, enabled ? _busyCount + 1 : _busyCount - 1); + + if (null == _pageBusyDialog) + { + _pageBusyDialog = new Dialog(MauiContext.GetNativeParent()) + { + Orientation = PopupOrientation.Center, + BackgroundColor = EColor.Transparent + }; + + _pageBusyDialog.SetTitleBackgroundColor(EColor.Transparent); + _pageBusyDialog.SetContentBackgroundColor(EColor.Transparent); + + var activity = new EProgressBar(_pageBusyDialog) { IsPulseMode = true }.SetLargeStyle(); + activity.PlayPulse(); + activity.Show(); + + _pageBusyDialog.Content = activity; + } + + if (_busyCount > 0) + { + _pageBusyDialog.Show(); + } + else + { + _pageBusyDialog.Dismiss(); + _pageBusyDialog.Unrealize(); + _pageBusyDialog = null; + } + } + + void OnAlertRequest(Page sender, AlertArguments arguments) + { + // Verify that the page making the request is child of this platform + if (!PageIsInThisContext(sender)) + return; + + var alert = Dialog.CreateDialog(MauiContext.GetNativeParent(), (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); + } + + void OnActionSheetRequest(Page sender, ActionSheetArguments arguments) + { + // Verify that the page making the request is child of this platform + if (!PageIsInThisContext(sender)) + return; + + var alert = Dialog.CreateDialog(MauiContext.GetNativeParent()); + + alert.Title = arguments.Title; + var box = new EBox(alert); + + if (null != arguments.Destruction) + { + var destruction = new TButton(alert) + { + Text = arguments.Destruction, + AlignmentX = -1 + }; + //TextColor should be set after applying style + destruction.TextColor = TColor.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 TButton(alert) + { + Text = buttonName, + AlignmentX = -1 + }; + + 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 TButton(alert) { 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); + } + + void OnPromptRequested(Page sender, PromptArguments args) + { + // Verify that the page making the request is child of this platform + if (!PageIsInThisContext(sender)) + return; + + var prompt = Dialog.CreateDialog(MauiContext.GetNativeParent(), (args.Accept != null)); + prompt.Title = args.Title; + + var entry = new Entry + { + MinimumWidthRequest = 200, + HorizontalOptions = LayoutOptions.Fill, + BackgroundColor = GColor.FromRgb(250, 250, 250), + TextColor = GColor.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 VerticalStackLayout + { + Spacing = 10, + }; + layout.Add(new Label + { + LineBreakMode = LineBreakMode.CharacterWrap, + TextColor = 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 + }); + layout.Add(entry); + layout.Parent = sender; + var nativeView = layout.ToPlatform(MauiContext); + + var width = sender.Width <= -1 ? double.PositiveInfinity : sender.Width; + var height = sender.Height <= -1 ? double.PositiveInfinity : sender.Height; + var request = layout.CrossPlatformMeasure(width, height); + + nativeView.MinimumHeight = request.Height.ToScaledPixel(); + nativeView.MinimumWidth = request.Width.ToScaledPixel(); + + prompt.Content = 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); + } + + bool PageIsInThisContext(IView sender) + { + var context = sender.Handler?.MauiContext ?? null; + return context?.GetNativeWindow() == Window; + } + } +} diff --git a/src/Controls/src/Core/Platform/GestureManager/GestureManager.Tizen.cs b/src/Controls/src/Core/Platform/GestureManager/GestureManager.Tizen.cs new file mode 100644 index 0000000000..f231e5a477 --- /dev/null +++ b/src/Controls/src/Core/Platform/GestureManager/GestureManager.Tizen.cs @@ -0,0 +1,137 @@ +#nullable enable + +using System; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Linq; + +namespace Microsoft.Maui.Controls.Platform +{ + class GestureManager : IDisposable + { + IViewHandler? _handler; + GestureDetector? _gestureDetector; + bool _disposed = false; + + protected virtual VisualElement? Element => _handler?.VirtualView as VisualElement; + + public GestureManager(IViewHandler handler) + { + _handler = handler; + _gestureDetector = null; + SetupElement(null, Element); + } + + void SetupElement(VisualElement? oldElement, VisualElement? newElement) + { + if (oldElement != null) + { + if (oldElement is View ov && + ov.GestureRecognizers is INotifyCollectionChanged incc) + { + incc.CollectionChanged -= OnGestureRecognizerCollectionChanged; + _gestureDetector?.Clear(); + } + oldElement.PropertyChanged -= OnElementPropertyChanged; + } + + if (newElement != null) + { + if (newElement is View ov && + ov.GestureRecognizers is INotifyCollectionChanged incc) + { + incc.CollectionChanged += OnGestureRecognizerCollectionChanged; + if (ov.GestureRecognizers.Count > 0) + { + _gestureDetector = new GestureDetector(_handler); + _gestureDetector.AddGestures(ov.GestureRecognizers); + } + } + newElement.PropertyChanged += OnElementPropertyChanged; + } + + UpdateInputTransparent(); + UpdateIsEnabled(); + } + + void OnElementPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName) + UpdateInputTransparent(); + else if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName) + UpdateIsEnabled(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + _disposed = true; + + if (disposing) + { + SetupElement(Element, null); + if (_gestureDetector != null) + { + _gestureDetector.Dispose(); + _gestureDetector = null; + } + _handler = null; + } + } + + void UpdateInputTransparent() + { + if (Element != null && _gestureDetector != null) + { + _gestureDetector.InputTransparent = Element.InputTransparent; + } + } + + void UpdateIsEnabled() + { + if (Element != null && _gestureDetector != null) + { + _gestureDetector.IsEnabled = Element.IsEnabled; + } + } + + void OnGestureRecognizerCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + if (_gestureDetector == null) + { + _gestureDetector = new GestureDetector(_handler); + } + + // Gestures will be registered/unregistered according to changes in the GestureRecognizers list + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + _gestureDetector.AddGestures(e.NewItems?.OfType()); + break; + + case NotifyCollectionChangedAction.Replace: + _gestureDetector.RemoveGestures(e.OldItems?.OfType()); + _gestureDetector.AddGestures(e.NewItems?.OfType()); + break; + + case NotifyCollectionChangedAction.Remove: + _gestureDetector.RemoveGestures(e.OldItems?.OfType()); + break; + + case NotifyCollectionChangedAction.Reset: + _gestureDetector.Clear(); + break; + } + } + } +} diff --git a/src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.Tizen.cs b/src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.Tizen.cs new file mode 100644 index 0000000000..1f9c89a024 --- /dev/null +++ b/src/Controls/src/Core/Platform/ModalNavigationManager/ModalNavigationManager.Tizen.cs @@ -0,0 +1,59 @@ +#nullable enable + +using System.Threading.Tasks; +using Microsoft.Maui; + +namespace Microsoft.Maui.Controls.Platform +{ + internal partial class ModalNavigationManager + { + ModalStack _modalStack => MauiContext.GetModalStack(); + IPageController CurrentPageController => _navModel.CurrentPage; + + partial void OnPageAttachedHandler() + { + MauiContext.GetNativeWindow().SetBackButtonPressedHandler(OnBackButtonPressed); + } + + public Task PopModalAsync(bool animated) + { + Page modal = _navModel.PopModal(); + ((IPageController)modal).SendDisappearing(); + var source = new TaskCompletionSource(); + + var modalRenderer = modal.Handler as IPlatformViewHandler; + 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.ToPlatform(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/Controls/src/Core/Platform/PlatformConfigurationExtensions.cs b/src/Controls/src/Core/Platform/PlatformConfigurationExtensions.cs index eec66985e2..f09c4341dd 100644 --- a/src/Controls/src/Core/Platform/PlatformConfigurationExtensions.cs +++ b/src/Controls/src/Core/Platform/PlatformConfigurationExtensions.cs @@ -4,6 +4,8 @@ using CurrentPlatform = Microsoft.Maui.Controls.PlatformConfiguration.iOS; using CurrentPlatform = Microsoft.Maui.Controls.PlatformConfiguration.Android; #elif WINDOWS using CurrentPlatform = Microsoft.Maui.Controls.PlatformConfiguration.Windows; +#elif TIZEN +using CurrentPlatform = Microsoft.Maui.Controls.PlatformConfiguration.Tizen; #elif NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/Controls/src/Core/Platform/PlatformEffect.cs b/src/Controls/src/Core/Platform/PlatformEffect.cs index 7d00c80daa..ca81a67794 100644 --- a/src/Controls/src/Core/Platform/PlatformEffect.cs +++ b/src/Controls/src/Core/Platform/PlatformEffect.cs @@ -5,6 +5,8 @@ using PlatformView = UIKit.UIView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; #elif NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/Controls/src/Core/Platform/Tizen/DragGestureHandler.cs b/src/Controls/src/Core/Platform/Tizen/DragGestureHandler.cs new file mode 100644 index 0000000000..50fef189fe --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/DragGestureHandler.cs @@ -0,0 +1,243 @@ +using System; +using System.Threading.Tasks; +using ElmSharp; +using Microsoft.Maui.Controls.Internals; +using Tizen.UIExtensions.ElmSharp; +using EGestureType = ElmSharp.GestureLayer.GestureType; +using TImage = Tizen.UIExtensions.ElmSharp.Image; +using TLabel = Tizen.UIExtensions.ElmSharp.Label; + +namespace Microsoft.Maui.Controls.Platform +{ + public class DragGestureHandler : GestureHandler + { + DragDropExtensions.Interop.DragIconCreateCallback _iconCallback; + DragDropExtensions.Interop.DragStateCallback _dragDoneCallback; + + static bool s_isDragging; + static CustomDragStateData s_currentDragStateData; + + protected virtual IView Element => Handler?.VirtualView as IView; + + public DragGestureHandler(IGestureRecognizer recognizer, IViewHandler handler) : base(recognizer) + { + _iconCallback = OnIconCallback; + _dragDoneCallback = OnDragDoneCallback; + Handler = handler; + } + + public override EGestureType Type => EGestureType.LongTap; + + public IViewHandler Handler { get; } + + public static CustomDragStateData CurrentStateData + { + get + { + return s_currentDragStateData; + } + } + + EvasObject PlatformView + { + get + { + return Handler.PlatformView as EvasObject; + } + } + + 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 (Handler == null) + return; + + var arg = dragGestureRecognizer.SendDragStarting(Element); + + 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(PlatformView, + 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(PlatformView, window); + + if (s_currentDragStateData.DataPackage.Image != null) + { + icon = GetImageIconAsync(parent).Result; + } + else if (PlatformView is ShapeView) + { + icon = GetShapeView(parent); + } + else + { + icon = GetDefaultIcon(parent); + } + var bound = PlatformView.Geometry; + bound.X = 0; + bound.Y = 0; + icon.Geometry = bound; + + if (icon is TLabel) + { + 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 TLabel(parent); + label.Text = s_currentDragStateData.DataPackage.Text; + + if (Element is IFontElement fe) + label.FontSize = fe.FontSize; + + return label; + } + else + { + var box = new ElmSharp.Rectangle(parent); + box.Color = new ElmSharp.Color(128, 128, 128, 128); + return box; + } + } + + async Task GetImageIconAsync(EvasObject parent) + { + var image = new TImage(parent); + var mImage = s_currentDragStateData.DataPackage.Image; + var services = Handler.MauiContext?.Services; + var provider = services.GetService(typeof(IImageSourceServiceProvider)) as IImageSourceServiceProvider; + var service = provider?.GetImageSourceService(mImage); + var result = await service.GetImageAsync(mImage, image); + if (result == null) + return null; + return image; + } + + EvasObject GetShapeView(EvasObject parent) + { + var copiedImg = new EvasImage(parent) + { + IsFilled = true + }; + + if (PlatformView 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; + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/DropGestureHandler.cs b/src/Controls/src/Core/Platform/Tizen/DropGestureHandler.cs new file mode 100644 index 0000000000..a25c4ec482 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/DropGestureHandler.cs @@ -0,0 +1,126 @@ +using System; +using System.Linq; +using ElmSharp; +using Tizen.Common; +using Tizen.UIExtensions.ElmSharp; +using EGestureType = ElmSharp.GestureLayer.GestureType; + +namespace Microsoft.Maui.Controls.Platform +{ + public class DropGestureHandler : GestureHandler + { + DragDropExtensions.Interop.DragStateCallback _dragEnterCallback; + DragDropExtensions.Interop.DragStateCallback _dragLeaveCallback; + DragDropExtensions.Interop.DropCallback _dropCallback; + + public override EGestureType Type => default(EGestureType); + + public DropGestureHandler(IGestureRecognizer recognizer, IViewHandler handler) : base(recognizer) + { + _dragEnterCallback = OnEnterCallback; + _dragLeaveCallback = OnLeaveCallback; + _dropCallback = OnDropCallback; + Handler = handler; + } + + public IViewHandler Handler { get; } + + EvasObject PlatformView + { + get + { + var native = Handler.PlatformView as EvasObject; + if (native is Canvas canvas) + { + var child = canvas.Children.LastOrDefault(); + + if (child != null) + { + if (child.PassEvents) + child.PassEvents = false; + + return child; + } + } + return native; + } + } + + + public void AddDropGesture() + { + if (Handler == null) + return; + + var target = DragDropExtensions.DragDropContentType.Targets; + + DragDropExtensions.AddDropTarget(PlatformView, + 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 + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Extensions/ButtonExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/ButtonExtensions.cs new file mode 100644 index 0000000000..60448c71b3 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/ButtonExtensions.cs @@ -0,0 +1,13 @@ +using static Microsoft.Maui.Controls.Button; +using EButton = ElmSharp.Button; + +namespace Microsoft.Maui.Controls.Platform +{ + public static class ButtonExtensions + { + public static void UpdateContentLayout(this EButton platformButton, Button button) + { + //TODO : Need to impl + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Platform/Tizen/Extensions/CollectionViewExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/CollectionViewExtensions.cs new file mode 100644 index 0000000000..0740026247 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/CollectionViewExtensions.cs @@ -0,0 +1,129 @@ +using System.Collections.Specialized; +using System.Linq; +using Microsoft.Maui.Controls.Handlers.Items; +using Tizen.UIExtensions.ElmSharp; +using TCollectionView = Tizen.UIExtensions.ElmSharp.CollectionView; +using TCollectionViewSelectionMode = Tizen.UIExtensions.ElmSharp.CollectionViewSelectionMode; +using TItemSizingStrategy = Tizen.UIExtensions.ElmSharp.ItemSizingStrategy; +using TSelectedItemChangedEventArgs = Tizen.UIExtensions.ElmSharp.SelectedItemChangedEventArgs; +using TSnapPointsType = Tizen.UIExtensions.ElmSharp.SnapPointsType; +using DPExtensions = Tizen.UIExtensions.ElmSharp.DPExtensions; + +namespace Microsoft.Maui.Controls.Platform +{ + public static class CollectionViewExtensions + { + static INotifyCollectionChanged _observableSource; + + public static void UpdateItemsSource(this TCollectionView platformView, ItemsView view) + { + if (view.ItemsSource is INotifyCollectionChanged collectionChanged) + { + if (_observableSource != null) + { + _observableSource.CollectionChanged -= OnCollectionChanged; + } + _observableSource = collectionChanged; + _observableSource.CollectionChanged += OnCollectionChanged; + } + UpdateAdaptor(platformView, view); + + void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (view.ItemsSource == null || !view.ItemsSource.Cast().Any()) + { + platformView.Adaptor = EmptyItemAdaptor.Create(view); + } + else + { + if (platformView.Adaptor is EmptyItemAdaptor) + { + platformView.UpdateAdaptor(view); + } + } + } + } + + public static void UpdateItemsLayout(this TCollectionView platformView, StructuredItemsView view) + { + if (view.ItemsLayout != null) + { + var itemSizingStrategy = view.ItemSizingStrategy.ToPlatform(); + if (view.ItemsLayout is GridItemsLayout grid) + { + var orientation = grid.Orientation == ItemsLayoutOrientation.Horizontal; + var verticalItemSpacing = DPExtensions.ConvertToScaledPixel(grid.VerticalItemSpacing); + var horizontalItemSpacing = DPExtensions.ConvertToScaledPixel(grid.HorizontalItemSpacing); + platformView.LayoutManager = new GridLayoutManager(orientation, grid.Span, itemSizingStrategy, verticalItemSpacing, horizontalItemSpacing); + } + else if (view.ItemsLayout is LinearItemsLayout linear) + { + var orientation = linear.Orientation == ItemsLayoutOrientation.Horizontal; + var itemSpacing = DPExtensions.ConvertToScaledPixel(linear.ItemSpacing); + platformView.LayoutManager = new LinearLayoutManager(orientation, itemSizingStrategy, itemSpacing); + } + else + { + platformView.LayoutManager = new LinearLayoutManager(false); + } + platformView.SnapPointsType = (view.ItemsLayout as ItemsLayout).SnapPointsType.ToPlatform(); + platformView.SelectionMode = (view as SelectableItemsView).SelectionMode.ToPlatform(); + } + } + + public static void UpdateAdaptor(this TCollectionView platformView, ItemsView view) + { + if (view.ItemsSource == null || !view.ItemsSource.Cast().Any()) + { + platformView.Adaptor = EmptyItemAdaptor.Create(view); + } + else if (view.ItemTemplate == null) + { + platformView.Adaptor = new ItemDefaultTemplateAdaptor(view); + } + else + { + platformView.Adaptor = new ItemTemplateAdaptor(view); + } + platformView.Adaptor.ItemSelected += OnItemSelected; + } + + static void OnItemSelected(object sender, TSelectedItemChangedEventArgs e) + { + (sender as ItemTemplateAdaptor)?.SendItemSelected(e.SelectedItem); + } + + public static TItemSizingStrategy ToPlatform(this ItemSizingStrategy itemSizingStrategy) + { + if (itemSizingStrategy == ItemSizingStrategy.MeasureAllItems) + return TItemSizingStrategy.MeasureAllItems; + return TItemSizingStrategy.MeasureFirstItem; + } + + public static TSnapPointsType ToPlatform(this SnapPointsType snapPointsType) + { + switch (snapPointsType) + { + case SnapPointsType.Mandatory: + return TSnapPointsType.Mandatory; + case SnapPointsType.MandatorySingle: + return TSnapPointsType.MandatorySingle; + default: + return TSnapPointsType.None; + } + } + + public static TCollectionViewSelectionMode ToPlatform(this SelectionMode selectionMode) + { + switch (selectionMode) + { + case SelectionMode.Multiple: + return TCollectionViewSelectionMode.Multiple; + case SelectionMode.Single: + return TCollectionViewSelectionMode.Single; + default: + return TCollectionViewSelectionMode.None; + } + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Extensions/DragDropExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/DragDropExtensions.cs new file mode 100644 index 0000000000..1d3f8108f1 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/DragDropExtensions.cs @@ -0,0 +1,114 @@ +using System; +using System.Runtime.InteropServices; +using ElmSharp; + +namespace Microsoft.Maui.Controls.Platform +{ + 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/Controls/src/Core/Platform/Tizen/Extensions/FontExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/FontExtensions.cs new file mode 100644 index 0000000000..bb363a06d7 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/FontExtensions.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Maui.Controls.Platform +{ + public static class FontExtensions + { + public static string ToNativeFontFamily(this string self, IFontManager fontManager) + { + return fontManager.GetFontFamily(self); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Extensions/SearchBarExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/SearchBarExtensions.cs new file mode 100644 index 0000000000..8238de824c --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/SearchBarExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.Maui.Controls; +using TFontAttributes = Tizen.UIExtensions.Common.FontAttributes; + +namespace Microsoft.Maui.Controls.Platform +{ + public static class SearchBarExtensions + { + + public static TFontAttributes ToPlatform(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/Extensions/ShellExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/ShellExtensions.cs new file mode 100644 index 0000000000..fc30d0f8f2 --- /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 ToPlatform(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/Extensions/TextExtensions.cs b/src/Controls/src/Core/Platform/Tizen/Extensions/TextExtensions.cs new file mode 100644 index 0000000000..8dada6bad8 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Extensions/TextExtensions.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Maui.Platform; +using Microsoft.Maui.Controls.Internals; +using TEntry = Tizen.UIExtensions.ElmSharp.Entry; +using TLabel = Tizen.UIExtensions.ElmSharp.Label; + +namespace Microsoft.Maui.Controls.Platform +{ + public static class TextExtensions + { + public static void UpdateText(this TEntry entry, InputView inputView) + { + entry.Text = TextTransformUtilites.GetTransformedText(entry.Text, inputView.TextTransform); + } + + public static void UpdateLineBreakMode(this TLabel platformLabel, Label label) + { + platformLabel.LineBreakMode = label.LineBreakMode.ToPlatform(); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/GestureDetector.cs b/src/Controls/src/Core/Platform/Tizen/GestureDetector.cs new file mode 100644 index 0000000000..6576dce5f6 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/GestureDetector.cs @@ -0,0 +1,637 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using ElmSharp; +using Microsoft.Maui.Devices; +using Microsoft.Maui.Controls.Internals; +using EGestureType = ElmSharp.GestureLayer.GestureType; + +namespace Microsoft.Maui.Controls.Platform +{ + class GestureDetector : IDisposable + { + readonly IDictionary> _handlerCache; + + IViewHandler? _handler; + GestureLayer? _gestureLayer; + double _doubleTapTime = 0; + double _longTapTime = 0; + bool _inputTransparent = false; + bool _isEnabled; + + protected virtual VisualElement? Element => _handler?.VirtualView as VisualElement; + + View? View => Element as View; + + protected virtual EvasObject? Control => _handler?.PlatformView as EvasObject; + + public bool IsEnabled + { + get + { + return _isEnabled; + } + set + { + _isEnabled = value; + UpdateGestureLayerEnabled(); + } + } + + public bool InputTransparent + { + get + { + return _inputTransparent; + } + set + { + _inputTransparent = value; + UpdateGestureLayerEnabled(); + } + } + + public GestureDetector(IViewHandler? handler) + { + _handlerCache = new Dictionary>(); + _handler = handler; + _isEnabled = View?.IsEnabled ?? false; + _inputTransparent = View?.InputTransparent ?? false; + } + + public void Dispose() + { + Clear(); + _handler = null; + } + + 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) + { + if (Control != null) + Control.KeyDown -= OnKeyDown; + } + } + + public void AddGestures(IEnumerable? recognizers) + { + if (_gestureLayer == null) + { + CreateGestureLayer(); + } + if (recognizers == null) + return; + foreach (var item in recognizers) + { + AddGesture(item); + } + } + + public void RemoveGestures(IEnumerable? recognizers) + { + if (recognizers == null) + return; + foreach (var item in recognizers) + RemoveGesture(item); + } + + void CreateGestureLayer() + { + _gestureLayer = new GestureLayer(Control); + _gestureLayer.Attach(Control); + _gestureLayer.Deleted += (s, e) => + { + _gestureLayer = null; + Clear(); + }; + UpdateGestureLayerEnabled(); + + if (DeviceInfo.Idiom == DeviceIdiom.TV) + { + if (Control != null) + Control.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); + if (handler == null) return; + + 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 (_gestureLayer == null) + return; + 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 (_gestureLayer == null) + return; + 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 (_gestureLayer == null) + return; + 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, _handler); + } + 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, _handler); + } + else if (recognizer is DropGestureRecognizer) + { + return new DropGestureHandler(recognizer, _handler); + } + return Registrar.Registered.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) + { + if (handler == null) + return; + RemoveGesture(handler.Recognizer); + AddGesture(handler.Recognizer); + + if (_gestureLayer == null) + return; + if (handler.Timeout > _gestureLayer.DoubleTapTimeout) + _gestureLayer.DoubleTapTimeout = handler.Timeout; + } + + void UpdateLongTapGesture(GestureHandler handler) + { + if (_gestureLayer == null) + return; + if (handler.Timeout > 0 && handler.Timeout < _gestureLayer.LongTapTimeout) + _gestureLayer.LongTapTimeout = handler.Timeout; + } + + void UpdateFlickGesture(GestureHandler handler) + { + if (_gestureLayer == null) + return; + 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 (_gestureLayer == null) + return; + 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); + } + } + } + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/GestureHandler.cs b/src/Controls/src/Core/Platform/Tizen/GestureHandler.cs new file mode 100644 index 0000000000..623357bc30 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/GestureHandler.cs @@ -0,0 +1,55 @@ +using System.ComponentModel; +using ElmSharp; + +namespace Microsoft.Maui.Controls.Platform +{ + 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/Controls/src/Core/Platform/Tizen/IGestureController.cs b/src/Controls/src/Core/Platform/Tizen/IGestureController.cs new file mode 100644 index 0000000000..a3fda1bb1e --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/IGestureController.cs @@ -0,0 +1,15 @@ +using System; + +namespace Microsoft.Maui.Controls.Platform +{ + 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/Controls/src/Core/Platform/Tizen/PanGestureHandler.cs b/src/Controls/src/Core/Platform/Tizen/PanGestureHandler.cs new file mode 100644 index 0000000000..4a18bda041 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/PanGestureHandler.cs @@ -0,0 +1,43 @@ +using ElmSharp; + +namespace Microsoft.Maui.Controls.Platform +{ + 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, DPExtensions.ConvertToScaledDP(lineData.X2 - lineData.X1), DPExtensions.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/Controls/src/Core/Platform/Tizen/PinchGestureHandler.cs b/src/Controls/src/Core/Platform/Tizen/PinchGestureHandler.cs new file mode 100644 index 0000000000..22242d4dca --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/PinchGestureHandler.cs @@ -0,0 +1,58 @@ +using ElmSharp; + +namespace Microsoft.Maui.Controls.Platform +{ + public class PinchGestureHandler : GestureHandler + { + Graphics.Point _currentScalePoint; + int _previousPinchRadius; + double _originalPinchScale; + IViewHandler _handler; + + public PinchGestureHandler(IGestureRecognizer recognizer, IViewHandler handler) : base(recognizer) + { + _handler = handler; + } + + public override GestureLayer.GestureType Type + { + get + { + return GestureLayer.GestureType.Zoom; + } + } + + protected override void OnStarted(View sender, object data) + { + var geometry = (_handler.PlatformView as EvasObject).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); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellFlyoutItemAdaptor.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellFlyoutItemAdaptor.cs new file mode 100644 index 0000000000..e58088272d --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellFlyoutItemAdaptor.cs @@ -0,0 +1,185 @@ +#nullable enable + +using System; +using System.Collections; +using System.Collections.Generic; +using ElmSharp; +using Microsoft.Maui.Controls.Internals; +using Tizen.UIExtensions.ElmSharp; +using DPExtensions = Tizen.UIExtensions.ElmSharp.DPExtensions; + +namespace Microsoft.Maui.Controls.Platform +{ + public class ShellFlyoutItemAdaptor : ItemAdaptor + { + Dictionary _nativeFormsTable = new Dictionary(); + Dictionary _dataBindedViewTable = new Dictionary(); + + Shell _shell; + View? _headerCache; + IMauiContext _context; + + protected Shell Shell => _shell; + + public bool HasHeader { get; set; } + + protected virtual DataTemplate? DefaultItemTemplate => null; + + protected virtual DataTemplate? DefaultMenuItemTemplate => null; + + public ShellFlyoutItemAdaptor(Shell shell, IMauiContext context, IEnumerable items, bool hasHeader) : base(items) + { + _shell = shell; + _context = context; + HasHeader = hasHeader; + } + + public override EvasObject? CreateNativeView(EvasObject parent) + { + return CreateNativeView(0, parent); + } + + DataTemplate? GetDataTemplate(int index) + { + var item = this[index]; + if (item != null && item is BindableObject bo) + { + DataTemplate? dataTemplate = (Shell as IShellController)?.GetFlyoutItemDataTemplate(bo); + if (item is IMenuItemController) + { + if (DefaultMenuItemTemplate != null && Shell.MenuItemTemplate == dataTemplate) + dataTemplate = DefaultMenuItemTemplate; + } + else + { + if (DefaultItemTemplate != null && Shell.ItemTemplate == dataTemplate) + dataTemplate = DefaultItemTemplate; + } + + var template = dataTemplate.SelectDataTemplate(item, Shell); + + return template; + } + + return null; + } + + public override EvasObject? CreateNativeView(int index, EvasObject parent) + { + + var template = GetDataTemplate(index); + + if (template != null) + { + var content = (View)template.CreateContent(); + var native = content.ToPlatform(_context); + + _nativeFormsTable[native] = content; + return native; + } + + return null; + } + + public override EvasObject? GetFooterView(EvasObject parent) + { + return null; + } + + public override EvasObject? GetHeaderView(EvasObject parent) + { + if (!HasHeader) + return null; + + _headerCache = ((IShellController)Shell).FlyoutHeader; + + if (_headerCache != null) + { + var native = _headerCache.ToPlatform(_context); + return native; + } + + return null; + } + + public override Size MeasureFooter(int widthConstraint, int heightConstraint) + { + return new Size(0, 0); + } + + public override Size MeasureHeader(int widthConstraint, int heightConstraint) + { + return _headerCache?.Measure(DPExtensions.ConvertToScaledDP(widthConstraint), DPExtensions.ConvertToScaledDP(heightConstraint)).Request.ToEFLPixel() ?? new Size(0, 0); + } + + public override Size MeasureItem(int widthConstraint, int heightConstraint) + { + return MeasureItem(0, widthConstraint, heightConstraint); + } + + public override Size MeasureItem(int index, int widthConstraint, int heightConstraint) + { + var item = this[index]; + if (item != null && _dataBindedViewTable.TryGetValue(item, out View? createdView) && createdView != null) + { + return createdView.Measure(DPExtensions.ConvertToScaledDP(widthConstraint), DPExtensions.ConvertToScaledDP(heightConstraint), MeasureFlags.IncludeMargins).Request.ToEFLPixel(); + } + + return new Size(0, 0); + } + + public override void RemoveNativeView(EvasObject native) + { + native?.Unrealize(); + } + + public override void SetBinding(EvasObject native, int index) + { + if (_nativeFormsTable.TryGetValue(native, out View? view)) + { + ResetBindedView(view); + var item = this[index]; + if (item != null) + { + view.BindingContext = item; + _dataBindedViewTable[item] = view; + } + + view.MeasureInvalidated += OnItemMeasureInvalidated; + Shell.AddLogicalChild(view); + } + } + + public override void UnBinding(EvasObject native) + { + if (_nativeFormsTable.TryGetValue(native, out View? view)) + { + view.MeasureInvalidated -= OnItemMeasureInvalidated; + ResetBindedView(view); + } + } + + void ResetBindedView(View view) + { + if (view.BindingContext != null && _dataBindedViewTable.ContainsKey(view.BindingContext)) + { + _dataBindedViewTable[view.BindingContext] = null; + Shell.RemoveLogicalChild(view); + view.BindingContext = null; + } + } + + void OnItemMeasureInvalidated(object? sender, EventArgs e) + { + var data = (sender as View)?.BindingContext ?? null; + if (data != null) + { + int index = GetItemIndex(data); + if (index != -1) + { + CollectionView?.ItemMeasureInvalidated(index); + } + } + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellItemView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellItemView.cs new file mode 100644 index 0000000000..6c689ee44b --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellItemView.cs @@ -0,0 +1,475 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Reflection; +using ElmSharp; +using Microsoft.Extensions.DependencyInjection; +using Tizen.UIExtensions.ElmSharp; +using EBox = ElmSharp.Box; +using EColor = ElmSharp.Color; +using EToolbarItem = ElmSharp.ToolbarItem; +using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; +using TImage = Tizen.UIExtensions.ElmSharp.Image; +using TThemeConstants = Tizen.UIExtensions.ElmSharp.ThemeConstants; + +namespace Microsoft.Maui.Controls.Platform +{ + public class ShellItemView : IAppearanceObserver, IDisposable + { + Tabs? _tabs = null; + EBox _mainLayout; + EBox _contentHolder; + Panel? _moreItemsDrawer = null; + ShellMoreTabs? _moreItemsList = null; + EToolbarItem? _moreTabItem = null; + ShellSectionStack? _currentStack = null; + + Dictionary _sectionsTable = new Dictionary(); + Dictionary _tabItemsTable = new Dictionary(); + Dictionary _shellSectionStackCache = new Dictionary(); + List _tabsItems = new List(); + + bool _disposed = false; + Color _tabBarBackgroudColor = ShellView.DefaultBackgroundColor; + Color _tabBarTitleColor = ShellView.DefaultTitleColor; + + const string _dotsIcon = TThemeConstants.Shell.Resources.DotsIcon; + + public ShellItemView(ShellItem item, IMauiContext context) + { + ShellItem = item; + MauiContext = context; + + //Initialize(); + _mainLayout = new EBox(NativeParent); + _mainLayout.SetLayoutCallback(OnLayout); + _mainLayout.Show(); + _contentHolder = new EBox(NativeParent); + _contentHolder.Show(); + _mainLayout.PackEnd(_contentHolder); + + ShellItem.PropertyChanged += OnShellItemPropertyChanged; + if (ShellItem.Items is INotifyCollectionChanged notifyCollectionChanged) + { + notifyCollectionChanged.CollectionChanged += OnShellItemsCollectionChanged; + } + ShellController.AddAppearanceObserver(this, ShellItem); + + UpdateTabsItems(); + UpdateCurrentItem(ShellItem.CurrentItem); + } + + ~ShellItemView() + { + Dispose(false); + } + + protected IMauiContext MauiContext { get; private set; } + + protected EvasObject? NativeParent + { + get => MauiContext.GetNativeParent(); + } + + public EvasObject NativeView + { + get + { + return _mainLayout; + } + } + + public EColor TabBarBackgroundColor + { + get + { + return _tabBarBackgroudColor; + } + set + { + _tabBarBackgroudColor = value; + UpdateTabsBackgroudColor(_tabBarBackgroudColor); + } + } + + public EColor TabBarTitleColor + { + get => _tabBarTitleColor; + set + { + _tabBarTitleColor = value; + UpdateTabBarTitleColor(value); + } + } + + ShellItem ShellItem { get; } + IShellController ShellController => Shell.Current; + bool HasMoreItems => _moreItemsDrawer != null; + bool HasTabs => _tabs != null; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + ShellController.RemoveAppearanceObserver(this); + if (ShellItem != null) + { + ShellItem.PropertyChanged -= OnShellItemPropertyChanged; + if (ShellItem.Items is INotifyCollectionChanged notifyCollectionChanged) + { + notifyCollectionChanged.CollectionChanged -= OnShellItemsCollectionChanged; + } + + foreach (var stack in _shellSectionStackCache.Values) + { + stack.Dispose(); + } + + DestroyMoreItems(); + DeinitializeTabs(); + + _sectionsTable.Clear(); + _tabItemsTable.Clear(); + _shellSectionStackCache.Clear(); + _tabsItems.Clear(); + } + NativeView.Unrealize(); + } + _disposed = true; + } + + protected virtual void UpdateTabsItems() + { + ResetTabs(); + if (ShellItem.Items.Count > 1) + { + InitializeTabs(); + foreach (ShellSection section in ShellItem.Items) + { + AddTabsItem(section); + } + } + else + { + DeinitializeTabs(); + } + } + + protected virtual ShellSectionStack CreateShellSectionStack(ShellSection section) + { + return new ShellSectionStack(section, MauiContext); + } + + bool _disableMoreItemOpen; + + void UpdateCurrentItem(ShellSection section) + { + UpdateCurrentShellSection(section); + + if (_tabs != null) + { + if (_tabItemsTable.ContainsKey(section)) + { + _tabItemsTable[section].IsSelected = true; + } + else if (_moreItemsDrawer != null) + { + _disableMoreItemOpen = true; + + if (_moreTabItem != null) + _moreTabItem.IsSelected = true; + + _disableMoreItemOpen = false; + } + + if (_moreItemsDrawer != null) + { + _moreItemsDrawer.IsOpen = false; + } + } + } + + void UpdateCurrentItemFromUI(ShellSection? section) + { + if (section != null && ShellItem.CurrentItem != section) + { + ShellItem.SetValueFromRenderer(ShellItem.CurrentItemProperty, section); + } + if (_moreItemsDrawer != null) + { + _moreItemsDrawer.IsOpen = false; + } + } + + void InitializeTabs() + { + if (_tabs != null) + return; + + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + + _tabs = new Tabs(NativeParent); + _tabs.Show(); + _tabs.BackgroundColor = _tabBarBackgroudColor; + _tabs.Scrollable = TabsType.Fixed; + _tabs.Selected += OnTabsSelected; + _mainLayout.PackEnd(_tabs); + } + + void DeinitializeTabs() + { + if (_tabs == null) + return; + + _mainLayout.UnPack(_tabs); + _tabs.Selected -= OnTabsSelected; + _tabs.Unrealize(); + _tabs = null; + } + + void CreateMoreItems() + { + if (_moreItemsDrawer != null) + return; + + _moreItemsList = new ShellMoreTabs(NativeParent); + _moreItemsList.Show(); + _moreItemsList.ItemSelected += OnMoreItemSelected; + + _moreItemsDrawer = new Panel(NativeParent); + _moreItemsDrawer.Show(); + + _moreItemsDrawer.SetScrollable(true); + _moreItemsDrawer.SetScrollableArea(1.0); + _moreItemsDrawer.Direction = PanelDirection.Bottom; + _moreItemsDrawer.IsOpen = false; + _moreItemsDrawer.SetContent(_moreItemsList, true); + _mainLayout.PackEnd(_moreItemsDrawer); + } + + void DestroyMoreItems() + { + if (_moreItemsDrawer == null) + return; + + _mainLayout.UnPack(_moreItemsDrawer); + + _moreItemsList?.Unrealize(); + _moreItemsDrawer?.Unrealize(); + + _moreItemsList = null; + _moreItemsDrawer = null; + } + + void OnMoreItemSelected(object? sender, GenListItemEventArgs e) + { + ShellSection? section = e.Item.Data as ShellSection; + UpdateCurrentItemFromUI(section); + } + + void OnShellItemPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(ShellItem.CurrentItem)) + { + UpdateCurrentItem(ShellItem.CurrentItem); + } + } + + void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance) + { + var tabBarBackgroudColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarBackgroundColor; + var tabBarTitleColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarTitleColor; + + TabBarBackgroundColor = tabBarBackgroudColor.IsDefault() ? ShellView.DefaultBackgroundColor : (tabBarBackgroudColor?.ToPlatformEFL()).GetValueOrDefault(); + TabBarTitleColor = tabBarTitleColor.IsDefault() ? ShellView.DefaultTitleColor : (tabBarTitleColor?.ToPlatformEFL()).GetValueOrDefault(); + } + + void UpdateTabsBackgroudColor(EColor color) + { + foreach (EToolbarItem item in _tabsItems) + { + item.SetBackgroundColor(color); + } + } + + void UpdateTabBarTitleColor(EColor color) + { + foreach (EToolbarItem item in _tabsItems) + { + item.SetTextColor(color); + } + } + + void ResetTabs() + { + if (!HasTabs) + return; + + foreach (var item in _tabsItems) + { + item.Delete(); + } + _tabsItems.Clear(); + DestroyMoreItems(); + _moreTabItem = null; + } + + void OnShellItemsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + UpdateTabsItems(); + } + + void AddTabsItem(ShellSection section) + { + if (_tabsItems.Count < 5) + { + var item = AppendTabsItem(section.Title, section.Icon); + if (item != null) + { + _sectionsTable.Add(item, section); + _tabItemsTable.Add(section, item); + _tabsItems.Add(item); + } + } + else if (_moreItemsDrawer == null) + { + CreateMoreItems(); + + var last = _tabsItems.Last(); + var lastSection = _sectionsTable[last]; + + _tabsItems.Remove(last); + _sectionsTable.Remove(last); + _tabItemsTable.Remove(lastSection); + last.Delete(); + + //The source of icon resources is https://materialdesignicons.com/ + var assembly = typeof(ShellItemView).GetTypeInfo().Assembly; + var assemblyName = assembly.GetName().Name; + _moreTabItem = AppendTabsItem("More", ImageSource.FromResource(assemblyName + "." + _dotsIcon, assembly)); + if (_moreTabItem != null) + _tabsItems.Add(_moreTabItem); + + _moreItemsList?.AddItem(lastSection); + _moreItemsList?.AddItem(section); + } + else + { + _moreItemsList?.AddItem(section); + } + } + + void UpdateCurrentShellSection(ShellSection section) + { + if (_currentStack != null) + { + _currentStack.Hide(); + _contentHolder.UnPack(_currentStack); + } + _currentStack = null; + + if (section == null) + { + return; + } + + ShellSectionStack native; + if (_shellSectionStackCache.ContainsKey(section)) + { + native = _shellSectionStackCache[section]; + } + else + { + native = CreateShellSectionStack(section); + _shellSectionStackCache[section] = native; + } + _currentStack = native; + _currentStack.Show(); + _contentHolder.PackEnd(_currentStack); + } + + void OnTabsSelected(object? sender, EToolbarItemEventArgs e) + { + if (_tabs?.SelectedItem == null) + return; + + if (_moreItemsDrawer != null && e.Item == _moreTabItem) + { + if (!_disableMoreItemOpen) + { + _moreItemsDrawer.IsOpen = !_moreItemsDrawer.IsOpen; + } + } + else + { + UpdateCurrentItemFromUI(_sectionsTable[_tabs.SelectedItem]); + } + } + + void OnLayout() + { + if (NativeView.Geometry.Height == 0 || NativeView.Geometry.Width == 0) + return; + + int tabsHeight = 0; + var bound = _mainLayout.Geometry; + if (_tabs != null) + { + tabsHeight = _tabs.MinimumHeight; + var tabsBound = bound; + tabsBound.Y += (bound.Height - tabsHeight); + tabsBound.Height = tabsHeight; + _tabs.Geometry = tabsBound; + if (_moreItemsDrawer != null && _moreItemsList != null) + { + int moreItemListHeight = _moreItemsList.HeightRequest; + moreItemListHeight = Math.Min(moreItemListHeight, bound.Height - tabsHeight); + var moreItemDrawerBound = bound; + moreItemDrawerBound.Y += (bound.Height - tabsHeight - moreItemListHeight); + moreItemDrawerBound.Height = moreItemListHeight; + _moreItemsDrawer.Geometry = moreItemDrawerBound; + } + } + bound.Height -= tabsHeight; + _contentHolder.Geometry = bound; + } + + EToolbarItem? AppendTabsItem(string text, ImageSource iconSource) + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + + var item = _tabs?.Append(text); + if (item != null) + { + if (iconSource != null) + { + TImage image = new TImage(NativeParent); + var provider = MauiContext.Services.GetRequiredService(); + var service = provider.GetRequiredImageSourceService(iconSource); + + _ = service.GetImageAsync(iconSource, image); + + item.SetIconPart(image); + } + + item.SetBackgroundColor(_tabBarBackgroudColor); + item.SetUnderlineColor(EColor.Transparent); + item.SetTextColor(_tabBarTitleColor); + return item; + } + return null; + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellMoreTabs.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellMoreTabs.cs new file mode 100644 index 0000000000..408cf90399 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellMoreTabs.cs @@ -0,0 +1,97 @@ +using ElmSharp; +using EBox = ElmSharp.Box; +using EImage = ElmSharp.Image; +using TImage = Tizen.UIExtensions.ElmSharp.Image; +using TLabel = Tizen.UIExtensions.ElmSharp.Label; +using TThemeConstants = Tizen.UIExtensions.ElmSharp.ThemeConstants; + +namespace Microsoft.Maui.Controls.Platform +{ + public class ShellMoreTabs : GenList + { + GenItemClass _defaultClass = null; + + public ShellMoreTabs(EvasObject parent) : base(parent) + { + SetAlignment(-1, -1); + SetWeight(1, 1); + NativeParent = parent; + + Homogeneous = true; + SelectionMode = GenItemSelectionMode.Always; + BackgroundColor = ShellView.DefaultBackgroundColor; + _defaultClass = new GenItemClass(TThemeConstants.GenItemClass.Styles.Full) + { + GetContentHandler = GetContent, + }; + } + + protected EvasObject NativeParent { get; private set; } + + public void AddItem(ShellSection section) + { + Append(_defaultClass, section); + } + + public int HeightRequest + { + get + { + var cellHeight = this.GetDefaultIconSize() * 2 + this.GetDefaultIconSize(); + return DPExtensions.ConvertToScaledPixel(cellHeight) * Count; + } + } + + EvasObject GetContent(object data, string part) + { + ShellSection section = data as ShellSection; + + var box = new EBox(NativeParent); + box.Show(); + + EImage icon = null; + if (section.Icon != null) + { + icon = new TImage(NativeParent); + icon.Show(); + box.PackEnd(icon); + } + + var title = new TLabel(NativeParent) + { + Text = section.Title, + FontSize = DPExtensions.ConvertToEflFontPoint(14), + HorizontalTextAlignment = Tizen.UIExtensions.Common.TextAlignment.Start, + VerticalTextAlignment = Tizen.UIExtensions.Common.TextAlignment.Center, + }; + title.Show(); + box.PackEnd(title); + int iconPadding = DPExtensions.ConvertToScaledPixel(this.GetDefaultIconPadding()); + int iconSize = DPExtensions.ConvertToScaledPixel(this.GetDefaultIconSize()); + int cellHeight = iconPadding * 2 + iconSize; + box.SetLayoutCallback(() => + { + var bound = box.Geometry; + int leftMargin = iconPadding; + + if (icon != null) + { + var iconBound = bound; + iconBound.X += iconPadding; + iconBound.Y += iconPadding; + iconBound.Width = iconSize; + iconBound.Height = iconSize; + icon.Geometry = iconBound; + leftMargin = (2 * iconPadding + iconSize); + } + + bound.X += leftMargin; + bound.Width -= leftMargin; + title.Geometry = bound; + }); + + box.MinimumHeight = cellHeight; + return box; + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellNavBar.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellNavBar.cs new file mode 100644 index 0000000000..a06b5b445f --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellNavBar.cs @@ -0,0 +1,400 @@ +#nullable enable + +using System; +using System.Reflection; +using ElmSharp; +using Microsoft.Maui.Devices; +using Microsoft.Extensions.DependencyInjection; +using Tizen.UIExtensions.ElmSharp; +using EBox = ElmSharp.Box; +using EColor = ElmSharp.Color; +using TButton = Tizen.UIExtensions.ElmSharp.Button; +using TImage = Tizen.UIExtensions.ElmSharp.Image; +using TLabel = Tizen.UIExtensions.ElmSharp.Label; +using TThemeConstants = Tizen.UIExtensions.ElmSharp.ThemeConstants; +using TDPExtensions = Tizen.UIExtensions.ElmSharp.DPExtensions; + +namespace Microsoft.Maui.Controls.Platform +{ + public class ShellNavBar : EBox, IFlyoutBehaviorObserver, IDisposable + { + TImage? _menuIcon; + TButton _menuButton; + TLabel _title; + ShellSearchView? _searchView = null; + EvasObject? _nativeTitleView = null; + + SearchHandler? _searchHandler = null; + View? _titleView = null; + Page? _page = null; + + FlyoutBehavior _flyoutBehavior = FlyoutBehavior.Flyout; + + EColor _backgroudColor = ShellView.DefaultBackgroundColor; + EColor _foregroudColor = ShellView.DefaultForegroundColor; + EColor _titleColor = ShellView.DefaultTitleColor; + + // The source of icon resources is https://materialdesignicons.com/ + const string _menuIconRes = TThemeConstants.Shell.Resources.MenuIcon; + const string _backIconRes = TThemeConstants.Shell.Resources.BackIcon; + + bool _hasBackButton = false; + private bool disposedValue; + bool _isTV = DeviceInfo.Idiom == DeviceIdiom.TV; + + public ShellNavBar(IMauiContext context) : base(context?.GetNativeParent()) + { + MauiContext = context; + + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + SetLayoutCallback(OnLayout); + + _menuButton = new TButton(NativeParent); + _menuButton.Clicked += OnMenuClicked; + + _menuIcon = new TImage(NativeParent); + UpdateMenuIcon(); + + _title = new TLabel(NativeParent) + { + FontSize = this.GetDefaultTitleFontSize(), + VerticalTextAlignment = (global::Tizen.UIExtensions.Common.TextAlignment)TextAlignment.Center, + TextColor = _titleColor.ToCommon(), + FontAttributes = Tizen.UIExtensions.Common.FontAttributes.Bold, + }; + _title.Show(); + + BackgroundColor = _backgroudColor; + _menuButton.BackgroundColor = _backgroudColor; + PackEnd(_menuButton); + PackEnd(_title); + } + + ~ShellNavBar() + { + Dispose(false); + } + + protected IMauiContext? MauiContext { get; private set; } + + protected EvasObject? NativeParent + { + get => MauiContext?.GetNativeParent(); + } + + public IShellController ShellController => Shell.Current; + + public bool HasBackButton + { + get + { + return _hasBackButton; + } + set + { + _hasBackButton = value; + UpdateMenuIcon(); + } + } + + public FlyoutBehavior FlyoutBehavior + { + get => _flyoutBehavior; + set + { + if (_flyoutBehavior != value) + { + _flyoutBehavior = value; + UpdateMenuIcon(); + } + } + } + + public SearchHandler? SearchHandler + { + get + { + return _searchHandler; + } + set + { + _searchHandler = value; + UpdateSearchHandler(_searchHandler); + UpdateChildren(); + } + } + + public View? TitleView + { + get + { + return _titleView; + } + set + { + _titleView = value; + UpdateTitleView(_titleView); + UpdateChildren(); + } + } + + public string Title + { + get + { + return _title.Text; + } + set + { + _title.Text = value; + } + } + + public override EColor BackgroundColor + { + get + { + return _backgroudColor; + } + set + { + _backgroudColor = value; + _menuButton.BackgroundColor = _backgroudColor; + base.BackgroundColor = _backgroudColor; + } + } + + public EColor ForegroundColor + { + get + { + return _foregroudColor; + } + set + { + _foregroudColor = value; + } + } + + public EColor TitleColor + { + get + { + return _titleColor; + } + set + { + _titleColor = value; + _title.TextColor = value.ToCommon(); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public void SetPage(Page page) + { + _page = page; + Title = page.Title; + SearchHandler = Shell.GetSearchHandler(page); + TitleView = Shell.GetTitleView(page); + UpdateMenuIcon(); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + Unrealize(); + } + disposedValue = true; + } + } + + async void UpdateMenuIcon() + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + + ImageSource? source = null; + if (HasBackButton) + { + if (_isTV) + { + _menuButton.Style = TThemeConstants.Button.Styles.Default; + _menuButton.Text = TThemeConstants.Shell.Resources.TV.BackIconCode; + _menuIcon = null; + } + else + { + var assembly = typeof(ShellNavBar).GetTypeInfo().Assembly; + var assemblyName = assembly.GetName().Name; + source = ImageSource.FromResource(assemblyName + "." + _backIconRes, assembly); + } + } + else if (_flyoutBehavior != FlyoutBehavior.Flyout) + { + _menuButton.Hide(); + } + else if (ShellController.FlyoutIcon != null) + { + if (_isTV) + { + _menuButton.Style = TThemeConstants.Button.Styles.Circle; + _menuIcon = new TImage(NativeParent); + } + source = Shell.Current.FlyoutIcon; + } + else + { + if (_isTV) + { + _menuButton.Style = TThemeConstants.Button.Styles.Default; + _menuButton.Text = TThemeConstants.Shell.Resources.TV.MenuIconCode; + _menuIcon = null; + } + else + { + var assembly = typeof(ShellNavBar).GetTypeInfo().Assembly; + var assemblyName = assembly.GetName().Name; + source = ImageSource.FromResource(assemblyName + "." + _menuIconRes, assembly); + + } + } + + if (source != null && _menuIcon != null) + { + _menuIcon.Show(); + var provider = MauiContext?.Services.GetRequiredService(); + var service = provider?.GetRequiredImageSourceService(source); + if (service != null) + { + await service.GetImageAsync(source, _menuIcon); + } + } + _menuButton.SetIconPart(_menuIcon); + _menuButton.Show(); + } + + void OnMenuClicked(object? sender, EventArgs e) + { + var backButtonHandler = Shell.GetBackButtonBehavior(_page); + if (backButtonHandler?.Command != null) + { + backButtonHandler.Command.Execute(backButtonHandler.CommandParameter); + } + else if (_hasBackButton) + { + Shell.Current.CurrentItem.Navigation.PopAsync(); + } + else if (_flyoutBehavior == FlyoutBehavior.Flyout) + { + Shell.Current.FlyoutIsPresented = !Shell.Current.FlyoutIsPresented; + } + } + + void UpdateTitleView(View? titleView) + { + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + _nativeTitleView?.Unrealize(); + _nativeTitleView = null; + + if (titleView != null) + { + var _nativeTitleView = titleView.ToPlatform(MauiContext); + _nativeTitleView.Show(); + PackEnd(_nativeTitleView); + } + } + + void UpdateSearchHandler(SearchHandler? handler) + { + if (_searchView != null) + { + UnPack(_searchView.PlatformView); + _searchView.Dispose(); + _searchView = null; + } + + if (handler != null) + { + _searchView = new ShellSearchView(handler, MauiContext); + _searchView.PlatformView?.Show(); + PackEnd(_searchView.PlatformView); + } + } + + void UpdateChildren() + { + if (_searchHandler != null) + { + _searchView?.PlatformView?.Show(); + _title?.Hide(); + _nativeTitleView?.Hide(); + } + else if (_titleView != null) + { + _nativeTitleView?.Show(); + _title?.Hide(); + _searchView?.PlatformView?.Hide(); + } + else + { + _title.Show(); + _nativeTitleView?.Hide(); + _searchView?.PlatformView?.Hide(); + } + } + + void OnLayout() + { + if (Geometry.Width == 0 || Geometry.Height == 0) + return; + + int menuSize = TDPExtensions.ConvertToScaledPixel(this.GetDefaultMenuSize()); + int menuMargin = TDPExtensions.ConvertToScaledPixel(this.GetDefaultMargin()); + int titleHMargin = TDPExtensions.ConvertToScaledPixel(this.GetDefaultMargin()); + int titleVMargin = TDPExtensions.ConvertToScaledPixel(this.GetDefaultTitleVMargin()); + + var bound = Geometry; + + var menuBound = bound; + menuBound.X += menuMargin; + menuBound.Y += (menuBound.Height - menuSize) / 2; + menuBound.Width = menuSize; + menuBound.Height = menuSize; + + _menuButton.Geometry = menuBound; + + var contentBound = Geometry; + contentBound.X = menuBound.Right + titleHMargin; + contentBound.Y += titleVMargin; + contentBound.Width -= (menuBound.Width + menuMargin + titleHMargin * 2); + contentBound.Height -= titleVMargin * 2; + + if (_searchView != null && _searchView.PlatformView != null) + { + _searchView.PlatformView.Geometry = contentBound; + } + else if (_titleView != null && _nativeTitleView != null) + { + _nativeTitleView.Geometry = contentBound; + } + else + { + _title.Geometry = contentBound; + } + } + + void IFlyoutBehaviorObserver.OnFlyoutBehaviorChanged(FlyoutBehavior behavior) + { + FlyoutBehavior = behavior; + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellSearchResultList.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSearchResultList.cs new file mode 100644 index 0000000000..97ca3331ba --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSearchResultList.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using ElmSharp; +using EColor = ElmSharp.Color; +using TThemeConstants = Tizen.UIExtensions.ElmSharp.ThemeConstants; + +namespace Microsoft.Maui.Controls.Platform +{ + public class ShellSearchResultList : GenList + { + GenItemClass _defaultClass = null; + IReadOnlyList _itemsSource; + + public ShellSearchResultList(IMauiContext context) : base(context?.GetNativeParent()) + { + MauiContext = context; + + SetAlignment(-1, -1); + SetWeight(1, 1); + AllowFocus(true); + + Homogeneous = true; + SelectionMode = GenItemSelectionMode.Always; + BackgroundColor = EColor.White; + + _defaultClass = new GenItemClass(TThemeConstants.GenItemClass.Styles.Full) + { + GetContentHandler = GetContent, + }; + } + + public int Height { get; private set; } + + public IReadOnlyList ItemsSource + { + get => _itemsSource; + set + { + Clear(); + Height = 0; + + _itemsSource = value; + foreach (var item in _itemsSource) + { + Append(item); + } + } + } + + protected IMauiContext MauiContext { get; private set; } + + protected EvasObject NativeParent + { + get => MauiContext.GetNativeParent(); + } + + public void UpdateLayout() + { + if (FirstItem != null && Height == 0) + { + var view = FirstItem.Data as View; + var native = view.ToPlatform(MauiContext); + var measured = view.Measure(DPExtensions.ConvertToScaledDP(Geometry.Width), double.PositiveInfinity); + Height = DPExtensions.ConvertToScaledPixel(measured.Request.Height); + } + + var bound = Geometry; + bound.Height = Math.Min(Height * _itemsSource.Count, bound.Width); + Geometry = bound; + + UpdateRealizedItems(); + } + + public DataTemplate ItemTemplate { get; set; } + + EvasObject GetContent(object data, string part) + { + var view = data as View; + var native = view.ToPlatform(MauiContext); + + if (Height == 0) + { + var measured = view.Measure(DPExtensions.ConvertToScaledDP(Geometry.Width), double.PositiveInfinity); + Height = DPExtensions.ConvertToScaledPixel(measured.Request.Height); + } + + native.MinimumHeight = Height; + return native; + } + + void Append(object data) + { + var view = ItemTemplate.CreateContent() as View; + view.Parent = Shell.Current; + view.BindingContext = data; + Append(_defaultClass, view); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellSearchView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSearchView.cs new file mode 100644 index 0000000000..bd7024c064 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSearchView.cs @@ -0,0 +1,372 @@ +#nullable enable + +using System; +using System.ComponentModel; +using ElmSharp; +using EColor = ElmSharp.Color; +using TSearchBar = Tizen.UIExtensions.ElmSharp.SearchBar; +using TTextChangedEventArgs = Tizen.UIExtensions.Common.TextChangedEventArgs; + +namespace Microsoft.Maui.Controls.Platform +{ + public class ShellSearchView : IDisposable + { + bool disposedValue; + ShellSearchResultList? _searchResultList; + + public ShellSearchView(SearchHandler searchHandler, IMauiContext? context) + { + Element = searchHandler; + MauiContext = context; + + Element.FocusChangeRequested += OnFocusChangedRequested; + Element.PropertyChanged += OnElementPropertyChanged; + (Element as ISearchHandlerController).ListProxyChanged += OnSearchResultListChanged; + + if (NativeParent != null) + { + Control = new TSearchBar(NativeParent) + { + IsSingleLine = true, + }; + Control.Show(); + Control.SetInputPanelReturnKeyType(InputPanelReturnKeyType.Search); + Control.TextChanged += OnTextChanged; + Control.Activated += OnActivated; + Control.Focused += OnFocused; + Control.Unfocused += OnFocused; + } + + UpdateKeyboard(); + UpdatePlaceholder(); + UpdatePlaceholderColor(); + UpdateHorizontalTextAlignment(); + UpdateTextColor(); + UpdateFontAttributes(); + UpdateFontFamily(); + UpdateFontSize(); + UpdateBackgroundColor(); + UpdateQuery(); + UpdateIsSearchEnabled(); + UpdateSearchResult(); + } + + public SearchHandler Element { get; } + + public EvasObject? PlatformView => Control; + + protected IMauiContext? MauiContext { get; private set; } + + protected EvasObject? NativeParent + { + get => MauiContext?.GetNativeParent(); + } + + ISearchHandlerController SearchHandlerController => Element; + + TSearchBar? Control { get; } + + ~ShellSearchView() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + Element.FocusChangeRequested -= OnFocusChangedRequested; + Element.PropertyChanged -= OnElementPropertyChanged; + (Element as ISearchHandlerController).ListProxyChanged -= OnSearchResultListChanged; + + if (Control != null) + { + Control.TextChanged -= OnTextChanged; + Control.Activated -= OnActivated; + Control.Focused -= OnFocused; + Control.Unfocused -= OnFocused; + Control.Unrealize(); + } + } + disposedValue = true; + } + } + + void OnElementPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Element.Keyboard)) + { + UpdateKeyboard(); + } + else if (e.PropertyName == nameof(Element.Placeholder)) + { + UpdatePlaceholder(); + } + else if (e.PropertyName == nameof(Element.PlaceholderColor)) + { + UpdatePlaceholderColor(); + } + else if (e.PropertyName == nameof(Element.HorizontalTextAlignment)) + { + UpdateHorizontalTextAlignment(); + } + else if (e.PropertyName == nameof(Element.TextColor)) + { + UpdateTextColor(); + } + else if (e.PropertyName == nameof(Element.FontAttributes)) + { + UpdateFontAttributes(); + } + else if (e.PropertyName == nameof(Element.FontFamily)) + { + UpdateFontFamily(); + } + else if (e.PropertyName == nameof(Element.FontSize)) + { + UpdateFontSize(); + } + else if (e.PropertyName == nameof(Element.BackgroundColor)) + { + UpdateBackgroundColor(); + } + else if (e.PropertyName == nameof(Element.Query)) + { + UpdateQuery(); + } + else if (e.PropertyName == nameof(Element.IsSearchEnabled)) + { + UpdateIsSearchEnabled(); + } + else if (e.PropertyName == nameof(Element.ShowsResults)) + { + UpdateSearchResult(); + } + } + + void OnSearchResultListChanged(object? sender, ListProxyChangedEventArgs e) + { + UpdateSearchResult(); + } + + void InitializeSearchResultList() + { + if (_searchResultList != null) + { + return; + } + _searchResultList = new ShellSearchResultList(MauiContext); + _searchResultList.Show(); + _searchResultList.ItemSelected += OnResultItemSelected; + } + + void OnResultItemSelected(object? sender, GenListItemEventArgs e) + { + var data = (e.Item.Data as View)?.BindingContext; + + if (data != null) + { + SearchHandlerController.ItemSelected(data); + Application.Current?.Dispatcher.Dispatch(() => + { + DeinitializeSearchResultList(); + }); + } + } + + void DeinitializeSearchResultList() + { + if (_searchResultList == null) + { + return; + } + + _searchResultList.ItemSelected -= OnResultItemSelected; + _searchResultList.Unrealize(); + _searchResultList = null; + } + + void UpdateSearchResult() + { + if (SearchHandlerController == null) + return; + + if (!Element.ShowsResults) + { + DeinitializeSearchResultList(); + return; + } + + if (Control != null && + Control.IsFocused && SearchHandlerController.ListProxy != null && + SearchHandlerController.ListProxy.Count > 0 && + Element.ItemTemplate != null) + { + InitializeSearchResultList(); + if (_searchResultList != null) + { + _searchResultList.ItemTemplate = Element.ItemTemplate; + _searchResultList.ItemsSource = SearchHandlerController.ListProxy; + UpdateSearchResultLayout(); + } + } + else + { + DeinitializeSearchResultList(); + } + } + + void UpdateIsSearchEnabled() + { + if (Control == null) + return; + + Control.IsEnabled = Element.IsSearchEnabled; + } + + void UpdateQuery() + { + if (Control == null) + return; + + Control.Text = (Element.Query != null) ? Element.Query : ""; + } + + void UpdateFontAttributes() + { + if (Control == null) + return; + + Control.FontAttributes = Element.FontAttributes.ToPlatform(); + } + + void UpdateFontFamily() + { + if (Control == null) + return; + + Control.FontFamily = Element.FontFamily; + } + + void UpdateFontSize() + { + if (Control == null) + return; + + Control.FontSize = Element.FontSize; + } + + void UpdateBackgroundColor() + { + if (Control == null) + return; + + var color = Element.BackgroundColor.ToPlatformEFL(); + Control.BackgroundColor = color == EColor.Default ? EColor.White : color; + } + + void UpdateTextColor() + { + if (Control == null) + return; + + Control.TextColor = Element.TextColor.ToPlatform(); + } + + void UpdateHorizontalTextAlignment() + { + if (Control == null) + return; + + Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToPlatform(); + } + + void OnFocusChangedRequested(object? sender, VisualElement.FocusRequestArgs e) + { + if (Control == null) + return; + + Control.SetFocus(e.Focus); + e.Result = true; + } + + void UpdateKeyboard() + { + if (Control == null) + return; + + Control.Keyboard = Element.Keyboard.ToPlatform(); + } + + void UpdatePlaceholder() + { + if (Control == null) + return; + + Control.Placeholder = Element.Placeholder; + } + void UpdatePlaceholderColor() + { + if (Control == null) + return; + + Control.PlaceholderColor = Element.PlaceholderColor.ToPlatform(); + } + + void OnFocused(object? sender, EventArgs e) + { + if (Control == null) + return; + + Element.SetIsFocused(Control.IsFocused); + if (Control.IsFocused) + { + UpdateSearchResult(); + } + else + { + if (_searchResultList != null) + { + _searchResultList.Hide(); + } + Application.Current?.Dispatcher.DispatchDelayed(TimeSpan.FromMilliseconds(100), () => + { + DeinitializeSearchResultList(); + }); + } + } + + void OnActivated(object? sender, EventArgs e) + { + if (Control == null) + return; + + Control.HideInputPanel(); + (Element as ISearchHandlerController).QueryConfirmed(); + } + + void OnTextChanged(object? sender, TTextChangedEventArgs e) + { + Element.SetValueCore(SearchHandler.QueryProperty, (sender as TSearchBar)?.Text); + } + + void UpdateSearchResultLayout() + { + if (_searchResultList != null && PlatformView != null) + { + var bound = PlatformView.Geometry; + bound.Y += PlatformView.Geometry.Height; + _searchResultList.Geometry = bound; + _searchResultList.UpdateLayout(); + } + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionHandler.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionHandler.cs new file mode 100644 index 0000000000..791dc80af9 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionHandler.cs @@ -0,0 +1,389 @@ +#nullable enable + +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 IShellSectionHandler : IDisposable + { + EvasObject PlatformView { get; } + } + + public class ShellSectionHandler : IAppearanceObserver, IShellSectionHandler + { + EBox _mainLayout; + EBox _contentArea; + 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 ShellSectionHandler(ShellSection section, IMauiContext context) + { + ShellSection = section; + MauiContext = context; + ShellSection.PropertyChanged += OnSectionPropertyChanged; + if (ShellSection.Items is INotifyCollectionChanged collection) + { + collection.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.GetNativeParent(); + } + + 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 PlatformView + { + 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); + } + } + + ~ShellSectionHandler() + { + 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?.ToPlatformEFL()).GetValueOrDefault(); + ToolbarForegroundColor = foregroundColor.IsDefault() ? ShellView.DefaultForegroundColor : (foregroundColor?.ToPlatformEFL()).GetValueOrDefault(); + } + + 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(); + } + PlatformView.Unrealize(); + } + _disposed = true; + } + + void InitializeTabs() + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + + 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); + } + + if(_tabs !=null) + _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); + + if (item != null) + { + _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.ToPlatform(MauiContext); + } + + void OnLayout() + { + if (PlatformView.Geometry.Width == 0 || PlatformView.Geometry.Height == 0) + return; + var bound = PlatformView.Geometry; + + int tabsHeight; + if (_tabs != null && 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/ShellSectionStack.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionStack.cs new file mode 100644 index 0000000000..44fa03f08b --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellSectionStack.cs @@ -0,0 +1,305 @@ +#nullable enable + +using System; +using System.ComponentModel; +using System.Threading.Tasks; +using Microsoft.Maui.Devices; +using ElmSharp; +using EBox = ElmSharp.Box; + +namespace Microsoft.Maui.Controls.Platform +{ + public class ShellSectionStack : EBox, IAppearanceObserver, IDisposable + { + ShellNavBar? _navBar = null; + Page? _currentPage = null; + SimpleViewStack _viewStack; + IShellSectionHandler? _shellSectionHandler; + + bool _disposed = false; + bool _navBarIsVisible = true; + + public ShellSectionStack(ShellSection section, IMauiContext context) : base(context.GetNativeParent()) + { + ShellSection = section; + MauiContext = context; + + SetAlignment(-1, -1); + SetWeight(1, 1); + SetLayoutCallback(OnLayout); + + _viewStack = new SimpleViewStack(NativeParent); + if (DeviceInfo.Idiom == DeviceIdiom.Phone) + { + _viewStack.BackgroundColor = ElmSharp.Color.White; + } + _viewStack.Show(); + PackEnd(_viewStack); + + InitializeComponent(); + } + + protected IMauiContext? MauiContext { get; private set; } + + protected EvasObject? NativeParent + { + get => MauiContext?.GetNativeParent(); + } + + public virtual bool NavBarIsVisible + { + get + { + return _navBarIsVisible; + } + set + { + _navBarIsVisible = value; + OnLayout(); + } + } + + ShellSection ShellSection { get; } + + ~ShellSectionStack() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + (Shell.Current as IShellController).RemoveAppearanceObserver(this); + (Shell.Current as IShellController).RemoveFlyoutBehaviorObserver(_navBar); + if (ShellSection != null) + { + IShellSectionController controller = ShellSection; + controller.NavigationRequested -= OnNavigationRequested; + controller.RemoveDisplayedPageObserver(this); + } + if (_currentPage != null) + { + _currentPage.PropertyChanged -= OnPagePropertyChanged; + } + if (_navBar != null) + { + _navBar.Dispose(); + _navBar = null; + } + Unrealize(); + } + _disposed = true; + } + + protected virtual IShellSectionHandler CreateShellSectionView(ShellSection section) + { + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + return new ShellSectionHandler(section, MauiContext); + } + + void InitializeComponent() + { + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + _navBar = new ShellNavBar(MauiContext); + _navBar.Show(); + PackEnd(_navBar); + + IShellSectionController controller = ShellSection; + controller.NavigationRequested += OnNavigationRequested; + controller.AddDisplayedPageObserver(this, UpdateDisplayedPage); + ((IShellController)Shell.Current).AddAppearanceObserver(this, ShellSection); + ((IShellController)Shell.Current).AddFlyoutBehaviorObserver(_navBar); + + _shellSectionHandler = CreateShellSectionView(ShellSection); + _shellSectionHandler.PlatformView.Show(); + _viewStack.Push(_shellSectionHandler.PlatformView); + + Application.Current?.Dispatcher.Dispatch(() => + { + (_shellSectionHandler.PlatformView as Widget)?.SetFocus(true); + }); + } + + void UpdateDisplayedPage(Page page) + { + // this callback is raised when DisplayPage was updated and it is raised ahead of push NavigationRequesed event + if (_currentPage != null) + { + _currentPage.PropertyChanged -= OnPagePropertyChanged; + } + if (page == null) + return; + + _currentPage = page; + _currentPage.PropertyChanged += OnPagePropertyChanged; + NavBarIsVisible = Shell.GetNavBarIsVisible(page); + _navBar?.SetPage(page); + } + + void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance) + { + if (_navBar == null) + return; + + var titleColor = (appearance as IShellAppearanceElement)?.EffectiveTabBarTitleColor; + var backgroundColor = appearance?.BackgroundColor; + var foregroundColor = appearance?.ForegroundColor; + + _navBar.TitleColor = titleColor.IsDefault() ? ShellView.DefaultTitleColor : (titleColor?.ToPlatformEFL()).GetValueOrDefault(); + _navBar.BackgroundColor = backgroundColor.IsDefault() ? ShellView.DefaultBackgroundColor : (backgroundColor?.ToPlatformEFL()).GetValueOrDefault(); + _navBar.ForegroundColor = foregroundColor.IsDefault() ? ShellView.DefaultForegroundColor : (foregroundColor?.ToPlatformEFL()).GetValueOrDefault(); + } + + + protected virtual void OnPagePropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == Page.TitleProperty.PropertyName) + { + if (_navBar != null) + _navBar.Title = (sender as Page)?.Title ?? ""; + } + else if (e.PropertyName == Shell.NavBarIsVisibleProperty.PropertyName) + { + NavBarIsVisible = Shell.GetNavBarIsVisible(sender as Page); + } + else if (e.PropertyName == Shell.TitleViewProperty.PropertyName) + { + if (_navBar != null) + _navBar.TitleView = Shell.GetTitleView(sender as Page); + } + } + + void OnNavigationRequested(object? sender, Internals.NavigationRequestedEventArgs e) + { + if (e.RequestType == Internals.NavigationRequestType.Push) + { + PushRequest(sender, e); + } + else if (e.RequestType == Internals.NavigationRequestType.Insert) + { + InsertRequest(sender, e); + } + else if (e.RequestType == Internals.NavigationRequestType.Pop) + { + PopRequest(sender, e); + } + else if (e.RequestType == Internals.NavigationRequestType.PopToRoot) + { + PopToRootRequest(sender, e); + } + else if (e.RequestType == Internals.NavigationRequestType.Remove) + { + RemoveRequest(sender, e); + } + UpdateHasBackButton(); + } + + void RemoveRequest(object? sender, Internals.NavigationRequestedEventArgs request) + { + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + var nativePage = request.Page.ToPlatform(MauiContext); + if (nativePage == null) + { + request.Task = Task.FromException(new ArgumentException("Can't found page on stack", nameof(request.Page))); + return; + } + _viewStack.Remove(nativePage); + request.Task = Task.FromResult(true); + } + + void PopRequest(object? sender, Internals.NavigationRequestedEventArgs request) + { + _viewStack.Pop(); + request.Task = Task.FromResult(true); + } + + void PopToRootRequest(object? sender, Internals.NavigationRequestedEventArgs request) + { + _viewStack.PopToRoot(); + request.Task = Task.FromResult(true); + } + + void PushRequest(object? sender, Internals.NavigationRequestedEventArgs request) + { + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + var nativePage = request.Page.ToPlatform(MauiContext); + _viewStack.Push(nativePage); + request.Task = Task.FromResult(true); + Application.Current?.Dispatcher.Dispatch(() => + { + (nativePage as Widget)?.SetFocus(true); + }); + } + + void InsertRequest(object? sender, Internals.NavigationRequestedEventArgs request) + { + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + var before = request.BeforePage.ToPlatform(MauiContext); + if (before == null) + { + request.Task = Task.FromException(new ArgumentException("Can't found page on stack", nameof(request.BeforePage))); + return; + } + var page = request.Page.ToPlatform(MauiContext); + _viewStack.Insert(before, page); + request.Task = Task.FromResult(true); + } + + void UpdateHasBackButton() + { + if (_navBar == null) + return; + + if (_viewStack.Stack.Count > 1) + _navBar.HasBackButton = true; + else + _navBar.HasBackButton = false; + } + + void OnLayout() + { + if (Geometry.Width == 0 || Geometry.Height == 0) + return; + + var bound = Geometry; + int navBarHeight; + if (NavBarIsVisible) + { + var navBound = bound; + navBarHeight = DPExtensions.ConvertToScaledPixel(_navBar.GetDefaultNavBarHeight()); + navBound.Height = navBarHeight; + + if (_navBar != null) + { + _navBar.Show(); + _navBar.Geometry = navBound; + _navBar.RaiseTop(); + } + } + else + { + navBarHeight = 0; + _navBar?.Hide(); + } + + bound.Y += navBarHeight; + bound.Height -= navBarHeight; + _viewStack.Geometry = bound; + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ShellView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ShellView.cs new file mode 100644 index 0000000000..bde90036b6 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ShellView.cs @@ -0,0 +1,427 @@ +#nullable enable + +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using ElmSharp; +using Microsoft.Extensions.DependencyInjection; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using EBox = ElmSharp.Box; +using EColor = ElmSharp.Color; +using ITNavigationView = Tizen.UIExtensions.ElmSharp.INavigationView; +using TCollectionView = Tizen.UIExtensions.ElmSharp.CollectionView; +using TImage = Tizen.UIExtensions.ElmSharp.Image; +using TNavigationView = Tizen.UIExtensions.ElmSharp.NavigationView; +using TSelectedItemChangedEventArgs = Tizen.UIExtensions.ElmSharp.SelectedItemChangedEventArgs; +using TThemeConstants = Tizen.UIExtensions.ElmSharp.ThemeConstants; +using TDPExtensions = Tizen.UIExtensions.ElmSharp.DPExtensions; + +namespace Microsoft.Maui.Controls.Platform +{ + public class ShellView : EBox, IFlyoutBehaviorObserver + { + public static readonly EColor DefaultBackgroundColor = TThemeConstants.Shell.ColorClass.DefaultBackgroundColor; + public static readonly EColor DefaultForegroundColor = TThemeConstants.Shell.ColorClass.DefaultForegroundColor; + public static readonly EColor DefaultTitleColor = TThemeConstants.Shell.ColorClass.DefaultTitleColor; + + INavigationDrawer _navigationDrawer; + ITNavigationView _navigationView; + FlyoutHeaderBehavior _headerBehavior; + + List>? _cachedGroups; + + View? _headerView; + View? _footerView; + TCollectionView _itemsView; + + Element? _lastSelected; + ShellItemView? _currentShellItem; + + public ShellView(EvasObject parent) : base(parent) + { + NativeParent = parent; + _navigationDrawer = CreateNavigationDrawer(); + _navigationView = CreateNavigationView(); + _navigationView.LayoutUpdated += OnNavigationViewLayoutUpdated; + _navigationView.Content = _itemsView = CreateItemsView(); + + _navigationDrawer.NavigationView = _navigationView.TargetView; + _navigationDrawer.Toggled += OnDrawerToggled; + + _navigationDrawer.TargetView.SetAlignment(-1.0, -1.0); + _navigationDrawer.TargetView.SetWeight(1.0, 1.0); + _navigationDrawer.TargetView.Show(); + PackEnd(_navigationDrawer.TargetView); + } + + public IMauiContext? MauiContext { get; private set; } + + protected EvasObject? NativeParent { get; private set; } + + protected Shell? Element { get; private set; } + + protected TCollectionView ItemsView => _itemsView; + + protected ITNavigationView NavigationView => _navigationView; + + protected bool HeaderOnMenu => _headerBehavior == FlyoutHeaderBehavior.Scroll || _headerBehavior == FlyoutHeaderBehavior.CollapseOnScroll; + + public virtual void SetElement(Shell shell, IMauiContext context) + { + Element = shell; + Element.PropertyChanged += OnElementPropertyChanged; + MauiContext = context; + + ((IShellController)Element).StructureChanged += OnShellStructureChanged; + _lastSelected = null; + + UpdateFlyoutIsPresented(); + UpdateFlyoutBackgroundColor(); + UpdateFlyoutBackgroundImage(); + UpdateCurrentItem(); + UpdateFlyoutHeader(); + UpdateFooter(); + } + + protected virtual ShellItemView CreateShellItemView(ShellItem item) + { + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + return new ShellItemView(item, MauiContext); + } + + protected virtual INavigationDrawer CreateNavigationDrawer() + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + + return new NavigationDrawer(NativeParent); + } + + protected virtual ITNavigationView CreateNavigationView() + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + + return new TNavigationView(NativeParent); + } + + protected virtual TCollectionView CreateItemsView() + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + + return new TCollectionView(NativeParent) + { + AlignmentX = -1, + AlignmentY = -1, + WeightX = 1, + WeightY = 1, + SelectionMode = CollectionViewSelectionMode.Single, + HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible, + VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible, + LayoutManager = new LinearLayoutManager(false, Tizen.UIExtensions.ElmSharp.ItemSizingStrategy.MeasureFirstItem) + }; + } + + protected virtual ItemAdaptor GetItemAdaptor(IEnumerable items) + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + return new ShellFlyoutItemAdaptor(Element, MauiContext, items, HeaderOnMenu); + } + + protected virtual void OnElementPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == Shell.CurrentItemProperty.PropertyName) + { + UpdateCurrentItem(); + } + else if (e.PropertyName == Shell.FlyoutIsPresentedProperty.PropertyName) + { + UpdateFlyoutIsPresented(); + } + else if (e.PropertyName == Shell.FlyoutBackgroundColorProperty.PropertyName) + { + UpdateFlyoutBackgroundColor(); + } + else if (e.PropertyName == Shell.FlyoutBackgroundImageProperty.PropertyName) + { + UpdateFlyoutBackgroundImage(); + } + else if (e.PropertyName == Shell.FlyoutBackgroundImageProperty.PropertyName) + { + UpdateFlyoutBackgroundImageAspect(); + } + else if (e.PropertyName == Shell.FlyoutHeaderProperty.PropertyName) + { + UpdateFlyoutHeader(); + } + else if (e.PropertyName == Shell.FlyoutHeaderTemplateProperty.PropertyName) + { + UpdateFlyoutHeader(); + } + else if (e.PropertyName == Shell.FlyoutHeaderBehaviorProperty.PropertyName) + { + UpdateFlyoutHeader(); + } + else if (e.PropertyName == Shell.FlyoutFooterProperty.PropertyName) + { + UpdateFooter(); + } + } + + protected virtual void UpdateFlyoutIsPresented() + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + + // It is workaround of Panel.IsOpen bug, Panel.IsOpen property is not working when layouting was triggered + Application.Current?.Dispatcher.Dispatch(() => + { + _navigationDrawer.IsOpen = Element.FlyoutIsPresented; + }); + } + + protected void OnDrawerToggled(object? sender, EventArgs e) + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + + Element.SetValueFromRenderer(Shell.FlyoutIsPresentedProperty, _navigationDrawer.IsOpen); + } + + protected virtual void UpdateFlyoutBehavior() + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + + _navigationDrawer.DrawerBehavior = Element.FlyoutBehavior.ToPlatform(); + } + + protected virtual void BuildMenu() + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + + var groups = ((IShellController)Element).GenerateFlyoutGrouping(); + + if (!IsItemChanged(groups) && !HeaderOnMenu) + return; + + _cachedGroups = groups; + + var items = new List(); + + foreach (var group in groups) + { + bool isFirst = true; + foreach (var item in group) + { + items.Add(item); + + // TODO: implements separator + if (isFirst) + isFirst = false; + } + } + + ItemsView.Adaptor = GetItemAdaptor(items); + ItemsView.Adaptor.ItemSelected += OnItemSelected; + } + + protected virtual void UpdateFlyoutHeader() + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + if (_headerView != null) + { + _headerView.MeasureInvalidated -= OnHeaderSizeChanged; + _headerView = null; + } + + _headerView = (Element as IShellController).FlyoutHeader; + _headerBehavior = Element.FlyoutHeaderBehavior; + + BuildMenu(); + + if (_headerView != null) + { + if (HeaderOnMenu) + { + _navigationView.Header = null; + } + else + { + _navigationView.Header = _headerView.ToPlatform(MauiContext); + _headerView.MeasureInvalidated += OnHeaderSizeChanged; + } + } + else + { + _navigationView.Header = null; + } + } + + protected virtual void UpdateFooter() + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + if (_footerView != null) + { + _footerView.MeasureInvalidated -= OnFooterSizeChanged; + _footerView = null; + } + + _footerView = (Element as IShellController).FlyoutFooter; + + if (_footerView != null) + { + _navigationView.Footer = _footerView.ToPlatform(MauiContext); + _footerView.MeasureInvalidated += OnFooterSizeChanged; + } + else + { + _navigationView.Footer = null; + } + } + + void OnShellStructureChanged(object? sender, EventArgs e) + { + BuildMenu(); + } + + void OnItemSelected(object? sender, TSelectedItemChangedEventArgs e) + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + + _lastSelected = e.SelectedItem as Element; + ((IShellController)Element).OnFlyoutItemSelected(_lastSelected); + } + + bool IsItemChanged(List> groups) + { + if (_cachedGroups == null) + return true; + + if (_cachedGroups.Count != groups.Count) + return true; + + for (int i = 0; i < groups.Count; i++) + { + if (_cachedGroups[i].Count != groups[i].Count) + return true; + + for (int j = 0; j < groups[i].Count; j++) + { + if (_cachedGroups[i][j] != groups[i][j]) + return true; + } + } + + _cachedGroups = groups; + return false; + } + + void UpdateCurrentItem() + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + + _currentShellItem?.Dispose(); + if (Element.CurrentItem != null) + { + _currentShellItem = CreateShellItemView(Element.CurrentItem); + _navigationDrawer.Main = _currentShellItem.NativeView; + } + else + { + _navigationDrawer.Main = null; + } + } + + void UpdateFlyoutBackgroundColor() + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + + _navigationView.BackgroundColor = Element.FlyoutBackgroundColor.ToPlatformEFL(); + } + + async void UpdateFlyoutBackgroundImage() + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + _ = MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + if (Element.FlyoutBackgroundImage != null) + { + var image = new TImage(NativeParent); + var imageSource = Element.FlyoutBackgroundImage; + var provider = MauiContext.Services.GetRequiredService(); + var service = provider.GetRequiredImageSourceService(imageSource); + image.Aspect = Element.FlyoutBackgroundImageAspect.ToPlatform(); + _navigationView.BackgroundImage = image; + + await service.GetImageAsync(imageSource, image); + } + else + { + _navigationView.BackgroundImage = null; + } + } + + void UpdateFlyoutBackgroundImageAspect() + { + _ = Element ?? throw new InvalidOperationException($"{nameof(Element)} should have been set by base class."); + + if (_navigationView.BackgroundImage is TImage image) + { + image.Aspect = Element.FlyoutBackgroundImageAspect.ToPlatform(); + } + } + + void OnNavigationViewLayoutUpdated(object? sender, LayoutEventArgs args) + { + UpdateHeaderLayout(args.Geometry.Width, args.Geometry.Height); + UpdateFooterLayout(args.Geometry.Width, args.Geometry.Height); + } + + void OnHeaderSizeChanged(object? sender, EventArgs e) + { + var bound = (_navigationView as EvasObject)?.Geometry; + Application.Current?.Dispatcher.Dispatch(()=> { + UpdateHeaderLayout((bound?.Width).GetValueOrDefault(), (bound?.Height).GetValueOrDefault()); + }); + } + + void OnFooterSizeChanged(object? sender, EventArgs e) + { + var bound = (_navigationView as EvasObject)?.Geometry; + Application.Current?.Dispatcher.Dispatch(() => { + UpdateFooterLayout((bound?.Width).GetValueOrDefault(), (bound?.Height).GetValueOrDefault()); + }); + } + + void UpdateHeaderLayout(double widthConstraint, double heightConstraint) + { + if ((!HeaderOnMenu) && (_headerView != null)) + { + var requestSize = _headerView.Measure(widthConstraint, heightConstraint); + if(_navigationView.Header != null) + _navigationView.Header.MinimumHeight = TDPExtensions.ConvertToScaledPixel(requestSize.Request.Height); + } + } + + void UpdateFooterLayout(double widthConstraint, double heightConstraint) + { + if (_footerView != null) + { + var requestSize = _footerView.Measure(widthConstraint, heightConstraint); + if (_navigationView.Footer != null) + _navigationView.Footer.MinimumHeight = TDPExtensions.ConvertToScaledPixel(requestSize.Request.Height); + } + } + + void IFlyoutBehaviorObserver.OnFlyoutBehaviorChanged(FlyoutBehavior behavior) + { + UpdateFlyoutBehavior(); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/SimpleViewStack.cs b/src/Controls/src/Core/Platform/Tizen/Shell/SimpleViewStack.cs new file mode 100644 index 0000000000..3114f02108 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/SimpleViewStack.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using System.Linq; +using ElmSharp; +using EBox = ElmSharp.Box; + +namespace Microsoft.Maui.Controls.Platform +{ + public class SimpleViewStack : EBox + { + EvasObject _lastTop; + + public SimpleViewStack(EvasObject parent) : base(parent) + { + InternalStack = new List(); + SetLayoutCallback(OnLayout); + } + + List InternalStack { get; set; } + + public IReadOnlyList Stack => InternalStack; + + public void Push(EvasObject view) + { + InternalStack.Add(view); + PackEnd(view); + UpdateTopView(); + } + + public void Pop() + { + if (_lastTop != null) + { + var tobeRemoved = _lastTop; + InternalStack.Remove(tobeRemoved); + UnPack(tobeRemoved); + UpdateTopView(); + // if Pop was called by removed page, + // Unrealize cause deletation of NativeCallback, it could be a cause of crash + Application.Current?.Dispatcher.Dispatch(() => + { + tobeRemoved.Unrealize(); + }); + } + } + + public void PopToRoot() + { + while (InternalStack.Count > 1) + { + Pop(); + } + } + + public void Insert(EvasObject before, EvasObject view) + { + view.Hide(); + var idx = InternalStack.IndexOf(before); + InternalStack.Insert(idx, view); + PackEnd(view); + UpdateTopView(); + } + + public void Remove(EvasObject view) + { + InternalStack.Remove(view); + UnPack(view); + UpdateTopView(); + Application.Current?.Dispatcher.Dispatch(() => + { + view?.Unrealize(); + }); + } + + void UpdateTopView() + { + if (_lastTop != InternalStack.LastOrDefault()) + { + _lastTop?.Hide(); + _lastTop = InternalStack.LastOrDefault(); + _lastTop.Show(); + (_lastTop as Widget)?.SetFocus(true); + } + } + + void OnLayout() + { + foreach (var view in Stack) + { + view.Geometry = Geometry; + } + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/TVShellItemAdaptor.cs b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellItemAdaptor.cs new file mode 100644 index 0000000000..dcaa6d41e8 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellItemAdaptor.cs @@ -0,0 +1,358 @@ +#nullable enable + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using ElmSharp; +using Microsoft.Maui.Controls.Internals; +using Tizen.UIExtensions.ElmSharp; +using ITNavigtaionView = Tizen.UIExtensions.ElmSharp.INavigationView; +using TViewHolderState = Tizen.UIExtensions.ElmSharp.ViewHolderState; +using DPExtensions = Tizen.UIExtensions.ElmSharp.DPExtensions; + +namespace Microsoft.Maui.Controls.Platform +{ + public class TVShellItemAdaptor : ItemAdaptor + { + Dictionary _nativeFormsTable = new Dictionary(); + Dictionary _dataBindedViewTable = new Dictionary(); + + Element _element; + IMauiContext _context; + ITNavigtaionView? _navigationView; + + protected virtual bool IsSelectable { get; } + + public DataTemplate DefaultTemplate { get; private set; } + + public TVShellItemAdaptor(Element element, ITNavigtaionView? nv, IMauiContext context, IEnumerable items, bool isCollapsed) : base(items) + { + _element = element; + _context = context; + _navigationView = nv; + IsSelectable = true; + DefaultTemplate = CreateDafaultTemplate(nv, isCollapsed); + } + + public override EvasObject? CreateNativeView(EvasObject parent) + { + return CreateNativeView(0, parent); + } + + public override EvasObject? CreateNativeView(int index, EvasObject parent) + { + View? view = GetTemplatedView(index); + if (view != null) + { + var native = view.ToPlatform(_context); + _nativeFormsTable[native] = view; + return native; + } + + return null; + } + + public override EvasObject? GetFooterView(EvasObject parent) + { + return null; + } + + public override EvasObject? GetHeaderView(EvasObject parent) + { + return null; + } + + public override Size MeasureFooter(int widthConstraint, int heightConstraint) + { + return new Size(0, 0); + } + + public override Size MeasureHeader(int widthConstraint, int heightConstraint) + { + return new Size(0, 0); + } + + public override Size MeasureItem(int widthConstraint, int heightConstraint) + { + return MeasureItem(0, widthConstraint, heightConstraint); + } + + public override Size MeasureItem(int index, int widthConstraint, int heightConstraint) + { + View? view = GetTemplatedView(index); + if (view != null) + { + var native = view.ToPlatform(_context); + view.Parent = _element; + + if (Count > index) + view.BindingContext = this[index]; + + var size = view.Measure(DPExtensions.ConvertToScaledDP(widthConstraint), DPExtensions.ConvertToScaledDP(heightConstraint), MeasureFlags.IncludeMargins).Request; + native.Unrealize(); + + return size.ToEFLPixel(); + } + + return new Size(0, 0); + } + + public override void RemoveNativeView(EvasObject native) + { + native?.Unrealize(); + } + + public override void SetBinding(EvasObject native, int index) + { + if (_nativeFormsTable.TryGetValue(native, out View? view)) + { + ResetBindedView(view); + var item = this[index]; + view.BindingContext = item; + if (item != null) + _dataBindedViewTable[item] = view; + + view.MeasureInvalidated += OnItemMeasureInvalidated; + view.Parent = _element; + } + } + + public override void UnBinding(EvasObject native) + { + if (_nativeFormsTable.TryGetValue(native, out View? view)) + { + view.MeasureInvalidated -= OnItemMeasureInvalidated; + ResetBindedView(view); + } + } + + public override void UpdateViewState(EvasObject native, TViewHolderState state) + { + base.UpdateViewState(native, state); + if (_nativeFormsTable.TryGetValue(native, out View? view)) + { + switch (state) + { + case TViewHolderState.Focused: + VisualStateManager.GoToState(view, VisualStateManager.CommonStates.Focused); + view.SetValue(VisualElement.IsFocusedPropertyKey, true); + break; + case TViewHolderState.Normal: + VisualStateManager.GoToState(view, VisualStateManager.CommonStates.Normal); + view.SetValue(VisualElement.IsFocusedPropertyKey, false); + break; + case TViewHolderState.Selected: + if (IsSelectable) + VisualStateManager.GoToState(view, VisualStateManager.CommonStates.Selected); + break; + } + } + } + + DataTemplate CreateDafaultTemplate(ITNavigtaionView? nv, bool isCollapsed) + { + return new DataTemplate(() => + { + var grid = new Grid + { + HeightRequest = nv.GetTvFlyoutItemHeight(), + WidthRequest = nv.GetTvFlyoutItemWidth(), + BackgroundColor = Graphics.Colors.Transparent + }; + + ColumnDefinitionCollection columnDefinitions = new ColumnDefinitionCollection(); + columnDefinitions.Add(new ColumnDefinition { Width = nv.GetTvFlyoutIconColumnSize() }); + columnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star }); + grid.ColumnDefinitions = columnDefinitions; + + var image = new Image + { + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Center, + HeightRequest = nv.GetTvFlyoutIconSize(), + WidthRequest = nv.GetTvFlyoutIconSize(), + Margin = new Thickness(nv.GetTvFlyoutMargin(), 0, 0, 0), + }; + image.SetBinding(Image.SourceProperty, new Binding("FlyoutIcon")); + grid.Add(image); + grid.SetColumn(image, 0); + + var label = new Label + { + FontSize = nv.GetTvFlyoutItemFontSize(), + VerticalTextAlignment = TextAlignment.Center, + Margin = new Thickness(nv.GetTvFlyoutMargin(), 0, 0, 0), + }; + + label.SetBinding(Label.TextProperty, new Binding("Title")); + label.SetBinding(Label.TextColorProperty, new Binding("BackgroundColor", converter: new TextColorConverter(), source: grid)); + + if (isCollapsed) + { + label.Opacity = 0; + label.SetBinding(Label.OpacityProperty, new Binding("Width", converter: new OpacityConverter(label.Opacity), source: label)); + } + + grid.Add(label); + grid.SetColumn(label, 1); + + var groups = new VisualStateGroupList(); + + var commonGroup = new VisualStateGroup(); + commonGroup.Name = "CommonStates"; + groups.Add(commonGroup); + + var normalState = new VisualState(); + normalState.Name = "Normal"; + normalState.Setters.Add(new Setter + { + Property = VisualElement.BackgroundColorProperty, + Value = nv.GetTvFlyoutItemColor(), + }); + + var focusedState = new VisualState(); + focusedState.Name = "Focused"; + focusedState.Setters.Add(new Setter + { + Property = VisualElement.BackgroundColorProperty, + Value = nv.GetTvFlyoutItemFocusedColor() + }); + + var selectedState = new VisualState(); + selectedState.Name = "Selected"; + selectedState.Setters.Add(new Setter + { + Property = VisualElement.BackgroundColorProperty, + Value = nv.GetTvFlyoutItemColor() + }); + + commonGroup.States.Add(normalState); + commonGroup.States.Add(focusedState); + commonGroup.States.Add(selectedState); + + VisualStateManager.SetVisualStateGroups(grid, groups); + return grid; + }); + } + + View? GetTemplatedView(int index) + { + var dataTemplate = DefaultTemplate; + var item = this[index]; + if (item is BindableObject bo) + { + dataTemplate = (_element as IShellController)?.GetFlyoutItemDataTemplate(bo); + if (dataTemplate != null) + { + if (item is IMenuItemController) + { + if (_element is Shell shell && shell.MenuItemTemplate != dataTemplate) + dataTemplate = DefaultTemplate; + } + else + { + if (_element is Shell shell && shell.ItemTemplate != dataTemplate) + dataTemplate = DefaultTemplate; + } + } + else + { + dataTemplate = DefaultTemplate; + } + } + + var view = dataTemplate.SelectDataTemplate(this[index], _element).CreateContent() as View; + return view; + } + + void ResetBindedView(View view) + { + if (view.BindingContext != null && _dataBindedViewTable.ContainsKey(view.BindingContext)) + { + _dataBindedViewTable[view.BindingContext] = null; + view.Parent = null; + view.BindingContext = null; + } + } + + void OnItemMeasureInvalidated(object? sender, EventArgs e) + { + var data = (sender as View)?.BindingContext ?? null; + if (data != null) + { + int index = GetItemIndex(data); + if (index != -1) + { + CollectionView?.ItemMeasureInvalidated(index); + } + } + } + + class TextColorConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is Graphics.Color c && c == Graphics.Colors.Transparent) + { + return Graphics.Colors.White; + } + else + { + return Graphics.Colors.Black; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is Graphics.Color c && c == Graphics.Colors.White) + { + return Graphics.Colors.Transparent; + } + else + { + return Graphics.Colors.Black; + } + } + } + + class OpacityConverter : IValueConverter + { + double _opacity; + double _itemWidth = -1; + + public OpacityConverter(double opacity) + { + _opacity = opacity; + } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var width = (double)value; + + if (_itemWidth == -1) + { + _itemWidth = width; + return _opacity; + } + + _itemWidth = (_itemWidth < width) ? width : _itemWidth; + return ((width / _itemWidth) > 1) ? 1 : (width / _itemWidth); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + var width = (double)value; + + if (_itemWidth == -1) + { + _itemWidth = width; + return _opacity; + } + + _itemWidth = (_itemWidth < width) ? width : _itemWidth; + return width * _itemWidth; + } + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/TVShellItemView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellItemView.cs new file mode 100644 index 0000000000..4662d3232e --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellItemView.cs @@ -0,0 +1,18 @@ +namespace Microsoft.Maui.Controls.Platform +{ + public class TVShellItemView : ShellItemView + { + public TVShellItemView(ShellItem item, IMauiContext context) : base(item, context) + { + } + + protected override ShellSectionStack CreateShellSectionStack(ShellSection section) + { + return new TVShellSectionStack(section, MauiContext); + } + + protected override void UpdateTabsItems() + { + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/TVShellSectionHandler.cs b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellSectionHandler.cs new file mode 100644 index 0000000000..8ea8f90330 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellSectionHandler.cs @@ -0,0 +1,285 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using ElmSharp; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using EBox = ElmSharp.Box; +using TCollectionView = Tizen.UIExtensions.ElmSharp.CollectionView; +using TNavigationView = Tizen.UIExtensions.ElmSharp.NavigationView; +using ITCollectionViewController = Tizen.UIExtensions.ElmSharp.ICollectionViewController; +using TSelectedItemChangedEventArgs = Tizen.UIExtensions.ElmSharp.SelectedItemChangedEventArgs; + + +namespace Microsoft.Maui.Controls.Platform +{ + public class TVShellSectionHandler : IShellSectionHandler, IDisposable + { + EBox _mainLayout; + EBox _contentArea; + EvasObject? _currentContent = null; + + TNavigationView? _navigationView; + TCollectionView? _itemsView; + + IList? _cachedItems; + Dictionary _contentCache = new Dictionary(); + + bool _disposed = false; + + bool _drawerIsVisible => (ShellSection != null) ? (ShellSection.Items.Count > 1) : false; + + public TVShellSectionHandler(ShellSection section, IMauiContext context) + { + ShellSection = section; + MauiContext = context; + ShellSection.PropertyChanged += OnSectionPropertyChanged; + if (ShellSection.Items is INotifyCollectionChanged collection) + { + collection.CollectionChanged += OnShellSectionCollectionChanged; + } + + _mainLayout = new EBox(NativeParent); + _mainLayout.SetLayoutCallback(OnLayout); + + _contentArea = new EBox(NativeParent); + _contentArea.Show(); + _mainLayout.PackEnd(_contentArea); + + UpdateSectionItems(); + UpdateCurrentItem(ShellSection.CurrentItem); + } + + public ShellSection ShellSection { get; } + + public EvasObject PlatformView + { + get + { + return _mainLayout; + } + } + + protected IMauiContext MauiContext { get; private set; } + + protected TCollectionView? ItemsView => _itemsView; + + protected EvasObject? NativeParent + { + get => MauiContext.GetNativeParent(); + } + + ~TVShellSectionHandler() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + if (ShellSection != null) + { + ShellSection.PropertyChanged -= OnSectionPropertyChanged; + } + + PlatformView.Unrealize(); + } + _disposed = true; + } + + protected virtual TCollectionView CreateItemsView() + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + + return new TCollectionView(NativeParent) + { + AlignmentX = -1, + AlignmentY = -1, + WeightX = 1, + WeightY = 1, + SelectionMode = CollectionViewSelectionMode.Single, + HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible, + VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible, + LayoutManager = new LinearLayoutManager(false) + }; + } + + void OnNavigationViewSelectedItemChanged(object sender, ItemSelectedEventArgs e) + { + if (e.SelectedItem == null) + return; + + var content = e.SelectedItem; + if (ShellSection.CurrentItem != content) + { + ShellSection.SetValueFromRenderer(ShellSection.CurrentItemProperty, content); + } + } + + void OnSectionPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == ShellSection.CurrentItemProperty.PropertyName) + { + UpdateCurrentItem(ShellSection.CurrentItem); + } + } + + void UpdateSectionItems() + { + if (!_drawerIsVisible) + { + return; + } + + if (_navigationView == null && NativeParent != null) + { + _navigationView = new TVNavigationView(NativeParent); + _navigationView.SetAlignment(-1, -1); + _navigationView.SetWeight(1, 1); + _navigationView.Show(); + _mainLayout.PackStart(_navigationView); + + _navigationView.LayoutUpdated += (s, e) => + { + var drawerBound = e.Geometry; + var drawerWidth = GetDrawerWidth(); + }; + + _navigationView.Content = _itemsView = CreateItemsView(); + } + + BuildMenu(); + } + + bool IsItemChanged(IList items) + { + if (_cachedItems == null) + return true; + + if (_cachedItems.Count != items.Count) + return true; + + for (int i = 0; i < items.Count; i++) + { + if (_cachedItems[i] != items[i]) + return true; + } + + _cachedItems = items; + return false; + } + + void BuildMenu() + { + var items = ShellSection.Items; + + if (!IsItemChanged(items)) + return; + + _cachedItems = items; + + if (ItemsView != null) + { + ItemsView.Adaptor = new TVShellItemAdaptor(ShellSection, _navigationView, MauiContext, items, false); + ItemsView.Adaptor.ItemSelected += OnItemSelected; + } + } + + void UpdateCurrentItem(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.ToPlatform(MauiContext); + } + + void OnLayout() + { + if (PlatformView.Geometry.Width == 0 || PlatformView.Geometry.Height == 0) + return; + + var bound = PlatformView.Geometry; + var drawerWidth = 0; + + if (_drawerIsVisible && _navigationView != null) + { + var drawerBound = bound; + drawerWidth = GetDrawerWidth(); + drawerBound.Width = drawerWidth; + + _navigationView.Geometry = drawerBound; + } + + var contentBound = bound; + + contentBound.X += drawerWidth; + contentBound.Width -= drawerWidth; + _contentArea.Geometry = contentBound; + } + + int GetDrawerWidth() + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + + int width = 0; + if (ItemsView is ITCollectionViewController controller) + width = controller.GetItemSize((NativeParent.Geometry.Width / 2), NativeParent.Geometry.Height).Width; + + return width; + } + + void OnItemSelected(object? sender, TSelectedItemChangedEventArgs e) + { + if (e.SelectedItem == null) + return; + + var content = e.SelectedItem; + if (ShellSection.CurrentItem != content) + { + ShellSection.SetValueFromRenderer(ShellSection.CurrentItemProperty, content); + } + } + + void OnShellSectionCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + UpdateSectionItems(); + } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/TVShellSectionStack.cs b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellSectionStack.cs new file mode 100644 index 0000000000..6b60ac79db --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellSectionStack.cs @@ -0,0 +1,16 @@ +namespace Microsoft.Maui.Controls.Platform +{ + public class TVShellSectionStack : ShellSectionStack + { + public TVShellSectionStack(ShellSection section, IMauiContext context) : base(section, context) + { + } + + public override bool NavBarIsVisible => false; + + protected override IShellSectionHandler CreateShellSectionView(ShellSection section) + { + return new TVShellSectionHandler(section, MauiContext); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/TVShellView.cs b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellView.cs new file mode 100644 index 0000000000..9ebaada57e --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/TVShellView.cs @@ -0,0 +1,43 @@ +using System.Collections; +using ElmSharp; +using Microsoft.Maui.Graphics; +using Tizen.UIExtensions.ElmSharp; +using ITNavigationView = Tizen.UIExtensions.ElmSharp.INavigationView; + +namespace Microsoft.Maui.Controls.Platform +{ + public class TVShellView : ShellView + { + public TVShellView(EvasObject parent) : base(parent) + { + } + + public override void SetElement(Shell shell, IMauiContext context) + { + base.SetElement(shell, context); + + // Workaround to set to use a default color for TV different from the mobile + shell.SetAppThemeColor(Shell.FlyoutBackgroundColorProperty, Colors.Black, Colors.Black); + } + + protected override INavigationDrawer CreateNavigationDrawer() + { + return new TVNavigationDrawer(NativeParent); + } + + protected override ITNavigationView CreateNavigationView() + { + return new TVNavigationView(NativeParent); + } + + protected override ShellItemView CreateShellItemView(ShellItem item) + { + return new TVShellItemView(item, MauiContext); + } + + protected override ItemAdaptor GetItemAdaptor(IEnumerable items) + { + return new TVShellItemAdaptor(Element, NavigationView, MauiContext, items, !Element.FlyoutIsPresented); + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ThemeConstants.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ThemeConstants.cs new file mode 100644 index 0000000000..a4f602b6fb --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ThemeConstants.cs @@ -0,0 +1,43 @@ +namespace Microsoft.Maui.Controls.Platform +{ + public class ThemeConstants + { + public class Shell + { + public class Resources + { + public const int DefaultMargin = 10; + public const int DefaultNavBarHeight = 70; + public const int DefaultMenuSize = 40; + + public const int DefaultTitleFontSize = 23; + public const int DefaultTitleMargin = 23; + + public const int DefaultIconSize = 30; + public const int DefaultIconPadding = 15; + + public const int DefaultFlyoutItemHeight = 60; + public const int DefaultFlyoutItemWidth = 250; + + public class TV + { + public const int DefaultMenuSize = 70; + + public const int DefaultFlyoutIconColumnSize = 40; + public const int DefaultFlyoutIconSize = 25; + + public const int DefaultFlyoutItemfontSize = 25; + } + } + + public class ColorClass + { + public class TV + { + public static readonly Graphics.Color DefaultFlyoutItemColor = Graphics.Colors.Transparent; + public static readonly Graphics.Color DefaultFlyoutItemFocusedColor = new Graphics.Color(0.95f); + } + } + } + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/Shell/ThemeManager.cs b/src/Controls/src/Core/Platform/Tizen/Shell/ThemeManager.cs new file mode 100644 index 0000000000..a7886b4d83 --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/Shell/ThemeManager.cs @@ -0,0 +1,130 @@ +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using ITNavigtaionView = Tizen.UIExtensions.ElmSharp.INavigationView; + +namespace Microsoft.Maui.Controls.Platform +{ + public static class ThemeManager + { + #region ShellMoreTabs + static double s_shellMoreToolBarIconPadding = -1; + public static double GetDefaultIconPadding(this ShellMoreTabs self) + { + if (s_shellMoreToolBarIconPadding > 0) + return s_shellMoreToolBarIconPadding; + return s_shellMoreToolBarIconPadding = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.DefaultIconPadding); + } + + static double s_shellMoreToolBarIconSize = -1; + public static double GetDefaultIconSize(this ShellMoreTabs self) + { + if (s_shellMoreToolBarIconSize > 0) + return s_shellMoreToolBarIconSize; + return s_shellMoreToolBarIconSize = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.DefaultIconSize); + } + #endregion + + #region ShellNavBar + static double s_shellNavBarDefaultHeight = -1; + public static double GetDefaultNavBarHeight(this ShellNavBar navBar) + { + if (s_shellNavBarDefaultHeight > 0) + return s_shellNavBarDefaultHeight; + return s_shellNavBarDefaultHeight = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.DefaultNavBarHeight); + } + + static double s_shellNavBarDefaultMenuSize = -1; + public static double GetDefaultMenuSize(this ShellNavBar navBar) + { + if (s_shellNavBarDefaultMenuSize > 0) + return s_shellNavBarDefaultMenuSize; + return s_shellNavBarDefaultMenuSize = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen( + Microsoft.Maui.Devices.DeviceInfo.Idiom == Microsoft.Maui.Devices.DeviceIdiom.TV ? ThemeConstants.Shell.Resources.TV.DefaultMenuSize : ThemeConstants.Shell.Resources.DefaultMenuSize); + } + + static double s_shellNavBarDefaultMargin = -1; + public static double GetDefaultMargin(this ShellNavBar navBar) + { + if (s_shellNavBarDefaultMargin > 0) + return s_shellNavBarDefaultMargin; + return s_shellNavBarDefaultMargin = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.DefaultMargin); + } + + static double s_shellNavBarTitleVDefaultMargin = -1; + public static double GetDefaultTitleVMargin(this ShellNavBar navBar) + { + if (s_shellNavBarTitleVDefaultMargin > 0) + return s_shellNavBarTitleVDefaultMargin; + return s_shellNavBarTitleVDefaultMargin = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.DefaultTitleMargin); + } + + static double s_shellNavBarTitleFontSize = -1; + public static double GetDefaultTitleFontSize(this ShellNavBar navBar) + { + if (s_shellNavBarTitleFontSize > 0) + return s_shellNavBarTitleFontSize; + return s_shellNavBarTitleFontSize = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.DefaultTitleFontSize); + } + #endregion + + #region TVShell + static double s_navigationViewFlyoutItemHeight = -1; + public static double GetTvFlyoutItemHeight(this ITNavigtaionView nav) + { + if (s_navigationViewFlyoutItemHeight > 0) + return s_navigationViewFlyoutItemHeight; + return s_navigationViewFlyoutItemHeight = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.DefaultFlyoutItemHeight); + } + + static double s_navigationViewFlyoutItemWidth = -1; + public static double GetTvFlyoutItemWidth(this ITNavigtaionView nav) + { + if (s_navigationViewFlyoutItemWidth > 0) + return s_navigationViewFlyoutItemWidth; + return s_navigationViewFlyoutItemWidth = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.DefaultFlyoutItemWidth); + } + + static double s_navigationViewFlyoutIconColumnSize = -1; + public static double GetTvFlyoutIconColumnSize(this ITNavigtaionView nav) + { + if (s_navigationViewFlyoutIconColumnSize > 0) + return s_navigationViewFlyoutIconColumnSize; + return s_navigationViewFlyoutIconColumnSize = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.TV.DefaultFlyoutIconColumnSize); + } + + static double s_navigationViewFlyoutIconSize = -1; + public static double GetTvFlyoutIconSize(this ITNavigtaionView nav) + { + if (s_navigationViewFlyoutIconSize > 0) + return s_navigationViewFlyoutIconSize; + return s_navigationViewFlyoutIconSize = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.TV.DefaultFlyoutIconSize); + } + + static double s_navigationViewFlyoutMargin = -1; + public static double GetTvFlyoutMargin(this ITNavigtaionView nav) + { + if (s_navigationViewFlyoutMargin > 0) + return s_navigationViewFlyoutMargin; + return s_navigationViewFlyoutMargin = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.DefaultMargin); + } + + static double s_navigationViewFlyoutItemFontSize = -1; + public static double GetTvFlyoutItemFontSize(this ITNavigtaionView nav) + { + if (s_navigationViewFlyoutItemFontSize > 0) + return s_navigationViewFlyoutItemFontSize; + return s_navigationViewFlyoutItemFontSize = DeviceInfo.CalculateDoubleScaledSizeInLargeScreen(ThemeConstants.Shell.Resources.TV.DefaultFlyoutItemfontSize); + } + + public static Graphics.Color GetTvFlyoutItemColor(this ITNavigtaionView nav) + { + return ThemeConstants.Shell.ColorClass.TV.DefaultFlyoutItemColor; + } + + public static Graphics.Color GetTvFlyoutItemFocusedColor(this ITNavigtaionView nav) + { + return ThemeConstants.Shell.ColorClass.TV.DefaultFlyoutItemFocusedColor; + } + #endregion + } +} diff --git a/src/Controls/src/Core/Platform/Tizen/SwipeGestureHandler.cs b/src/Controls/src/Core/Platform/Tizen/SwipeGestureHandler.cs new file mode 100644 index 0000000000..be7f26059e --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/SwipeGestureHandler.cs @@ -0,0 +1,29 @@ +using ElmSharp; + +namespace Microsoft.Maui.Controls.Platform +{ + public class SwipeGestureHandler : GestureHandler + { + public SwipeGestureHandler(IGestureRecognizer recognizer) : base(recognizer) + { + } + + public override GestureLayer.GestureType Type => GestureLayer.GestureType.Flick; + + protected override void OnStarted(View sender, object data) { } + + protected override void OnMoved(View sender, object data) { } + + protected override void OnCompleted(View sender, object data) + { + if (Recognizer is SwipeGestureRecognizer swipeGesture) + { + var lineData = (GestureLayer.LineData)data; + (swipeGesture as ISwipeGestureController)?.SendSwipe(sender, DPExtensions.ConvertToScaledDP(lineData.X2 - lineData.X1), DPExtensions.ConvertToScaledDP(lineData.Y2 - lineData.Y1)); + (swipeGesture as ISwipeGestureController)?.DetectSwipe(sender, swipeGesture.Direction); + } + } + + protected override void OnCanceled(View sender, object data) { } + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Platform/Tizen/TapGestureHandler.cs b/src/Controls/src/Core/Platform/Tizen/TapGestureHandler.cs new file mode 100644 index 0000000000..21ee68ea1e --- /dev/null +++ b/src/Controls/src/Core/Platform/Tizen/TapGestureHandler.cs @@ -0,0 +1,46 @@ +using ElmSharp; + +namespace Microsoft.Maui.Controls.Platform +{ + public class TapGestureHandler : GestureHandler + { + public TapGestureHandler(IGestureRecognizer recognizer) : base(recognizer) + { + } + + public override GestureLayer.GestureType Type + { + get + { + var recognizer = Recognizer as TapGestureRecognizer; + if (recognizer != null) + { + int numberOfTaps = recognizer.NumberOfTapsRequired; + + if (numberOfTaps > 2) + return GestureLayer.GestureType.TripleTap; + else if (numberOfTaps > 1) + return GestureLayer.GestureType.DoubleTap; + } + return GestureLayer.GestureType.Tap; + } + } + + protected override void OnStarted(View sender, object data) + { + } + + protected override void OnMoved(View sender, object data) + { + } + + protected override void OnCompleted(View sender, object data) + { + (Recognizer as TapGestureRecognizer)?.SendTapped(sender); + } + + protected override void OnCanceled(View sender, object data) + { + } + } +} diff --git a/src/Controls/src/Core/Properties/AssemblyInfo.cs b/src/Controls/src/Core/Properties/AssemblyInfo.cs index 484a31f47a..1595f94401 100644 --- a/src/Controls/src/Core/Properties/AssemblyInfo.cs +++ b/src/Controls/src/Core/Properties/AssemblyInfo.cs @@ -10,6 +10,7 @@ using Compatibility = Microsoft.Maui.Controls.Compatibility; [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Android")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.iOS")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Windows")] +[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Tizen")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Core.Design")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Core.UnitTests")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Android.UnitTests")] @@ -20,6 +21,7 @@ using Compatibility = Microsoft.Maui.Controls.Compatibility; [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Maps.iOS")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Maps.iOS.Classic")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Maps.Android")] +[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Maps.Tizen")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Xaml.UnitTests")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.UITests")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.FlexLayout.UnitTests")] diff --git a/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs b/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs index eb09e8c8cb..d27af8969e 100644 --- a/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs +++ b/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs @@ -21,6 +21,8 @@ using Microsoft.Maui.Controls.Compatibility.Platform.UWP; #elif IOS || MACCATALYST using Microsoft.Maui.Controls.Compatibility.Platform.iOS; using Microsoft.Maui.Controls.Handlers.Compatibility; +#elif TIZEN +using Microsoft.Maui.Controls.Compatibility.Platform.Tizen; #endif namespace Microsoft.Maui.Controls.Hosting @@ -111,9 +113,13 @@ namespace Microsoft.Maui.Controls.Hosting handlersCollection.AddHandler(typeof(FlyoutPage), typeof(Handlers.Compatibility.PhoneFlyoutPageRenderer)); #endif -#if ANDROID || IOS || MACCATALYST +#if ANDROID || IOS || MACCATALYST || TIZEN handlersCollection.AddHandler(); +#if ANDROID || IOS || MACCATALYST handlersCollection.AddHandler(); +#else + handlersCollection.AddHandler(); +#endif #endif #if WINDOWS || ANDROID handlersCollection.AddHandler(); @@ -133,7 +139,7 @@ namespace Microsoft.Maui.Controls.Hosting static MauiAppBuilder SetupDefaults(this MauiAppBuilder builder) { -#if WINDOWS || ANDROID || IOS || MACCATALYST +#if WINDOWS || ANDROID || IOS || MACCATALYST || TIZEN // initialize compatibility DependencyService DependencyService.SetToInitialized(); DependencyService.Register(); diff --git a/src/Controls/src/Xaml/SimplifyOnPlatformVisitor.cs b/src/Controls/src/Xaml/SimplifyOnPlatformVisitor.cs index 08ffe825be..2c545e7ddc 100644 --- a/src/Controls/src/Xaml/SimplifyOnPlatformVisitor.cs +++ b/src/Controls/src/Xaml/SimplifyOnPlatformVisitor.cs @@ -60,6 +60,12 @@ namespace Microsoft.Maui.Controls.Xaml if (TargetFramework.Contains("-maccatalyst", StringComparison.Ordinal)) #endif target = nameof(OnPlatformExtension.MacCatalyst); +#if NETSTANDARD2_0 + if (TargetFramework.Contains("-tizen")) +#else + if (TargetFramework.Contains("-tizen", StringComparison.Ordinal)) +#endif + target = nameof(OnPlatformExtension.Tizen); if (target is null) return; diff --git a/src/Core/src/ActivationState.cs b/src/Core/src/ActivationState.cs index 6f313d4f87..7475226bf3 100644 --- a/src/Core/src/ActivationState.cs +++ b/src/Core/src/ActivationState.cs @@ -22,6 +22,12 @@ namespace Microsoft.Maui { LaunchActivatedEventArgs = launchActivatedEventArgs; } +#elif TIZEN + public ActivationState(IMauiContext context, Tizen.Applications.Bundle? savedInstance) + : this(context, GetPersistedState(savedInstance)) + { + SavedInstance = savedInstance; + } #endif public ActivationState(IMauiContext context) @@ -44,6 +50,8 @@ namespace Microsoft.Maui public Android.OS.Bundle? SavedInstance { get; } #elif WINDOWS public UI.Xaml.LaunchActivatedEventArgs? LaunchActivatedEventArgs { get; } +#elif TIZEN + public Tizen.Applications.Bundle? SavedInstance { get; } #endif #if __ANDROID__ @@ -83,6 +91,22 @@ namespace Microsoft.Maui return state; } +#elif TIZEN + static IPersistedState GetPersistedState(Tizen.Applications.Bundle? state) + { + var dict = new PersistedState(); + + var keyset = state?.Keys; + if (keyset != null) + { + foreach (var k in keyset) + { + dict[k] = state?.GetItem(k); + } + } + + return dict; + } #endif } } \ No newline at end of file diff --git a/src/Core/src/Animations/PlatformTicker.Tizen.cs b/src/Core/src/Animations/PlatformTicker.Tizen.cs new file mode 100644 index 0000000000..f88c87a439 --- /dev/null +++ b/src/Core/src/Animations/PlatformTicker.Tizen.cs @@ -0,0 +1,42 @@ +using System.Threading; +using Tizen.Applications; + +namespace Microsoft.Maui.Animations +{ + public class PlatformTicker : Ticker + { + readonly Timer _timer; + readonly SynchronizationContext? _context; + bool _isRunning; + + public override bool IsRunning => _isRunning; + + public PlatformTicker() + { + 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/Core.csproj b/src/Core/src/Core.csproj index 80ef4c3e45..66f78946eb 100644 --- a/src/Core/src/Core.csproj +++ b/src/Core/src/Core.csproj @@ -18,6 +18,9 @@ + + + diff --git a/src/Core/src/Dispatching/Dispatcher.Tizen.cs b/src/Core/src/Dispatching/Dispatcher.Tizen.cs new file mode 100644 index 0000000000..4711b8cc6a --- /dev/null +++ b/src/Core/src/Dispatching/Dispatcher.Tizen.cs @@ -0,0 +1,108 @@ +using System; +using System.Threading; + +namespace Microsoft.Maui.Dispatching +{ + public partial class Dispatcher : IDispatcher + { + readonly SynchronizationContext _context; + + internal Dispatcher(SynchronizationContext context) + { + _context = context; + } + + bool IsDispatchRequiredImplementation() => + _context != SynchronizationContext.Current; + + bool DispatchImplementation(Action action) + { + _context.Post((o) => action(), null); + return true; + } + + bool DispatchDelayedImplementation(TimeSpan delay, Action action) + { + Timer? timer = null; + TimerCallback onTimeout = o => + { + _context.Post((o) => action(), null); + timer?.Dispose(); + }; + timer = new Timer(onTimeout, null, Timeout.Infinite, Timeout.Infinite); + timer?.Change(delay, delay); + return true; + } + + IDispatcherTimer CreateTimerImplementation() + { + return new DispatcherTimer(_context); + } + } + + partial class DispatcherTimer : IDispatcherTimer + { + readonly SynchronizationContext _context; + readonly Timer _timer; + + public DispatcherTimer(SynchronizationContext context) + { + _context = context; + _timer = new Timer((object? state) => _context.Post(OnTimerTick, null), null, Timeout.Infinite, Timeout.Infinite); + } + + public TimeSpan Interval { get; set; } + + public bool IsRepeating { get; set; } + + public bool IsRunning { get; private set; } + + public event EventHandler? Tick; + + public void Start() + { + if (IsRunning) + return; + + IsRunning = true; + // set interval separarately to prevent calling callback before `timer' is assigned + _timer.Change(Interval, Interval); + } + + public void Stop() + { + if (!IsRunning) + return; + + IsRunning = false; + + _timer.Change(Timeout.Infinite, Timeout.Infinite); + } + + + void OnTimerTick(object? state) + { + if (!IsRunning) + return; + + Tick?.Invoke(this, EventArgs.Empty); + + if (!IsRepeating) + { + _timer.Change(Timeout.Infinite, Timeout.Infinite); + } + } + } + + public partial class DispatcherProvider + { + static IDispatcher? GetForCurrentThreadImplementation() + { + var context = SynchronizationContext.Current; + if (context == null) + return null; + + return new Dispatcher(context); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Fonts/EmbeddedFontLoader.Tizen.cs b/src/Core/src/Fonts/EmbeddedFontLoader.Tizen.cs new file mode 100644 index 0000000000..10b13494cf --- /dev/null +++ b/src/Core/src/Fonts/EmbeddedFontLoader.Tizen.cs @@ -0,0 +1,55 @@ +using System; +using System.Diagnostics; +using System.IO; +using ElmSharp; +using Tizen.Common; +using IOPath = System.IO.Path; +using TApplication = Tizen.Applications.Application; + +namespace Microsoft.Maui +{ + public partial class EmbeddedFontLoader : IEmbeddedFontLoader + { + const string _fontCacheFolderName = "fonts"; + + public DirectoryInfo? FontCacheDirectory { get; private set; } + + public string? LoadFont(EmbeddedFont font) + { + if (FontCacheDirectory == null) + { + FontCacheDirectory = Directory.CreateDirectory(IOPath.Combine(TApplication.Current.DirectoryInfo.Data, _fontCacheFolderName)); + Utility.AppendGlobalFontPath(FontCacheDirectory.FullName); + } + + var filePath = IOPath.Combine(FontCacheDirectory.FullName, font.FontName!); + var name = IOPath.GetFileNameWithoutExtension(filePath); + if (File.Exists(filePath)) + return name; + try + { + using (var fileStream = File.Create(filePath)) + { + if (font.ResourceStream == null) + throw new InvalidOperationException("ResourceStream was null."); + + font.ResourceStream.CopyTo(fileStream); + } + +#if __TIZEN__ + if (DotnetUtil.TizenAPIVersion > 5) + { + Utility.FontReinit(); + } +#endif + return name; + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + File.Delete(filePath); + } + return null; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Fonts/FontManager.Tizen.cs b/src/Core/src/Fonts/FontManager.Tizen.cs new file mode 100644 index 0000000000..83b070ac57 --- /dev/null +++ b/src/Core/src/Fonts/FontManager.Tizen.cs @@ -0,0 +1,107 @@ +using System; +using System.IO; +using System.Collections.Concurrent; + +namespace Microsoft.Maui +{ + public class FontManager : IFontManager + { + readonly ConcurrentDictionary<(string? family, float size, FontSlant slant), string> _fonts = new(); + + readonly IFontRegistrar _fontRegistrar; + readonly IServiceProvider? _serviceProvider; + + public double DefaultFontSize => 14; // 14sp + + public FontManager(IFontRegistrar fontRegistrar, IServiceProvider? serviceProvider = null) + { + _fontRegistrar = fontRegistrar; + _serviceProvider = serviceProvider; + } + + + public string GetFont(Font font) + { + var size = (float)font.Size; + + return GetFont(font.Family, size, font.Slant, GetNativeFontFamily); + } + + public string GetFontFamily(string? fontFamliy) + { + if (string.IsNullOrEmpty(fontFamliy)) + return ""; + + var cleansedFont = CleanseFontName(fontFamliy??string.Empty); + if (cleansedFont == null) + return ""; + + int index = cleansedFont.LastIndexOf('-'); + if (index != -1) + { + string font = cleansedFont.Substring(0, index); + string style = cleansedFont.Substring(index + 1); + return $"{font}:style={style}"; + } + else + { + return cleansedFont; + } + } + + string GetFont(string? family, float size, FontSlant slant, Func<(string?, float, FontSlant), string> factory) + { + return _fonts.GetOrAdd((family, size, slant), factory); + } + + string GetNativeFontFamily((string? family, float size, FontSlant slant) fontKey) + { + if (string.IsNullOrEmpty(fontKey.family)) + return ""; + + var cleansedFont = CleanseFontName(fontKey.family??string.Empty); + + if (cleansedFont == null) + return ""; + + int index = cleansedFont.LastIndexOf('-'); + if (index != -1) + { + string font = cleansedFont.Substring(0, index); + string style = cleansedFont.Substring(index + 1); + return $"{font}:style={style}"; + } + else + { + return cleansedFont; + } + } + + string? CleanseFontName(string fontName) + { + // First check Alias + if (_fontRegistrar.GetFont(fontName) is string fontPostScriptName) + return fontPostScriptName; + + var fontFile = FontFile.FromString(fontName); + + if (!string.IsNullOrWhiteSpace(fontFile.Extension)) + { + if (_fontRegistrar.GetFont(fontFile.FileNameWithExtension()) is string filePath) + return filePath ?? fontFile.PostScriptName; + } + else + { + foreach (var ext in FontFile.Extensions) + { + + var formatted = fontFile.FileNameWithExtension(ext); + if (_fontRegistrar.GetFont(formatted) is string filePath) + return filePath; + } + } + + return fontFile.PostScriptName; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Fonts/FontRegistrar.Tizen.cs b/src/Core/src/Fonts/FontRegistrar.Tizen.cs new file mode 100644 index 0000000000..8915d20e89 --- /dev/null +++ b/src/Core/src/Fonts/FontRegistrar.Tizen.cs @@ -0,0 +1,26 @@ +#nullable enable +using System.IO; + +namespace Microsoft.Maui +{ + public partial class FontRegistrar : IFontRegistrar + { + string? LoadNativeAppFont(string font, string filename, string? alias) + { + using var stream = GetNativeFontStream(filename, alias); + + return LoadEmbeddedFont(font, filename, alias, stream); + } + + Stream GetNativeFontStream(string filename, string? alias) + { + // TODO: check other folders as well + var resDirPath = Tizen.Applications.Application.Current.DirectoryInfo.Resource; + var fontPath = Path.Combine(resDirPath, "fonts", filename); + if (File.Exists(fontPath)) + return File.OpenRead(fontPath); + + throw new FileNotFoundException($"Native font with the name {filename} was not found."); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Fonts/IFontManager.Tizen.cs b/src/Core/src/Fonts/IFontManager.Tizen.cs new file mode 100644 index 0000000000..c6ee0c3974 --- /dev/null +++ b/src/Core/src/Fonts/IFontManager.Tizen.cs @@ -0,0 +1,9 @@ +namespace Microsoft.Maui +{ + public partial interface IFontManager + { + string GetFont(Font font); + + string GetFontFamily(string? font); + } +} \ No newline at end of file diff --git a/src/Core/src/Graphics/MauiDrawable.Tizen.cs b/src/Core/src/Graphics/MauiDrawable.Tizen.cs new file mode 100644 index 0000000000..a99614a25d --- /dev/null +++ b/src/Core/src/Graphics/MauiDrawable.Tizen.cs @@ -0,0 +1,89 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui +{ + public class MauiDrawable : IDrawable + { + public IShadow? Shadow { get; set; } + + public Paint? Background { get; set; } + + public IBorderStroke? Border { get; set; } + + public Thickness ShadowThickness { get; set; } + + public IShape? Shape { get; set; } + + public IShape? Clip { get; set; } + + PathF GetBoundaryPath(Rect bounds) + { + if (Clip != null) + { + return Clip.PathForBounds(bounds); + } + + if (Shape != null) + { + return Shape.PathForBounds(bounds); + } + + var path = new PathF(); + path.AppendRectangle(bounds); + return path; + } + + public void Draw(ICanvas canvas, RectF dirtyRect) + { + canvas.SaveState(); + canvas.Translate((float)ShadowThickness.Left, (float)ShadowThickness.Top); + RectF drawBounds = new Rect(0, 0, dirtyRect.Width - ShadowThickness.HorizontalThickness, dirtyRect.Height - ShadowThickness.VerticalThickness); + var drawablePath = GetBoundaryPath(drawBounds); + + if (Shadow != null) + { + canvas.SaveState(); + Color color = Shadow.Paint.ToColor() != null ? Shadow.Paint.ToColor()!.MultiplyAlpha(Shadow.Opacity) : Colors.Black.MultiplyAlpha(Shadow.Opacity); + canvas.FillColor = color; + canvas.SetShadow( + new SizeF((float)Shadow.Offset.X, (float)Shadow.Offset.Y), + (int)Shadow.Radius, + color); + canvas.FillPath(drawablePath); + canvas.RestoreState(); + + canvas.SaveState(); + canvas.StrokeColor = Colors.Transparent; + canvas.DrawPath(drawablePath); + canvas.ClipPath(drawablePath, WindingMode.EvenOdd); + canvas.RestoreState(); + } + + if (Background != null) + { + canvas.SaveState(); + canvas.SetFillPaint(Background, drawBounds); + canvas.FillPath(drawablePath); + canvas.RestoreState(); + } + + if (Border != null) + { + canvas.SaveState(); + var borderPath = Border.Shape?.PathForBounds(drawBounds); + 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.RestoreState(); + } + canvas.RestoreState(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Graphics/PaintExtensions.Tizen.cs b/src/Core/src/Graphics/PaintExtensions.Tizen.cs new file mode 100644 index 0000000000..f683d214fe --- /dev/null +++ b/src/Core/src/Graphics/PaintExtensions.Tizen.cs @@ -0,0 +1,82 @@ +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; + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.Tizen.cs b/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.Tizen.cs new file mode 100644 index 0000000000..ab1eced9f8 --- /dev/null +++ b/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.Tizen.cs @@ -0,0 +1,28 @@ +using Tizen.UIExtensions.ElmSharp; +using EColor = ElmSharp.Color; +using EProgressBar = ElmSharp.ProgressBar; + +namespace Microsoft.Maui.Handlers +{ + public partial class ActivityIndicatorHandler : ViewHandler + { + protected virtual EColor DefaultColor => ThemeConstants.ProgressBar.ColorClass.Default; + + protected override EProgressBar CreatePlatformView() + { + var progressBar = new EProgressBar(NativeParent) { IsPulseMode = true }.SetSmallStyle(); + progressBar.Color = DefaultColor; + return progressBar; + } + + public static void MapIsRunning(IActivityIndicatorHandler handler, IActivityIndicator activityIndicator) + { + handler.PlatformView?.UpdateIsRunning(activityIndicator); + } + + public static void MapColor(IActivityIndicatorHandler handler, IActivityIndicator activityIndicator) + { + handler.PlatformView?.UpdateColor(activityIndicator); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.cs b/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.cs index 70d8198c86..5922ecfc0e 100644 --- a/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.cs +++ b/src/Core/src/Handlers/ActivityIndicator/ActivityIndicatorHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiActivityIndicator; using PlatformView = Android.Widget.ProgressBar; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.ProgressRing; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.ProgressBar; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/ActivityIndicator/IActivityIndicatorHandler.cs b/src/Core/src/Handlers/ActivityIndicator/IActivityIndicatorHandler.cs index 58d2bce514..f0bc878d76 100644 --- a/src/Core/src/Handlers/ActivityIndicator/IActivityIndicatorHandler.cs +++ b/src/Core/src/Handlers/ActivityIndicator/IActivityIndicatorHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiActivityIndicator; using PlatformView = Android.Widget.ProgressBar; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.ProgressRing; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.ProgressBar; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs b/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs new file mode 100644 index 0000000000..b8c0d621c0 --- /dev/null +++ b/src/Core/src/Handlers/Application/ApplicationHandler.Tizen.cs @@ -0,0 +1,25 @@ +using Tizen.Applications; + +namespace Microsoft.Maui.Handlers +{ + public partial class ApplicationHandler : ElementHandler + { + public static void MapTerminate(ApplicationHandler handler, IApplication application, object? args) + { + handler.PlatformView.Exit(); + } + + public static void MapOpenWindow(ApplicationHandler handler, IApplication application, object? args) + { + handler.PlatformView?.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 diff --git a/src/Core/src/Handlers/Application/ApplicationHandler.cs b/src/Core/src/Handlers/Application/ApplicationHandler.cs index d357e78d65..73ea47c328 100644 --- a/src/Core/src/Handlers/Application/ApplicationHandler.cs +++ b/src/Core/src/Handlers/Application/ApplicationHandler.cs @@ -7,6 +7,8 @@ using PlatformView = UIKit.IUIApplicationDelegate; using PlatformView = Android.App.Application; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Application; +#elif TIZEN +using PlatformView = Tizen.Applications.CoreApplication; #endif namespace Microsoft.Maui.Handlers diff --git a/src/Core/src/Handlers/Border/BorderHandler.Tizen.cs b/src/Core/src/Handlers/Border/BorderHandler.Tizen.cs new file mode 100644 index 0000000000..c258a0dd3a --- /dev/null +++ b/src/Core/src/Handlers/Border/BorderHandler.Tizen.cs @@ -0,0 +1,71 @@ +using System; + +namespace Microsoft.Maui.Handlers +{ + public partial class BorderHandler : ViewHandler + { + IPlatformViewHandler? _contentHandler; + + protected override BorderView 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 BorderView(NativeParent, VirtualView) + { + CrossPlatformMeasure = VirtualView.CrossPlatformMeasure, + CrossPlatformArrange = VirtualView.CrossPlatformArrange + }; + view.Show(); + return view; + } + + protected override void SetupContainer() + { + base.SetupContainer(); + PlatformView.ContainerView = ContainerView; + } + + public override Graphics.Size GetDesiredSize(double widthConstraint, double heightConstraint) + { + return VirtualView.CrossPlatformMeasure(widthConstraint, heightConstraint); + } + + 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; + } + + public static void MapContent(IBorderHandler handler, IBorderView border) + { + if (handler is BorderHandler borderHandler) + borderHandler.UpdateContent(); + } + + 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."); + + 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; + } + } + } + } +} diff --git a/src/Core/src/Handlers/Border/BorderHandler.cs b/src/Core/src/Handlers/Border/BorderHandler.cs index 4299a9b7f1..cc37c2ed25 100644 --- a/src/Core/src/Handlers/Border/BorderHandler.cs +++ b/src/Core/src/Handlers/Border/BorderHandler.cs @@ -5,6 +5,8 @@ using PlatformView = Microsoft.Maui.Platform.ContentView; using PlatformView = Microsoft.Maui.Platform.ContentViewGroup; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.ContentPanel; +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.BorderView; #elif NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Border/IBorderHandler.cs b/src/Core/src/Handlers/Border/IBorderHandler.cs index 4583eb91c1..d6360fe83c 100644 --- a/src/Core/src/Handlers/Border/IBorderHandler.cs +++ b/src/Core/src/Handlers/Border/IBorderHandler.cs @@ -5,6 +5,8 @@ using PlatformView = Microsoft.Maui.Platform.ContentView; using PlatformView = Microsoft.Maui.Platform.ContentViewGroup; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.ContentPanel; +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.BorderView; #elif NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs new file mode 100644 index 0000000000..4301ae2c30 --- /dev/null +++ b/src/Core/src/Handlers/Button/ButtonHandler.Tizen.cs @@ -0,0 +1,95 @@ +using System; +using System.Threading.Tasks; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class ButtonHandler : ViewHandler + { + protected override Button CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + return new Button(NativeParent); + } + + protected override void ConnectHandler(Button platformView) + { + platformView.Released += OnButtonReleased; + platformView.Clicked += OnButtonClicked; + platformView.Pressed += OnButtonPressed; + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(Button platformView) + { + platformView.Released -= OnButtonReleased; + platformView.Clicked -= OnButtonClicked; + platformView.Pressed -= OnButtonPressed; + base.DisconnectHandler(platformView); + } + + public static void MapText(IButtonHandler handler, IText button) + { + handler.PlatformView?.UpdateText(button); + } + + public static void MapTextColor(IButtonHandler handler, ITextStyle button) + { + handler.PlatformView?.UpdateTextColor(button); + } + + public static void MapImageSource(IButtonHandler handler, IImage image) => + MapImageSourceAsync(handler, image).FireAndForget(handler); + + public static Task MapImageSourceAsync(IButtonHandler handler, IImage image) + { + if (image.Source == null) + { + return Task.CompletedTask; + } + return handler.ImageSourceLoader.UpdateImageSourceAsync(); + } + + [MissingMapper] + public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button) { } + + [MissingMapper] + public static void MapFont(IButtonHandler handler, ITextStyle button) { } + + [MissingMapper] + public static void MapPadding(IButtonHandler handler, IButton button) { } + + [MissingMapper] + public static void MapStrokeColor(IButtonHandler handler, IButtonStroke buttonStroke) { } + + [MissingMapper] + public static void MapStrokeThickness(IButtonHandler handler, IButtonStroke buttonStroke) { } + + [MissingMapper] + public static void MapCornerRadius(IButtonHandler handler, IButtonStroke buttonStroke) { } + + [MissingMapper] + public static void MapLineBreakMode(IButtonHandler handler, IButton button) { } + + void OnButtonClicked(object? sender, EventArgs e) + { + VirtualView?.Clicked(); + } + + void OnButtonReleased(object? sender, EventArgs e) + { + VirtualView?.Released(); + } + + void OnButtonPressed(object? sender, EventArgs e) + { + VirtualView?.Pressed(); + } + + void OnSetImageSource(Image? image) + { + PlatformView.Image = image; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Button/ButtonHandler.cs b/src/Core/src/Handlers/Button/ButtonHandler.cs index aa81a3b303..06e6a8c5d8 100644 --- a/src/Core/src/Handlers/Button/ButtonHandler.cs +++ b/src/Core/src/Handlers/Button/ButtonHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIButton; using PlatformView = Google.Android.Material.Button.MaterialButton; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.Button; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Button; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Button/IButtonHandler.cs b/src/Core/src/Handlers/Button/IButtonHandler.cs index 7c097ad3ac..94e7159156 100644 --- a/src/Core/src/Handlers/Button/IButtonHandler.cs +++ b/src/Core/src/Handlers/Button/IButtonHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIButton; using PlatformView = Google.Android.Material.Button.MaterialButton; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.Button; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Button; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif @@ -16,4 +18,4 @@ namespace Microsoft.Maui.Handlers new PlatformView PlatformView { get; } ImageSourcePartLoader ImageSourceLoader { get; } } -} \ 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 new file mode 100644 index 0000000000..15b50c0f24 --- /dev/null +++ b/src/Core/src/Handlers/CheckBox/CheckBoxHandler.Tizen.cs @@ -0,0 +1,41 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class CheckBoxHandler : ViewHandler + { + protected override Check CreatePlatformView() => new Check(NativeParent); + + protected override void ConnectHandler(Check platformView) + { + base.ConnectHandler(platformView); + platformView.StateChanged += OnStateChanged; + } + + protected override void DisconnectHandler(Check platformView) + { + base.DisconnectHandler(platformView); + platformView.StateChanged -= OnStateChanged; + } + + public static void MapIsChecked(ICheckBoxHandler handler, ICheckBox check) + { + handler.PlatformView?.UpdateIsChecked(check); + } + + public static void MapForeground(ICheckBoxHandler handler, ICheckBox check) + { + handler.PlatformView?.UpdateForeground(check); + } + + void OnStateChanged(object? sender, EventArgs e) + { + if (VirtualView == null) + return; + + if (PlatformView != null) + VirtualView.IsChecked = PlatformView.IsChecked; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/CheckBox/CheckBoxHandler.cs b/src/Core/src/Handlers/CheckBox/CheckBoxHandler.cs index a6bbab0931..668efe6c32 100644 --- a/src/Core/src/Handlers/CheckBox/CheckBoxHandler.cs +++ b/src/Core/src/Handlers/CheckBox/CheckBoxHandler.cs @@ -5,6 +5,8 @@ using PlatformView = Microsoft.Maui.Platform.MauiCheckBox; using PlatformView = AndroidX.AppCompat.Widget.AppCompatCheckBox; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.CheckBox; +#elif TIZEN +using PlatformView = ElmSharp.Check; #elif NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/CheckBox/ICheckboxHandler.cs b/src/Core/src/Handlers/CheckBox/ICheckboxHandler.cs index 57fed104b9..0248931ace 100644 --- a/src/Core/src/Handlers/CheckBox/ICheckboxHandler.cs +++ b/src/Core/src/Handlers/CheckBox/ICheckboxHandler.cs @@ -5,6 +5,8 @@ using PlatformView = Microsoft.Maui.Platform.MauiCheckBox; using PlatformView = AndroidX.AppCompat.Widget.AppCompatCheckBox; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.CheckBox; +#elif TIZEN +using PlatformView = ElmSharp.Check; #elif NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/ContentView/ContentViewHandler.Tizen.cs b/src/Core/src/Handlers/ContentView/ContentViewHandler.Tizen.cs new file mode 100644 index 0000000000..88182d8492 --- /dev/null +++ b/src/Core/src/Handlers/ContentView/ContentViewHandler.Tizen.cs @@ -0,0 +1,77 @@ +using System; +using PlatformView = ElmSharp.EvasObject; +using EColor = ElmSharp.Color; +using Tizen.UIExtensions.Common; + +namespace Microsoft.Maui.Handlers +{ + public partial class ContentViewHandler : ViewHandler + { + IPlatformViewHandler? _contentHandler; + + 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 Graphics.Size GetDesiredSize(double widthConstraint, double heightConstraint) + { + return VirtualView.CrossPlatformMeasure(widthConstraint, heightConstraint); + } + + public override void SetVirtualView(IView view) + { + base.SetVirtualView(view); + _ = 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."); + + PlatformView.CrossPlatformMeasure = VirtualView.CrossPlatformMeasure; + PlatformView.CrossPlatformArrange = VirtualView.CrossPlatformArrange; + } + + public static void MapBackground(IContentViewHandler handler, IContentView view) + { + handler.UpdateValue(nameof(handler.ContainerView)); + handler.ToPlatform()?.UpdateBackground(view); + } + + public static void MapContent(IContentViewHandler handler, IContentView page) + { + if (handler is ContentViewHandler contentViewHandler) + { + contentViewHandler.UpdateContent(); + } + } + + 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."); + + 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; + } + } + } + } +} diff --git a/src/Core/src/Handlers/ContentView/ContentViewHandler.cs b/src/Core/src/Handlers/ContentView/ContentViewHandler.cs index ad54f36acd..f01dd14f83 100644 --- a/src/Core/src/Handlers/ContentView/ContentViewHandler.cs +++ b/src/Core/src/Handlers/ContentView/ContentViewHandler.cs @@ -5,7 +5,9 @@ using PlatformView = Microsoft.Maui.Platform.ContentView; using PlatformView = Microsoft.Maui.Platform.ContentViewGroup; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.ContentPanel; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.ContentCanvas; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif @@ -16,6 +18,9 @@ namespace Microsoft.Maui.Handlers public static IPropertyMapper Mapper = new PropertyMapper(ViewMapper) { [nameof(IContentView.Content)] = MapContent, +#if TIZEN + [nameof(IContentView.Background)] = MapBackground, +#endif }; public static CommandMapper CommandMapper = new(ViewCommandMapper) diff --git a/src/Core/src/Handlers/ContentView/IContentViewHandler.cs b/src/Core/src/Handlers/ContentView/IContentViewHandler.cs index a8dc3cd346..b4f4b2eb45 100644 --- a/src/Core/src/Handlers/ContentView/IContentViewHandler.cs +++ b/src/Core/src/Handlers/ContentView/IContentViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.ContentView; using PlatformView = Microsoft.Maui.Platform.ContentViewGroup; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.ContentPanel; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.ContentCanvas; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/DatePicker/DatePickerHandler.Tizen.cs b/src/Core/src/Handlers/DatePicker/DatePickerHandler.Tizen.cs new file mode 100644 index 0000000000..f08f407da7 --- /dev/null +++ b/src/Core/src/Handlers/DatePicker/DatePickerHandler.Tizen.cs @@ -0,0 +1,136 @@ +using System; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using TEntry = Tizen.UIExtensions.ElmSharp.Entry; +using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; +using EcoreMainloop = ElmSharp.EcoreMainloop; + +namespace Microsoft.Maui.Handlers +{ + public partial class DatePickerHandler : ViewHandler + { + const string DialogTitle = "Choose Date"; + Lazy? _lazyDialog; + + protected override TEntry CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + var entry = new EditfieldEntry(NativeParent) + { + IsSingleLine = true, + HorizontalTextAlignment = TTextAlignment.Center, + InputPanelShowByOnDemand = true, + IsEditable = false + }; + entry.SetVerticalTextAlignment(0.5); + return entry; + } + + protected override void ConnectHandler(TEntry platformView) + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + platformView.TextBlockFocused += OnTextBlockFocused; + platformView.EntryLayoutFocused += OnFocused; + platformView.EntryLayoutUnfocused += OnUnfocused; + + _lazyDialog = new Lazy(() => + { + var dialog = new DateTimePickerDialog(NativeParent) + { + Title = DialogTitle + }; + dialog.DateTimeChanged += OnDateTimeChanged; + dialog.PickerOpened += OnPickerOpened; + dialog.PickerClosed += OnPickerClosed; + return dialog; + }); + + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(TEntry platformView) + { + if (_lazyDialog != null && _lazyDialog.IsValueCreated) + { + _lazyDialog.Value.DateTimeChanged -= OnDateTimeChanged; + _lazyDialog.Value.PickerOpened -= OnPickerOpened; + _lazyDialog.Value.PickerClosed -= OnPickerClosed; + _lazyDialog.Value.Unrealize(); + _lazyDialog = null; + } + + platformView.TextBlockFocused -= OnTextBlockFocused; + platformView.EntryLayoutFocused -= OnFocused; + platformView.EntryLayoutUnfocused -= OnUnfocused; + + base.DisconnectHandler(platformView); + } + + public static void MapFormat(IDatePickerHandler handler, IDatePicker datePicker) + { + handler.PlatformView?.UpdateFormat(datePicker); + } + + public static void MapDate(IDatePickerHandler handler, IDatePicker datePicker) + { + handler.PlatformView?.UpdateDate(datePicker); + } + + public static void MapFont(IDatePickerHandler handler, IDatePicker datePicker) + { + var fontManager = handler.GetRequiredService(); + handler.PlatformView?.UpdateFont(datePicker, fontManager); + } + + public static void MapTextColor(IDatePickerHandler handler, IDatePicker datePicker) + { + handler.PlatformView?.UpdateTextColor(datePicker); + } + + [MissingMapper] + public static void MapMinimumDate(IDatePickerHandler handler, IDatePicker datePicker) { } + + [MissingMapper] + public static void MapMaximumDate(IDatePickerHandler handler, IDatePicker datePicker) { } + + [MissingMapper] + public static void MapCharacterSpacing(IDatePickerHandler handler, IDatePicker datePicker) { } + + protected virtual void OnDateTimeChanged(object? sender, DateChangedEventArgs dcea) + { + if (VirtualView == null || PlatformView == null) + return; + + VirtualView.Date = dcea.NewDate.Date; + } + + void OnTextBlockFocused(object? sender, EventArgs e) + { + if (VirtualView == null || PlatformView == null || _lazyDialog == null) + return; + + // For EFL Entry, the event will occur even if it is currently disabled. + // If the problem is resolved, no conditional statement is required. + if (VirtualView.IsEnabled) + { + var dialog = _lazyDialog.Value; + dialog.DateTime = VirtualView.Date; + dialog.MaximumDateTime = VirtualView.MaximumDate; + dialog.MinimumDateTime = VirtualView.MinimumDate; + // You need to call Show() after ui thread occupation because of EFL problem. + // Otherwise, the content of the popup will not receive focus. + EcoreMainloop.Post(() => dialog.Show()); + } + } + + protected virtual void OnPickerOpened(object? sender, EventArgs args) + { + } + + protected virtual void OnPickerClosed(object? sender, EventArgs args) + { + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/DatePicker/DatePickerHandler.cs b/src/Core/src/Handlers/DatePicker/DatePickerHandler.cs index fbabeb8cc5..840ae24b7b 100644 --- a/src/Core/src/Handlers/DatePicker/DatePickerHandler.cs +++ b/src/Core/src/Handlers/DatePicker/DatePickerHandler.cs @@ -6,7 +6,9 @@ using PlatformView = UIKit.UIDatePicker; using PlatformView = Microsoft.Maui.Platform.MauiDatePicker; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.CalendarDatePicker; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/DatePicker/IDatePickerHandler.cs b/src/Core/src/Handlers/DatePicker/IDatePickerHandler.cs index f90ab7af18..f4c684e4d9 100644 --- a/src/Core/src/Handlers/DatePicker/IDatePickerHandler.cs +++ b/src/Core/src/Handlers/DatePicker/IDatePickerHandler.cs @@ -6,7 +6,9 @@ using PlatformView = UIKit.UIDatePicker; using PlatformView = Microsoft.Maui.Platform.MauiDatePicker; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.CalendarDatePicker; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs new file mode 100644 index 0000000000..1a0ce4ba3c --- /dev/null +++ b/src/Core/src/Handlers/Editor/EditorHandler.Tizen.cs @@ -0,0 +1,170 @@ +using System; +using Tizen.UIExtensions.ElmSharp; +using EEntry = ElmSharp.Entry; + +namespace Microsoft.Maui.Handlers +{ + public partial class EditorHandler : ViewHandler + { + protected override Entry CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + return new EditfieldEntry(NativeParent, EditFieldEntryLayout.Styles.MulitLine) + { + IsSingleLine = false + }; + } + + protected override void ConnectHandler(Entry platformView) + { + platformView.Focused += OnEntryFocused; + platformView.Unfocused += OnEntryUnfocused; + platformView.Unfocused += OnCompleted; + platformView.PrependMarkUpFilter(MaxLengthFilter); + platformView.TextChanged += OnTextChanged; + } + + protected override void DisconnectHandler(Entry platformView) + { + platformView.BackButtonPressed -= OnCompleted; + platformView.Unfocused -= OnEntryUnfocused; + platformView.Focused -= OnEntryFocused; + platformView.TextChanged -= OnTextChanged; + } + + public static void MapBackground(IEditorHandler handler, IEditor editor) + { + handler.UpdateValue(nameof(handler.ContainerView)); + handler.ToPlatform()?.UpdateBackground(editor); + } + + public static void MapText(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdateText(editor); + + // Any text update requires that we update any attributed string formatting + MapFormatting(handler, editor); + } + + public static void MapTextColor(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdateTextColor(editor); + } + + public static void MapPlaceholder(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdatePlaceholder(editor); + } + + public static void MapPlaceholderColor(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdatePlaceholderColor(editor); + } + + public static void MapMaxLength(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdateMaxLength(editor); + } + + public static void MapIsReadOnly(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdateIsReadOnly(editor); + } + + public static void MapIsTextPredictionEnabled(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdateIsTextPredictionEnabled(editor); + } + + public static void MapFont(IEditorHandler handler, IEditor editor) + { + var fontManager = handler.GetRequiredService(); + + handler.PlatformView?.UpdateFont(editor, fontManager); + } + + public static void MapFormatting(IEditorHandler handler, IEditor editor) + { + // Update all of the attributed text formatting properties + handler.PlatformView?.UpdateMaxLength(editor); + } + + public static void MapKeyboard(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdateKeyboard(editor); + } + + public static void MapHorizontalTextAlignment(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdateHorizontalTextAlignment(editor); + } + + public static void MapVerticalTextAlignment(IEditorHandler handler, IEditor editor) + { + handler.PlatformView?.UpdateVerticalTextAlignment(editor); + } + + public static void MapCursorPosition(IEditorHandler handler, ITextInput editor) + { + handler.PlatformView?.UpdateSelectionLength(editor); + } + + public static void MapSelectionLength(IEditorHandler handler, ITextInput editor) + { + handler.PlatformView?.UpdateSelectionLength(editor); + } + + [MissingMapper] + public static void MapCharacterSpacing(IEditorHandler handler, IEditor editor) { } + + string? MaxLengthFilter(EEntry entry, string s) + { + if (VirtualView == null || PlatformView == null) + return null; + + if (entry.Text.Length < VirtualView.MaxLength) + return s; + + return null; + } + + void OnTextChanged(object? sender, EventArgs e) + { + if (VirtualView == null || PlatformView == null) + return; + + VirtualView.Text = PlatformView.Text; + } + + + + void OnEntryFocused(object? sender, EventArgs e) + { + if (PlatformView == null) + return; + + // BackButtonPressed is only passed to the object that is at the highest Z-Order, and it does not propagate to lower objects. + // If you want to make Editor input completed by using BackButtonPressed, you should subscribe BackButtonPressed event only when Editor gets focused. + PlatformView.BackButtonPressed += OnCompleted; + } + + void OnEntryUnfocused(object? sender, EventArgs e) + { + if (PlatformView == null) + return; + + // BackButtonPressed is only passed to the object that is at the highest Z-Order, and it does not propagate to lower objects. + // When the object is unfocesed BackButtonPressed event has to be released to stop using it. + PlatformView.BackButtonPressed -= OnCompleted; + } + + void OnCompleted(object? sender, EventArgs e) + { + if (PlatformView == null) + return; + + PlatformView.SetFocus(false); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Editor/EditorHandler.cs b/src/Core/src/Handlers/Editor/EditorHandler.cs index 856dd88cc3..a82bc9d82c 100644 --- a/src/Core/src/Handlers/Editor/EditorHandler.cs +++ b/src/Core/src/Handlers/Editor/EditorHandler.cs @@ -5,7 +5,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiTextView; using PlatformView = AndroidX.AppCompat.Widget.AppCompatEditText; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.TextBox; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Editor/IEditorHandler.cs b/src/Core/src/Handlers/Editor/IEditorHandler.cs index b2d7304117..a6d52b42b4 100644 --- a/src/Core/src/Handlers/Editor/IEditorHandler.cs +++ b/src/Core/src/Handlers/Editor/IEditorHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiTextView; using PlatformView = AndroidX.AppCompat.Widget.AppCompatEditText; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.TextBox; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/ElementHandlerExtensions.cs b/src/Core/src/Handlers/ElementHandlerExtensions.cs index 99b908f11c..1926db58f0 100644 --- a/src/Core/src/Handlers/ElementHandlerExtensions.cs +++ b/src/Core/src/Handlers/ElementHandlerExtensions.cs @@ -4,6 +4,8 @@ using PlatformView = UIKit.UIView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; #elif NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs new file mode 100644 index 0000000000..720fd581ce --- /dev/null +++ b/src/Core/src/Handlers/Entry/EntryHandler.Tizen.cs @@ -0,0 +1,221 @@ +using System; +using Tizen.UIExtensions.ElmSharp; +using EEntry = ElmSharp.Entry; + +namespace Microsoft.Maui.Handlers +{ + public partial class EntryHandler : ViewHandler + { + + protected override Entry CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + return new EditfieldEntry(NativeParent) + { + IsSingleLine = true + }; + } + + protected override void ConnectHandler(Entry platformView) + { + platformView.Activated += OnCompleted; + platformView.CursorPositionChanged += OnCursorChanged; + + // In order to know when the selection is cleared, SelectionCleared event has been used. + // Because CursorChanged event is still invoked with the selected text when an user clears selection. It is an known issue in EFL. + platformView.SelectionCleared += OnSelectionCleared; + + platformView.TextChanged += OnTextChanged; + platformView.EntryLayoutFocused += OnFocused; + platformView.EntryLayoutUnfocused += OnUnfocused; + 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) + //{ + // MainThread.BeginInvokeOnMainThread(() => + // { + // platformView.UpdateSelectionLength(VirtualView); + // }); + //} + } + + protected override void DisconnectHandler(Entry platformView) + { + platformView.Activated -= OnCompleted; + platformView.CursorPositionChanged -= OnCursorChanged; + platformView.TextChanged -= OnTextChanged; + platformView.EntryLayoutFocused -= OnFocused; + platformView.EntryLayoutUnfocused -= OnUnfocused; + } + + public static void MapBackground(IEntryHandler handler, IEntry entry) + { + handler.UpdateValue(nameof(handler.ContainerView)); + handler.ToPlatform()?.UpdateBackground(entry); + } + + public static void MapText(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateText(entry); + + // Any text update requires that we update any attributed string formatting + MapFormatting(handler, entry); + } + + public static void MapTextColor(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateTextColor(entry); + } + + public static void MapPlaceholder(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdatePlaceholder(entry); + } + + public static void MapPlaceholderColor(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdatePlaceholderColor(entry); + } + + public static void MapIsPassword(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateIsPassword(entry); + } + + public static void MapHorizontalTextAlignment(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateHorizontalTextAlignment(entry); + } + + public static void MapVerticalTextAlignment(IEntryHandler handler, IEntry entry) + { + handler?.PlatformView?.UpdateVerticalTextAlignment(entry); + } + + public static void MapMaxLength(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateMaxLength(entry); + } + + public static void MapIsReadOnly(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateIsReadOnly(entry); + } + + public static void MapIsTextPredictionEnabled(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateIsTextPredictionEnabled(entry); + } + + public static void MapKeyboard(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateKeyboard(entry); + } + + public static void MapReturnType(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateReturnType(entry); + } + + public static void MapFont(IEntryHandler handler, IEntry entry) + { + var fontManager = handler.GetRequiredService(); + + handler.PlatformView?.UpdateFont(entry, fontManager); + } + + public static void MapClearButtonVisibility(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateClearButtonVisibility(entry); + } + + public static void MapFormatting(IEntryHandler handler, IEntry entry) + { + // Update all of the attributed text formatting properties + // Setting any of those may have removed text alignment settings, + // so we need to make sure those are applied, too + handler.PlatformView?.UpdateMaxLength(entry); + handler.PlatformView?.UpdateHorizontalTextAlignment(entry); + } + + public static void MapSelectionLength(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateSelectionLength(entry); + } + + public static void MapCursorPosition(IEntryHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateSelectionLength(entry); + } + + public static void MapKeyboard(EditorHandler handler, IEntry entry) + { + handler.PlatformView?.UpdateKeyboard(entry); + } + + [MissingMapper] + public static void MapCharacterSpacing(IEntryHandler handler, IEntry entry) { } + + string? MaxLengthFilter(EEntry entry, string s) + { + if (VirtualView == null || PlatformView == null) + return null; + + if (entry.Text.Length < VirtualView.MaxLength) + return s; + + return null; + } + + void OnTextChanged(object? sender, EventArgs e) + { + if (VirtualView == null || PlatformView == null) + return; + + VirtualView.Text = PlatformView.Text; + } + + void OnCursorChanged(object? sender, EventArgs e) + { + if (VirtualView == null || PlatformView == null) + return; + + var position = PlatformView.CursorPosition; + + PlatformView.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 || PlatformView == null) + return; + + if (PlatformView.IsFocused) + { + VirtualView.SelectionLength = 0; + VirtualView.CursorPosition = PlatformView.CursorPosition; + } + } + + void OnCompleted(object? sender, EventArgs e) + { + if (PlatformView == null) + return; + + PlatformView.SetFocus(false); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Entry/EntryHandler.cs b/src/Core/src/Handlers/Entry/EntryHandler.cs index 35e92ea624..6b5180a255 100644 --- a/src/Core/src/Handlers/Entry/EntryHandler.cs +++ b/src/Core/src/Handlers/Entry/EntryHandler.cs @@ -5,7 +5,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiTextField; using PlatformView = AndroidX.AppCompat.Widget.AppCompatEditText; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.TextBox; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif @@ -60,4 +62,4 @@ namespace Microsoft.Maui.Handlers PlatformView IEntryHandler.PlatformView => PlatformView; } -} \ No newline at end of file +} diff --git a/src/Core/src/Handlers/Entry/IEntryHandler.cs b/src/Core/src/Handlers/Entry/IEntryHandler.cs index e4390388a8..66ed5f171d 100644 --- a/src/Core/src/Handlers/Entry/IEntryHandler.cs +++ b/src/Core/src/Handlers/Entry/IEntryHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiTextField; using PlatformView = AndroidX.AppCompat.Widget.AppCompatEditText; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.TextBox; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/FlyoutView/FlyoutViewHandler.Tizen.cs b/src/Core/src/Handlers/FlyoutView/FlyoutViewHandler.Tizen.cs new file mode 100644 index 0000000000..c5ab0d85e6 --- /dev/null +++ b/src/Core/src/Handlers/FlyoutView/FlyoutViewHandler.Tizen.cs @@ -0,0 +1,14 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class FlyoutViewHandler : ViewHandler + { + protected override EvasObject CreatePlatformView() + { + //TODO : Need to impl + throw new NotImplementedException(); + } + } +} diff --git a/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs new file mode 100644 index 0000000000..f699ed7d87 --- /dev/null +++ b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.Tizen.cs @@ -0,0 +1,28 @@ +using Microsoft.Maui.Platform; + +namespace Microsoft.Maui.Handlers +{ + public partial class GraphicsViewHandler : ViewHandler + { + protected override PlatformTouchGraphicsView CreatePlatformView() + { + return new PlatformTouchGraphicsView(NativeParent); + } + + public static void MapDrawable(IGraphicsViewHandler handler, IGraphicsView graphicsView) + { + handler.PlatformView?.UpdateDrawable(graphicsView); + } + + public static void MapFlowDirection(IGraphicsViewHandler handler, IGraphicsView graphicsView) + { + handler.PlatformView?.UpdateFlowDirection(graphicsView); + handler.PlatformView?.Invalidate(); + } + + public static void MapInvalidate(IGraphicsViewHandler handler, IGraphicsView graphicsView, object? arg) + { + handler.PlatformView?.Invalidate(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.cs b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.cs index b9c98eb5c2..926b5ad758 100644 --- a/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.cs +++ b/src/Core/src/Handlers/GraphicsView/GraphicsViewHandler.cs @@ -1,5 +1,5 @@ #nullable enable -#if __IOS__ || MACCATALYST || MONOANDROID || WINDOWS +#if __IOS__ || MACCATALYST || MONOANDROID || WINDOWS || TIZEN #define PLATFORM using PlatformView = Microsoft.Maui.Platform.PlatformTouchGraphicsView; #else diff --git a/src/Core/src/Handlers/GraphicsView/IGraphicsViewHandler.cs b/src/Core/src/Handlers/GraphicsView/IGraphicsViewHandler.cs index 61239029ce..88a52002e7 100644 --- a/src/Core/src/Handlers/GraphicsView/IGraphicsViewHandler.cs +++ b/src/Core/src/Handlers/GraphicsView/IGraphicsViewHandler.cs @@ -1,4 +1,4 @@ -#if __IOS__ || MACCATALYST || MONOANDROID || WINDOWS +#if __IOS__ || MACCATALYST || MONOANDROID || WINDOWS || TIZEN using PlatformView = Microsoft.Maui.Platform.PlatformTouchGraphicsView; #else using PlatformView = System.Object; diff --git a/src/Core/src/Handlers/IViewHandler.Tizen.cs b/src/Core/src/Handlers/IViewHandler.Tizen.cs new file mode 100644 index 0000000000..8cb46442b7 --- /dev/null +++ b/src/Core/src/Handlers/IViewHandler.Tizen.cs @@ -0,0 +1,19 @@ +using System; +using EvasObject = ElmSharp.EvasObject; +using ERect = ElmSharp.Rect; + +namespace Microsoft.Maui +{ + public interface IPlatformViewHandler : IViewHandler, IDisposable + { + new EvasObject? PlatformView { get; } + + new EvasObject? ContainerView { get; } + + void SetParent(IPlatformViewHandler parent); + + IPlatformViewHandler? Parent { get; } + + ERect GetPlatformContentGeometry(); + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/IImageHandler.cs b/src/Core/src/Handlers/Image/IImageHandler.cs index fae4c2a528..fbaddcd8a6 100644 --- a/src/Core/src/Handlers/Image/IImageHandler.cs +++ b/src/Core/src/Handlers/Image/IImageHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIImageView; using PlatformView = Android.Widget.ImageView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.Image; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Image; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs b/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs new file mode 100644 index 0000000000..d2bdeb28a1 --- /dev/null +++ b/src/Core/src/Handlers/Image/ImageHandler.Tizen.cs @@ -0,0 +1,58 @@ +#nullable enable +using System; +using System.Threading.Tasks; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class ImageHandler : ViewHandler + { + protected override Image CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + return new Image(NativeParent); + } + + protected override void DisconnectHandler(Image platformView) + { + base.DisconnectHandler(platformView); + SourceLoader.Reset(); + } + + public override bool NeedsContainer => + VirtualView?.Background != null || + VirtualView?.Clip != null || + base.NeedsContainer; + + public static void MapBackground(IImageHandler handler, IImage image) + { + handler.UpdateValue(nameof(IViewHandler.ContainerView)); + handler.ToPlatform()?.UpdateBackground(image); + } + + public static void MapAspect(IImageHandler handler, IImage image) => + handler.PlatformView?.UpdateAspect(image); + + public static void MapIsAnimationPlaying(IImageHandler handler, IImage image) => + handler.PlatformView?.UpdateIsAnimationPlaying(image); + + public static void MapSource(IImageHandler handler, IImage image) => + MapSourceAsync(handler, image).FireAndForget(handler); + + public static Task MapSourceAsync(IImageHandler handler, IImage image) + { + if (handler.PlatformView == null) + return Task.CompletedTask; + + handler.PlatformView.Clear(); + return handler.SourceLoader.UpdateImageSourceAsync(); + } + + void OnSetImageSource(Image? obj) + { + //Empty on purpose + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Image/ImageHandler.cs b/src/Core/src/Handlers/Image/ImageHandler.cs index e48a9fdbe0..f33d6b7285 100644 --- a/src/Core/src/Handlers/Image/ImageHandler.cs +++ b/src/Core/src/Handlers/Image/ImageHandler.cs @@ -6,7 +6,9 @@ using PlatformView = UIKit.UIImageView; using PlatformView = Android.Widget.ImageView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.Image; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Image; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif @@ -16,7 +18,7 @@ namespace Microsoft.Maui.Handlers { public static IPropertyMapper Mapper = new PropertyMapper(ViewHandler.ViewMapper) { -#if __ANDROID__ || WINDOWS +#if __ANDROID__ || WINDOWS || TIZEN [nameof(IImage.Background)] = MapBackground, #endif [nameof(IImage.Aspect)] = MapAspect, @@ -46,4 +48,4 @@ namespace Microsoft.Maui.Handlers PlatformView IImageHandler.PlatformView => PlatformView; } -} \ No newline at end of file +} diff --git a/src/Core/src/Handlers/ImageButton/IImageButtonHandler.cs b/src/Core/src/Handlers/ImageButton/IImageButtonHandler.cs index 52eb04d345..881022f741 100644 --- a/src/Core/src/Handlers/ImageButton/IImageButtonHandler.cs +++ b/src/Core/src/Handlers/ImageButton/IImageButtonHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIButton; using PlatformView = Google.Android.Material.ImageView.ShapeableImageView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.Button; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.MauiImageButton; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Tizen.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Tizen.cs new file mode 100644 index 0000000000..ab600d8d0d --- /dev/null +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.Tizen.cs @@ -0,0 +1,65 @@ +using System; +using TImage = Tizen.UIExtensions.ElmSharp.Image; + +namespace Microsoft.Maui.Handlers +{ + public partial class ImageButtonHandler : ViewHandler + { + protected override MauiImageButton CreatePlatformView() + { + _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} must be set to create a ImageButton"); + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} cannot be null"); + + var view = new MauiImageButton(NativeParent); + return view; + } + + protected override void ConnectHandler(MauiImageButton platformView) + { + platformView.Clicked += OnClicked; + platformView.Pressed += OnPressed; + platformView.Released += OnReleased; + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(MauiImageButton platformView) + { + platformView.Clicked -= OnClicked; + platformView.Pressed -= OnPressed; + platformView.Released -= OnReleased; + base.DisconnectHandler(platformView); + } + + [MissingMapper] + public static void MapStrokeColor(IImageButtonHandler handler, IButtonStroke buttonStroke) { } + + [MissingMapper] + public static void MapStrokeThickness(IImageButtonHandler handler, IButtonStroke buttonStroke) { } + + [MissingMapper] + public static void MapCornerRadius(IImageButtonHandler handler, IButtonStroke buttonStroke) { } + + [MissingMapper] + public static void MapPadding(IImageButtonHandler handler, IImageButton imageButton) { } + + private void OnReleased(object? sender, EventArgs e) + { + VirtualView?.Released(); + } + + private void OnPressed(object? sender, EventArgs e) + { + VirtualView?.Pressed(); + } + + private void OnClicked(object? sender, EventArgs e) + { + VirtualView?.Clicked(); + } + + void OnSetImageSource(TImage? img) + { + //Empty on purpose + } + } +} diff --git a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs index bf90c5e0ed..25532e407d 100644 --- a/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs +++ b/src/Core/src/Handlers/ImageButton/ImageButtonHandler.cs @@ -11,7 +11,11 @@ using System; using PlatformImage = Microsoft.UI.Xaml.Media.ImageSource; using PlatformImageView = Microsoft.UI.Xaml.Controls.Image; using PlatformView = Microsoft.UI.Xaml.Controls.Button; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformImage = Tizen.UIExtensions.ElmSharp.Image; +using PlatformImageView = Tizen.UIExtensions.ElmSharp.Image; +using PlatformView = Microsoft.Maui.Platform.MauiImageButton; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformImage = System.Object; using PlatformImageView = System.Object; using PlatformView = System.Object; @@ -55,7 +59,7 @@ namespace Microsoft.Maui.Handlers IImage IImageHandler.VirtualView => VirtualView; PlatformImageView IImageHandler.PlatformView => -#if __IOS__ +#if __IOS__ || TIZEN PlatformView.ImageView; #elif WINDOWS PlatformView.GetContent() ?? throw new InvalidOperationException("ImageButton did not contain an Image element."); @@ -67,4 +71,4 @@ namespace Microsoft.Maui.Handlers ImageSourcePartLoader IImageHandler.SourceLoader => SourceLoader; } -} \ No newline at end of file +} diff --git a/src/Core/src/Handlers/IndicatorView/IIndicatorViewHandler.cs b/src/Core/src/Handlers/IndicatorView/IIndicatorViewHandler.cs index b4b3236f9d..6cffb37e66 100644 --- a/src/Core/src/Handlers/IndicatorView/IIndicatorViewHandler.cs +++ b/src/Core/src/Handlers/IndicatorView/IIndicatorViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiPageControl; using PlatformView = Microsoft.Maui.Platform.MauiPageControl; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.MauiPageControl; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.IndicatorView; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/IndicatorView/IndicatorViewHandler.Tizen.cs b/src/Core/src/Handlers/IndicatorView/IndicatorViewHandler.Tizen.cs new file mode 100644 index 0000000000..fe77754eca --- /dev/null +++ b/src/Core/src/Handlers/IndicatorView/IndicatorViewHandler.Tizen.cs @@ -0,0 +1,60 @@ +using System; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class IndicatorViewHandler : ViewHandler + { + protected override IndicatorView CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + return new IndicatorView(NativeParent); + } + + protected override void ConnectHandler(IndicatorView platformView) + { + base.ConnectHandler(platformView); + PlatformView.SelectedPosition += OnSelectedPosition; + } + + protected override void DisconnectHandler(IndicatorView platformView) + { + base.DisconnectHandler(platformView); + PlatformView.SelectedPosition -= OnSelectedPosition; + } + + public static void MapCount(IIndicatorViewHandler handler, IIndicatorView indicator) + { + handler.PlatformView.UpdateIndicatorCount(indicator); + } + + public static void MapPosition(IIndicatorViewHandler handler, IIndicatorView indicator) + { + handler.PlatformView.UpdatePosition(indicator); + } + + //TODO : Need to impl + [MissingMapper] + public static void MapHideSingle(IIndicatorViewHandler handler, IIndicatorView indicator) { } + + [MissingMapper] + public static void MapMaximumVisible(IIndicatorViewHandler handler, IIndicatorView indicator) { } + + [MissingMapper] + public static void MapIndicatorSize(IIndicatorViewHandler handler, IIndicatorView indicator) { } + + [MissingMapper] + public static void MapIndicatorColor(IIndicatorViewHandler handler, IIndicatorView indicator) { } + + [MissingMapper] + public static void MapSelectedIndicatorColor(IIndicatorViewHandler handler, IIndicatorView indicator) { } + + [MissingMapper] + public static void MapIndicatorShape(IIndicatorViewHandler handler, IIndicatorView indicator) { } + + void OnSelectedPosition(object? sender, SelectedPositionChangedEventArgs e) + { + VirtualView.Position = e.SelectedPosition; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/IndicatorView/IndicatorViewHandler.cs b/src/Core/src/Handlers/IndicatorView/IndicatorViewHandler.cs index 79e458cae7..b525a717ac 100644 --- a/src/Core/src/Handlers/IndicatorView/IndicatorViewHandler.cs +++ b/src/Core/src/Handlers/IndicatorView/IndicatorViewHandler.cs @@ -5,7 +5,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiPageControl; using PlatformView = Microsoft.Maui.Platform.MauiPageControl; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.MauiPageControl; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.IndicatorView; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Label/ILabelHandler.cs b/src/Core/src/Handlers/Label/ILabelHandler.cs index 3aa57b5af6..e801efec38 100644 --- a/src/Core/src/Handlers/Label/ILabelHandler.cs +++ b/src/Core/src/Handlers/Label/ILabelHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiLabel; using PlatformView = AndroidX.AppCompat.Widget.AppCompatTextView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.TextBlock; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Label; +#elif NETSTANDARD || (NET6_0 && !IOS && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Label/LabelHandler.Tizen.cs b/src/Core/src/Handlers/Label/LabelHandler.Tizen.cs new file mode 100644 index 0000000000..276b3b52a6 --- /dev/null +++ b/src/Core/src/Handlers/Label/LabelHandler.Tizen.cs @@ -0,0 +1,78 @@ +using System; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class LabelHandler : ViewHandler + { + protected override Label CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + var label = new Label(NativeParent) + { + // Fix me : it is workaround code, LineBreakMode is not working when Label was measured but we set LineBreakMode as WordWrap at initialize time, it works + LineBreakMode = Tizen.UIExtensions.Common.LineBreakMode.WordWrap + }; + return label; + } + + public static void MapBackground(ILabelHandler handler, ILabel label) + { + handler.UpdateValue(nameof(handler.ContainerView)); + handler.ToPlatform()?.UpdateBackground(label); + } + + public static void MapText(ILabelHandler handler, ILabel label) + { + handler.PlatformView?.UpdateText(label); + + // Any text update requires that we update any attributed string formatting + MapFormatting(handler, label); + } + + public static void MapTextColor(ILabelHandler handler, ILabel label) + { + handler.PlatformView?.UpdateTextColor(label); + } + + public static void MapHorizontalTextAlignment(ILabelHandler handler, ILabel label) + { + handler.PlatformView?.UpdateHorizontalTextAlignment(label); + } + + public static void MapVerticalTextAlignment(ILabelHandler handler, ILabel label) + { + handler.PlatformView?.UpdateVerticalTextAlignment(label); + } + + public static void MapTextDecorations(ILabelHandler handler, ILabel label) + { + handler.PlatformView?.UpdateTextDecorations(label); + } + + public static void MapFont(ILabelHandler handler, ILabel label) + { + var fontManager = handler.GetRequiredService(); + handler.PlatformView?.UpdateFont(label, fontManager); + } + + public static void MapFormatting(ILabelHandler handler, ILabel label) + { + // Update all of the attributed text formatting properties + // Setting any of those may have removed text alignment settings, + // so we need to make sure those are applied, too + handler.PlatformView?.UpdateHorizontalTextAlignment(label); + handler.PlatformView?.UpdateTextDecorations(label); + } + + [MissingMapper] + public static void MapCharacterSpacing(ILabelHandler handler, ILabel label) {} + + [MissingMapper] + public static void MapLineHeight(ILabelHandler handler, ILabel label) {} + + [MissingMapper] + public static void MapPadding(ILabelHandler handler, ILabel label) {} + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Label/LabelHandler.cs b/src/Core/src/Handlers/Label/LabelHandler.cs index d59dafa21a..e1ee2b8e94 100644 --- a/src/Core/src/Handlers/Label/LabelHandler.cs +++ b/src/Core/src/Handlers/Label/LabelHandler.cs @@ -5,7 +5,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiLabel; using PlatformView = AndroidX.AppCompat.Widget.AppCompatTextView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.TextBlock; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Label; +#elif NETSTANDARD || (NET6_0 && !IOS && !TIZEN) using PlatformView = System.Object; #endif @@ -15,7 +17,7 @@ namespace Microsoft.Maui.Handlers { public static IPropertyMapper Mapper = new PropertyMapper(ViewHandler.ViewMapper) { -#if __IOS__ +#if __IOS__ || TIZEN [nameof(ILabel.Background)] = MapBackground, [nameof(ILabel.Opacity)] = MapOpacity, #elif WINDOWS diff --git a/src/Core/src/Handlers/Layout/ILayoutHandler.cs b/src/Core/src/Handlers/Layout/ILayoutHandler.cs index a58e29d9bc..bf43bc63d2 100644 --- a/src/Core/src/Handlers/Layout/ILayoutHandler.cs +++ b/src/Core/src/Handlers/Layout/ILayoutHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.LayoutView; using PlatformView = Microsoft.Maui.Platform.LayoutViewGroup; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.LayoutPanel; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.LayoutCanvas; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs new file mode 100644 index 0000000000..d43c36aa9b --- /dev/null +++ b/src/Core/src/Handlers/Layout/LayoutHandler.Tizen.cs @@ -0,0 +1,176 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class LayoutHandler : ViewHandler + { + public override bool NeedsContainer => + VirtualView?.Background != null || + VirtualView?.Clip != null || + base.NeedsContainer; + + protected override LayoutCanvas CreatePlatformView() + { + if (VirtualView == null) + { + throw new InvalidOperationException($"{nameof(VirtualView)} must be set to create a Canvas"); + } + + if (NativeParent == null) + { + throw new InvalidOperationException($"{nameof(NativeParent)} cannot be null"); + } + + var view = new LayoutCanvas(NativeParent, VirtualView) + { + CrossPlatformMeasure = VirtualView.CrossPlatformMeasure, + CrossPlatformArrange = VirtualView.CrossPlatformArrange + }; + + view.Show(); + return view; + } + + public override Graphics.Size GetDesiredSize(double widthConstraint, double heightConstraint) + { + return VirtualView.CrossPlatformMeasure(widthConstraint, heightConstraint); + } + + public override void SetVirtualView(IView view) + { + base.SetVirtualView(view); + + _ = 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."); + + PlatformView.CrossPlatformMeasure = VirtualView.CrossPlatformMeasure; + PlatformView.CrossPlatformArrange = VirtualView.CrossPlatformArrange; + + PlatformView.Children.Clear(); + + foreach (var child in VirtualView.OrderByZIndex()) + { + PlatformView.Children.Add(child.ToPlatform(MauiContext)); + if (child.Handler is IPlatformViewHandler thandler) + { + thandler?.SetParent(this); + } + } + } + + public void Add(IView child) + { + _ = 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."); + + var targetIndex = VirtualView.GetLayoutHandlerIndex(child); + PlatformView.Children.Insert(targetIndex, child.ToPlatform(MauiContext)); + if (child.Handler is IPlatformViewHandler childHandler) + { + childHandler?.SetParent(this); + } + } + + public void Remove(IView child) + { + _ = 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."); + + if (child.Handler is IPlatformViewHandler thandler && child?.ToPlatform() is EvasObject childView) + { + PlatformView.Children.Remove(childView); + thandler.Dispose(); + } + } + + public void Clear() + { + if (PlatformView == null) + return; + + foreach (var child in PlatformView.Children) + { + child.Unrealize(); + } + PlatformView.Children.Clear(); + } + + public void Insert(int index, IView child) + { + _ = 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."); + + var targetIndex = VirtualView.GetLayoutHandlerIndex(child); + PlatformView.Children.Insert(targetIndex, child.ToPlatform(MauiContext)); + if (child.Handler is IPlatformViewHandler childHandler) + { + childHandler?.SetParent(this); + } + } + + public void Update(int index, IView child) + { + _ = 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."); + + var toBeRemoved = PlatformView.Children[index]; + PlatformView.Children.RemoveAt(index); + toBeRemoved.Unrealize(); + + var targetIndex = VirtualView.GetLayoutHandlerIndex(child); + PlatformView.Children.Insert(targetIndex, child.ToPlatform(MauiContext)); + if (child.Handler is IPlatformViewHandler childHandler) + { + childHandler?.SetParent(this); + } + } + + public void UpdateZIndex(IView child) + { + _ = 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."); + + EnsureZIndexOrder(child); + } + + void EnsureZIndexOrder(IView child) + { + if (PlatformView.Children.Count == 0) + { + return; + } + + var nativeChildView = child.ToPlatform(MauiContext!); + var currentIndex = PlatformView.Children.IndexOf(nativeChildView); + + if (currentIndex == -1) + { + return; + } + + var targetIndex = VirtualView.GetLayoutHandlerIndex(child); + if (targetIndex > currentIndex) + { + child.ToPlatform(MauiContext!).RaiseTop(); + for (int i = targetIndex+1; i < PlatformView.Children.Count; i++) + { + PlatformView.Children[i].RaiseTop(); + } + } + else + { + child.ToPlatform(MauiContext!).Lower(); + for (int i = targetIndex-1; i >= 0; i--) + { + PlatformView.Children[i].Lower(); + } + } + } + } +} diff --git a/src/Core/src/Handlers/Layout/LayoutHandler.cs b/src/Core/src/Handlers/Layout/LayoutHandler.cs index e17e7b4892..a7463ad42c 100644 --- a/src/Core/src/Handlers/Layout/LayoutHandler.cs +++ b/src/Core/src/Handlers/Layout/LayoutHandler.cs @@ -5,6 +5,8 @@ using PlatformView = Microsoft.Maui.Platform.LayoutView; using PlatformView = Microsoft.Maui.Platform.LayoutViewGroup; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.LayoutPanel; +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.LayoutCanvas; #elif NETSTANDARD using PlatformView = System.Object; #endif @@ -48,6 +50,10 @@ namespace Microsoft.Maui.Handlers public static void MapBackground(ILayoutHandler handler, ILayout layout) { +#if TIZEN + handler.UpdateValue(nameof(handler.ContainerView)); + handler.ToPlatform()?.UpdateBackground(layout); +#endif ((PlatformView?)handler.PlatformView)?.UpdateBackground(layout); } diff --git a/src/Core/src/Handlers/MenuBar/IMenuBarHandler.cs b/src/Core/src/Handlers/MenuBar/IMenuBarHandler.cs index 7db5e0ccfd..22c7c99bbd 100644 --- a/src/Core/src/Handlers/MenuBar/IMenuBarHandler.cs +++ b/src/Core/src/Handlers/MenuBar/IMenuBarHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.IUIMenuBuilder; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.MenuBar; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/MenuBar/MenuBarHandler.Tizen.cs b/src/Core/src/Handlers/MenuBar/MenuBarHandler.Tizen.cs new file mode 100644 index 0000000000..958cd367f2 --- /dev/null +++ b/src/Core/src/Handlers/MenuBar/MenuBarHandler.Tizen.cs @@ -0,0 +1,30 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class MenuBarHandler : ElementHandler, IMenuBarHandler + { + // TODO : Need to implement + protected override EvasObject CreatePlatformElement() + { + throw new NotImplementedException(); + } + + public void Add(IMenuBarItem view) + { + } + + public void Remove(IMenuBarItem view) + { + } + + public void Clear() + { + } + + public void Insert(int index, IMenuBarItem view) + { + } + } +} diff --git a/src/Core/src/Handlers/MenuBar/MenuBarHandler.cs b/src/Core/src/Handlers/MenuBar/MenuBarHandler.cs index 1165fc84a5..f5badf32ac 100644 --- a/src/Core/src/Handlers/MenuBar/MenuBarHandler.cs +++ b/src/Core/src/Handlers/MenuBar/MenuBarHandler.cs @@ -7,7 +7,9 @@ using PlatformView = UIKit.IUIMenuBuilder; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.MenuBar; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/MenuBarItem/IMenuBarItemHandler.cs b/src/Core/src/Handlers/MenuBarItem/IMenuBarItemHandler.cs index 63e3e1ef18..42a47d99fb 100644 --- a/src/Core/src/Handlers/MenuBarItem/IMenuBarItemHandler.cs +++ b/src/Core/src/Handlers/MenuBarItem/IMenuBarItemHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIMenu; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.MenuBarItem; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/MenuBarItem/MenuBarItemHandler.Tizen.cs b/src/Core/src/Handlers/MenuBarItem/MenuBarItemHandler.Tizen.cs new file mode 100644 index 0000000000..6ae7b2e33c --- /dev/null +++ b/src/Core/src/Handlers/MenuBarItem/MenuBarItemHandler.Tizen.cs @@ -0,0 +1,30 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class MenuBarItemHandler : ElementHandler, IMenuBarItemHandler + { + // TODO : Need to implement + protected override EvasObject CreatePlatformElement() + { + throw new NotImplementedException(); + } + + public void Add(IMenuElement view) + { + } + + public void Remove(IMenuElement view) + { + } + + public void Clear() + { + } + + public void Insert(int index, IMenuElement view) + { + } + } +} diff --git a/src/Core/src/Handlers/MenuBarItem/MenuBarItemHandler.cs b/src/Core/src/Handlers/MenuBarItem/MenuBarItemHandler.cs index 90f47944dd..574671a695 100644 --- a/src/Core/src/Handlers/MenuBarItem/MenuBarItemHandler.cs +++ b/src/Core/src/Handlers/MenuBarItem/MenuBarItemHandler.cs @@ -7,7 +7,9 @@ using PlatformView = UIKit.UIMenu; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.MenuBarItem; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/MenuFlyoutItem/IMenuFlyoutItemHandler.cs b/src/Core/src/Handlers/MenuFlyoutItem/IMenuFlyoutItemHandler.cs index 1a807e2734..00efe52954 100644 --- a/src/Core/src/Handlers/MenuFlyoutItem/IMenuFlyoutItemHandler.cs +++ b/src/Core/src/Handlers/MenuFlyoutItem/IMenuFlyoutItemHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIMenuElement; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.MenuFlyoutItem; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/MenuFlyoutItem/MenuFlyoutItemHandler.cs b/src/Core/src/Handlers/MenuFlyoutItem/MenuFlyoutItemHandler.cs index 9f870262aa..7b889eebd8 100644 --- a/src/Core/src/Handlers/MenuFlyoutItem/MenuFlyoutItemHandler.cs +++ b/src/Core/src/Handlers/MenuFlyoutItem/MenuFlyoutItemHandler.cs @@ -7,7 +7,9 @@ using PlatformView = UIKit.UIMenuElement; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.MenuFlyoutItem; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/MenuFlyoutSubItem/IMenuFlyoutSubItemHandler.cs b/src/Core/src/Handlers/MenuFlyoutSubItem/IMenuFlyoutSubItemHandler.cs index 4bf0139cd3..7dfb3c45c9 100644 --- a/src/Core/src/Handlers/MenuFlyoutSubItem/IMenuFlyoutSubItemHandler.cs +++ b/src/Core/src/Handlers/MenuFlyoutSubItem/IMenuFlyoutSubItemHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIMenu; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.MenuFlyoutSubItem; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/MenuFlyoutSubItem/MenuFlyoutSubItemHandler.Tizen.cs b/src/Core/src/Handlers/MenuFlyoutSubItem/MenuFlyoutSubItemHandler.Tizen.cs new file mode 100644 index 0000000000..c026c2cd65 --- /dev/null +++ b/src/Core/src/Handlers/MenuFlyoutSubItem/MenuFlyoutSubItemHandler.Tizen.cs @@ -0,0 +1,30 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class MenuFlyoutSubItemHandler + { + // TODO : Need to implement + protected override EvasObject CreatePlatformElement() + { + throw new NotImplementedException(); + } + + public void Add(IMenuElement view) + { + } + + public void Remove(IMenuElement view) + { + } + + public void Clear() + { + } + + public void Insert(int index, IMenuElement view) + { + } + } +} diff --git a/src/Core/src/Handlers/MenuFlyoutSubItem/MenuFlyoutSubItemHandler.cs b/src/Core/src/Handlers/MenuFlyoutSubItem/MenuFlyoutSubItemHandler.cs index 49874dbac7..31a90d74fd 100644 --- a/src/Core/src/Handlers/MenuFlyoutSubItem/MenuFlyoutSubItemHandler.cs +++ b/src/Core/src/Handlers/MenuFlyoutSubItem/MenuFlyoutSubItemHandler.cs @@ -7,7 +7,9 @@ using PlatformView = UIKit.UIMenu; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.MenuFlyoutSubItem; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/NavigationPage/INavigationViewHandler.cs b/src/Core/src/Handlers/NavigationPage/INavigationViewHandler.cs index 661564de59..368d795672 100644 --- a/src/Core/src/Handlers/NavigationPage/INavigationViewHandler.cs +++ b/src/Core/src/Handlers/NavigationPage/INavigationViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.Frame; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.Naviframe; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/NavigationPage/NavigationViewHandler.Tizen.cs b/src/Core/src/Handlers/NavigationPage/NavigationViewHandler.Tizen.cs new file mode 100644 index 0000000000..54fd8981be --- /dev/null +++ b/src/Core/src/Handlers/NavigationPage/NavigationViewHandler.Tizen.cs @@ -0,0 +1,341 @@ +#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 +{ + public partial class NavigationViewHandler : + ViewHandler, IPlatformViewHandler + { + readonly List _naviItemContentPartList = new List(); + TaskCompletionSource? _currentTaskSource = null; + IDictionary? _naviItemMap; + + IView? PreviousPage => NavigationStack.Count > 1 ? NavigationStack[NavigationStack.Count - 2] : null; + NaviItem? CurrentNaviItem => PlatformView.NavigationStack.Count > 0 ? PlatformView.NavigationStack.Last() : null; + NaviItem? PreviousNaviItem => PlatformView.NavigationStack.Count > 1 ? PlatformView.NavigationStack[PlatformView.NavigationStack.Count - 2] : null; + + public INavigationView NavigationView => ((INavigationView)VirtualView); + + public IReadOnlyList NavigationStack { get; private set; } = new List(); + + protected override Naviframe CreatePlatformView() + { + return new Naviframe(NativeParent) + { + PreserveContentOnPop = true, + DefaultBackButtonEnabled = false, + }; + } + + public static void RequestNavigation(INavigationViewHandler arg1, IStackNavigationView arg2, object? arg3) + { + if (arg1 is NavigationViewHandler platformHandler && arg3 is NavigationRequest navigationRequest) + { + platformHandler.NavigationStack = navigationRequest.NavigationStack; + } + //if (arg3 is NavigationRequest args) + // arg1.OnPushRequested(args); + } + + //private static void PushAsyncTo(NavigationViewHandler arg1, INavigationView arg2, object? arg3) + //{ + // if (arg3 is MauiNavigationRequestedEventArgs args) + // arg1.OnPushRequested(args); + //} + + //private static void PopAsyncTo(NavigationViewHandler 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 || PlatformView.NavigationStack.Count == 0) + // { + // _naviItemMap[e.Page] = PlatformView.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 (PlatformView.NavigationStack.Count == 1) + // CompleteCurrentNavigationTask(); + // } + // else + // { + // _naviItemMap[e.Page] = PlatformView.InsertAfter(PlatformView.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 == PlatformView.NavigationStack.Count) + // { + // //e.Page?.SendDisappearing(); + // //UpdateNavigationBar(PreviousPage, PreviousNaviItem); + + // if (e.Animated) + // { + // PlatformView.Pop(); + + // _currentTaskSource = new TaskCompletionSource(); + // e.Task = _currentTaskSource.Task; + + // // There is no TransitionFinished (AnimationFinished) event after Pop the last page + // if (PlatformView.NavigationStack.Count == 0) + // CompleteCurrentNavigationTask(); + // } + // else + // { + // CurrentNaviItem?.Delete(); + // } + + // if (_naviItemMap.ContainsKey(e.Page)) + // _naviItemMap.Remove(e.Page); + // } + //} + + protected override void ConnectHandler(Naviframe platformView) + { + base.ConnectHandler(platformView); + platformView.AnimationFinished += OnAnimationFinished; + _naviItemMap = new Dictionary(); + + if (VirtualView == null) + return; + + //VirtualView.PushRequested += OnPushRequested; + //VirtualView.PopRequested += OnPopRequested; + //VirtualView.InternalChildren.CollectionChanged += OnPageCollectionChanged; + + foreach (var page in NavigationStack) + { + _naviItemMap[page] = PlatformView.Push(CreateNavItem(page), SpanTitle(page)); + //page.PropertyChanged += NavigationBarPropertyChangedHandler; + + //UpdateHasNavigationBar(page); + } + } + + protected override void DisconnectHandler(Naviframe platformView) + { + base.DisconnectHandler(platformView); + platformView.AnimationFinished -= OnAnimationFinished; + + //VirtualView.PushRequested -= OnPushRequested; + //VirtualView.PopRequested -= OnPopRequested; + //VirtualView.InternalChildren.CollectionChanged -= OnPageCollectionChanged; + } + + //public static void MapPadding(NavigationViewHandler handler, INavigationView view) { } + + //public static void MapBarTextColor(NavigationViewHandler handler, INavigationView view) + //{ + // //handler.UpdateTitle(view.CurrentPage); + //} + + public static void MapBarBackground(INavigationViewHandler handler, INavigationView view) { } + + public static void MapTitleIcon(INavigationViewHandler handler, INavigationView view) { } + + public static void MapTitleView(INavigationViewHandler 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 || PlatformView.NavigationStack.Count == 0) + // { + // _naviItemMap[nre.Page] = PlatformView.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 (PlatformView.NavigationStack.Count == 1) + // CompleteCurrentNavigationTask(); + // } + // else + // { + // _naviItemMap[nre.Page] = PlatformView.InsertAfter(PlatformView.NavigationStack.Last(), CreateNavItem(nre.Page), SpanTitle(nre.Page.Title)); + // } + // UpdateHasNavigationBar(nre.Page); + //} + + //void OnPopRequested(object sender, NavigationRequestedEventArgs nre) + //{ + // if (VirtualView.InternalChildren.Count == PlatformView.NavigationStack.Count) + // { + // nre.Page?.SendDisappearing(); + // UpdateNavigationBar(PreviousPage, PreviousNaviItem); + + // if (nre.Animated) + // { + // PlatformView.Pop(); + + // _currentTaskSource = new TaskCompletionSource(); + // nre.Task = _currentTaskSource.Task; + + // // There is no TransitionFinished (AnimationFinished) event after Pop the last page + // if (PlatformView.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) && PlatformView.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.ToPlatform(MauiContext!); + } + } +} diff --git a/src/Core/src/Handlers/NavigationPage/NavigationViewHandler.cs b/src/Core/src/Handlers/NavigationPage/NavigationViewHandler.cs index 8955c05f05..338aab2669 100644 --- a/src/Core/src/Handlers/NavigationPage/NavigationViewHandler.cs +++ b/src/Core/src/Handlers/NavigationPage/NavigationViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.Frame; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.Naviframe; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Page/PageHandler.Tizen.cs b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs new file mode 100644 index 0000000000..457e54dbec --- /dev/null +++ b/src/Core/src/Handlers/Page/PageHandler.Tizen.cs @@ -0,0 +1,29 @@ +using Tizen.UIExtensions.Common; +using EColor = ElmSharp.Color; + +namespace Microsoft.Maui.Handlers +{ + public partial class PageHandler : ContentViewHandler + { + public static void MapBackground(IPageHandler handler, IContentView page) + { + handler.UpdateValue(nameof(handler.ContainerView)); + if (page.Background != null && handler.PlatformView.BackgroundColor != EColor.Transparent) + { + handler.PlatformView.BackgroundColor = EColor.Transparent; + } + handler.ToPlatform()?.UpdateBackground(page); + } + + [MissingMapper] + public static void MapTitle(IPageHandler handler, IContentView page) { } + + protected override ContentCanvas CreatePlatformView() + { + var view = base.CreatePlatformView(); + view.BackgroundColor = (DeviceInfo.GetDeviceType() == DeviceType.TV) ? EColor.Transparent : EColor.White; + + return view; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Page/PageHandler.cs b/src/Core/src/Handlers/Page/PageHandler.cs index 48eb693a9a..086e456e67 100644 --- a/src/Core/src/Handlers/Page/PageHandler.cs +++ b/src/Core/src/Handlers/Page/PageHandler.cs @@ -5,6 +5,9 @@ namespace Microsoft.Maui.Handlers { public static new IPropertyMapper Mapper = new PropertyMapper(ContentViewHandler.Mapper) { +#if TIZEN + [nameof(IContentView.Background)] = MapBackground, +#endif [nameof(ITitledElement.Title)] = MapTitle }; diff --git a/src/Core/src/Handlers/Picker/IPickerHandler.cs b/src/Core/src/Handlers/Picker/IPickerHandler.cs index 07f0a82d44..ca71249e62 100644 --- a/src/Core/src/Handlers/Picker/IPickerHandler.cs +++ b/src/Core/src/Handlers/Picker/IPickerHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiPicker; using PlatformView = Microsoft.Maui.Platform.MauiPicker; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.ComboBox; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Picker/PickerHandler.Tizen.cs b/src/Core/src/Handlers/Picker/PickerHandler.Tizen.cs new file mode 100644 index 0000000000..ad15e086e5 --- /dev/null +++ b/src/Core/src/Handlers/Picker/PickerHandler.Tizen.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using Tizen.UIExtensions.ElmSharp; +using TEntry = Tizen.UIExtensions.ElmSharp.Entry; +using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; +using DeviceInfo = Tizen.UIExtensions.Common.DeviceInfo; +using EcoreMainloop = ElmSharp.EcoreMainloop; +using List = ElmSharp.List; +using ListItem = ElmSharp.ListItem; + +namespace Microsoft.Maui.Handlers +{ + public partial class PickerHandler : ViewHandler + { + List? _list; + Dialog? _dialog; + Dictionary _itemToItemNumber = new Dictionary(); + + protected override TEntry CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + return new EditfieldEntry(NativeParent) + { + IsSingleLine = true, + InputPanelShowByOnDemand = true, + IsEditable = false, + HorizontalTextAlignment = TTextAlignment.Center + }; + } + + protected override void ConnectHandler(TEntry platformView) + { + platformView.SetVerticalTextAlignment(0.5); + + platformView.TextBlockFocused += OnTextBlockFocused; + platformView.EntryLayoutFocused += OnFocused; + platformView.EntryLayoutUnfocused += OnUnfocused; + + if (DeviceInfo.IsTV) + { + platformView.EntryLayoutFocused += OnLayoutFocused; + platformView.EntryLayoutUnfocused += OnLayoutUnfocused; + } + + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(TEntry platformView) + { + platformView.TextBlockFocused -= OnTextBlockFocused; + platformView.EntryLayoutFocused -= OnFocused; + platformView.EntryLayoutUnfocused -= OnUnfocused; + if (DeviceInfo.IsTV) + { + platformView.EntryLayoutFocused -= OnLayoutFocused; + platformView.EntryLayoutUnfocused -= OnLayoutUnfocused; + } + CleanView(); + base.DisconnectHandler(platformView); + } + + static void Reload(IPickerHandler handler) + { + if (handler.VirtualView == null || handler.PlatformView == null) + return; + + handler.PlatformView.UpdatePicker(handler.VirtualView); + } + + public static void MapReload(IPickerHandler handler, IPicker picker, object? args) => Reload(handler); + + public static void MapTitleColor(IPickerHandler handler, IPicker picker) + { + handler.PlatformView?.UpdateTitleColor(picker); + } + + public static void MapFont(IPickerHandler handler, IPicker picker) + { + var fontManager = handler.GetRequiredService(); + handler.PlatformView?.UpdateFont(picker, fontManager); + } + + public static void MapHorizontalTextAlignment(IPickerHandler handler, IPicker picker) + { + handler.PlatformView?.UpdateHorizontalTextAlignment(picker); + } + + public static void MapVerticalTextAlignment(IPickerHandler handler, IPicker picker) + { + handler.PlatformView?.UpdateHorizontalTextAlignment(picker); + } + + public static void MapTextColor(IPickerHandler handler, IPicker picker) + { + handler.PlatformView?.UpdateTextColor(picker); + } + + public static void MapTitle(IPickerHandler handler, IPicker picker) + { + handler.PlatformView?.UpdateTitle(picker); + } + + public static void MapSelectedIndex(IPickerHandler handler, IPicker picker) + { + handler.PlatformView?.UpdateSelectedIndex(picker); + } + + [MissingMapper] + public static void MapCharacterSpacing(IPickerHandler handler, IPicker picker) { } + + void OnLayoutFocused(object? sender, EventArgs e) + { + if (PlatformView == null) + return; + + PlatformView.FontSize = PlatformView.FontSize * 1.5; + } + + void OnLayoutUnfocused(object? sender, EventArgs e) + { + if (PlatformView == null) + return; + + PlatformView.FontSize = PlatformView.FontSize / 1.5; + } + + void OnTextBlockFocused(object? sender, EventArgs e) + { + if (VirtualView == null || PlatformView == null || NativeParent == null) + return; + + // For EFL Entry, the event will occur even if it is currently disabled. + // If the problem is resolved, no conditional statement is required. + if (VirtualView.IsEnabled) + { + int i = 0; + _dialog = new Dialog(NativeParent) + { + AlignmentX = -1, + AlignmentY = -1, + Title = VirtualView.Title, + }; + _dialog.Dismissed += OnDialogDismissed; + _dialog.BackButtonPressed += (object? senders, EventArgs es) => + { + _dialog.Dismiss(); + }; + + _list = new List(_dialog); + foreach (var s in VirtualView.GetItemsAsArray()) + { + ListItem item = _list.Append(s); + _itemToItemNumber[item] = i; + i++; + } + _list.ItemSelected += OnItemSelected; + _dialog.Content = _list; + + // You need to call Show() after ui thread occupation because of EFL problem. + // Otherwise, the content of the popup will not receive focus. + EcoreMainloop.Post(() => + { + _dialog.Show(); + _list.Show(); + }); + } + } + + void OnItemSelected(object? senderObject, EventArgs ev) + { + if (VirtualView == null || PlatformView == null || _dialog == null) + return; + + VirtualView.SelectedIndex = _itemToItemNumber[(senderObject as List)!.SelectedItem]; + _dialog.Dismiss(); + } + + void OnDialogDismissed(object? sender, EventArgs e) + { + CleanView(); + } + + void CleanView() + { + if (null != _list) + { + _list.Unrealize(); + _itemToItemNumber.Clear(); + _list = null; + } + if (null != _dialog) + { + _dialog.Unrealize(); + _dialog = null; + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Picker/PickerHandler.cs b/src/Core/src/Handlers/Picker/PickerHandler.cs index 5c455c7d28..ed86856ea3 100644 --- a/src/Core/src/Handlers/Picker/PickerHandler.cs +++ b/src/Core/src/Handlers/Picker/PickerHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiPicker; using PlatformView = Microsoft.Maui.Platform.MauiPicker; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.ComboBox; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs b/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs new file mode 100644 index 0000000000..fb41e29b85 --- /dev/null +++ b/src/Core/src/Handlers/ProgressBar/ProgressBarHandler.Tizen.cs @@ -0,0 +1,33 @@ +using Tizen.UIExtensions.ElmSharp; +using EColor = ElmSharp.Color; +using EProgressBar = ElmSharp.ProgressBar; + +namespace Microsoft.Maui.Handlers +{ + public partial class ProgressBarHandler : ViewHandler + { + protected virtual EColor DefaultColor => ThemeConstants.ProgressBar.ColorClass.Default; + + protected override EProgressBar CreatePlatformView() + { + var progressBar = new EProgressBar(NativeParent); + progressBar.Color = DefaultColor; + return progressBar; + } + + void SetupDefaults(EProgressBar platformView) + { + platformView.Color = ThemeConstants.ProgressBar.ColorClass.Default; + } + + public static void MapProgress(ProgressBarHandler handler, IProgress progress) + { + handler.PlatformView?.UpdateProgress(progress); + } + + public static void MapProgressColor(ProgressBarHandler handler, IProgress progress) + { + handler.PlatformView?.UpdateProgressColor(progress); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/RadioButton/IRadioButtonHandler.cs b/src/Core/src/Handlers/RadioButton/IRadioButtonHandler.cs index 2be7357184..52aba450f4 100644 --- a/src/Core/src/Handlers/RadioButton/IRadioButtonHandler.cs +++ b/src/Core/src/Handlers/RadioButton/IRadioButtonHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.ContentView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.RadioButton; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.MauiRadioButton; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs new file mode 100644 index 0000000000..67062c6269 --- /dev/null +++ b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.Tizen.cs @@ -0,0 +1,63 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class RadioButtonHandler : ViewHandler + { + protected override MauiRadioButton CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + return new MauiRadioButton(NativeParent) + { + StateValue = 1 + }; + } + + protected override void ConnectHandler(MauiRadioButton platformView) + { + PlatformView.ValueChanged += OnValueChanged; + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(MauiRadioButton platformView) + { + PlatformView.ValueChanged -= OnValueChanged; + base.DisconnectHandler(platformView); + } + + public static void MapIsChecked(IRadioButtonHandler handler, IRadioButton radioButton) + { + handler.PlatformView?.UpdateIsChecked(radioButton); + } + + [MissingMapper] + public static void MapContent(IRadioButtonHandler handler, IRadioButton radioButton) { } + + public static void MapTextColor(IRadioButtonHandler handler, ITextStyle textStyle) + { + handler.PlatformView?.UpdateTextColor(textStyle); + } + + [MissingMapper] + public static void MapCharacterSpacing(IRadioButtonHandler handler, ITextStyle textStyle) { } + + [MissingMapper] + public static void MapFont(IRadioButtonHandler handler, ITextStyle textStyle) { } + + [MissingMapper] + public static void MapStrokeColor(IRadioButtonHandler handler, IRadioButton radioButton) { } + + [MissingMapper] + public static void MapStrokeThickness(IRadioButtonHandler handler, IRadioButton radioButton) { } + + [MissingMapper] + public static void MapCornerRadius(IRadioButtonHandler handler, IRadioButton radioButton) { } + + void OnValueChanged(object? sender, EventArgs e) + { + VirtualView.IsChecked = PlatformView.GroupValue == 1 ? true : false; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/RadioButton/RadioButtonHandler.cs b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.cs index edef90e0f3..d01bd2b95f 100644 --- a/src/Core/src/Handlers/RadioButton/RadioButtonHandler.cs +++ b/src/Core/src/Handlers/RadioButton/RadioButtonHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.ContentView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.RadioButton; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.MauiRadioButton; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/RefreshView/IRefreshViewHandler.cs b/src/Core/src/Handlers/RefreshView/IRefreshViewHandler.cs index 891e11e6cc..a03db2b98a 100644 --- a/src/Core/src/Handlers/RefreshView/IRefreshViewHandler.cs +++ b/src/Core/src/Handlers/RefreshView/IRefreshViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiRefreshView; using PlatformView = Microsoft.Maui.Platform.MauiSwipeRefreshLayout; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.RefreshContainer; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Tizen.cs b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Tizen.cs new file mode 100644 index 0000000000..48106b8ff4 --- /dev/null +++ b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.Tizen.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Maui.Graphics; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + // TODO : Need to implement + public partial class RefreshViewHandler : ViewHandler + { + protected override EvasObject CreatePlatformView() => throw new NotImplementedException(); + + public static void MapIsRefreshing(IRefreshViewHandler handler, IRefreshView refreshView) + { + } + + public static void MapContent(IRefreshViewHandler handler, IRefreshView refreshView) + { + } + + public static void MapRefreshColor(IRefreshViewHandler handler, IRefreshView refreshView) + { + } + + public static void MapRefreshViewBackground(IRefreshViewHandler handler, IView view) + { + } + + } +} diff --git a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.cs b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.cs index 7668970848..665363ce21 100644 --- a/src/Core/src/Handlers/RefreshView/RefreshViewHandler.cs +++ b/src/Core/src/Handlers/RefreshView/RefreshViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiRefreshView; using PlatformView = Microsoft.Maui.Platform.MauiSwipeRefreshLayout; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.RefreshContainer; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/ScrollView/IScrollViewHandler.cs b/src/Core/src/Handlers/ScrollView/IScrollViewHandler.cs index d7b00ef4f8..babc3dfa45 100644 --- a/src/Core/src/Handlers/ScrollView/IScrollViewHandler.cs +++ b/src/Core/src/Handlers/ScrollView/IScrollViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIScrollView; using PlatformView = Microsoft.Maui.Platform.MauiScrollView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.ScrollViewer; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.ScrollView; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs new file mode 100644 index 0000000000..754e8c8d99 --- /dev/null +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.Tizen.cs @@ -0,0 +1,153 @@ +using System; +using Microsoft.Maui.Graphics; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using EContainer = ElmSharp.Container; +using EcoreMainloop = ElmSharp.EcoreMainloop; + +namespace Microsoft.Maui.Handlers +{ + public partial class ScrollViewHandler : ViewHandler + { + EContainer? _scrollCanvas; + + Box? Canvas => (Box?)_scrollCanvas; + + protected override ScrollView CreatePlatformView() + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} cannot be null"); + var scrollView = new ScrollView(NativeParent); + _scrollCanvas = new Box(scrollView); + scrollView.SetContent(_scrollCanvas); + return scrollView; + } + + protected override void ConnectHandler(ScrollView platformView) + { + base.ConnectHandler(platformView); + _ = Canvas ?? throw new InvalidOperationException($"{nameof(Canvas)} cannot be null"); + + platformView.Scrolled += OnScrolled; + Canvas.LayoutUpdated += OnContentLayoutUpdated; + } + + public override ElmSharp.Rect GetPlatformContentGeometry() + { + return Canvas?.Geometry ?? PlatformView.Geometry; + } + + protected override void DisconnectHandler(ScrollView platformView) + { + base.DisconnectHandler(platformView); + _ = Canvas ?? throw new InvalidOperationException($"{nameof(Canvas)} cannot be null"); + + platformView.Scrolled -= OnScrolled; + Canvas.LayoutUpdated -= OnContentLayoutUpdated; + } + + public override Graphics.Size GetDesiredSize(double widthConstraint, double heightConstraint) + { + return VirtualView.CrossPlatformMeasure(widthConstraint, heightConstraint); + } + + void ScrollAnimationEnded(object? sender, EventArgs e) + { + VirtualView.ScrollFinished(); + } + + void OnScrolled(object? sender, EventArgs e) + { + var region = PlatformView.CurrentRegion.ToDP(); + VirtualView.HorizontalOffset = region.X; + VirtualView.VerticalOffset = region.Y; + } + + void OnContentLayoutUpdated(object? sender, LayoutEventArgs e) + { + // It is workaround, + // in some case, before set a size of ScrollView, if content was filled with sized items, + // after size of ScrollView was updated, a content position was moved to somewhere. + if (VirtualView != null && VirtualView.PresentedContent != null) + { + var frame = VirtualView.PresentedContent.Frame; + VirtualView.PresentedContent.ToPlatform(MauiContext!)?.Move((int)e.Geometry.X + frame.X.ToScaledPixel(), (int)e.Geometry.Y + frame.Y.ToScaledPixel()); + } + + UpdateContentSize(); + } + + void UpdateContentSize() + { + _ = Canvas ?? throw new InvalidOperationException($"{nameof(Canvas)} cannot be null"); + + if (VirtualView == null || VirtualView.PresentedContent == null) + return; + + Canvas.MinimumWidth = (VirtualView.PresentedContent.Margin.HorizontalThickness + VirtualView.PresentedContent.Frame.Width + VirtualView.Padding.HorizontalThickness).ToScaledPixel(); + Canvas.MinimumHeight = (VirtualView.PresentedContent.Margin.VerticalThickness + VirtualView.PresentedContent.Frame.Height + VirtualView.Padding.VerticalThickness).ToScaledPixel(); + + // elm-scroller updates the CurrentRegion after render + EcoreMainloop.Post(() => + { + if (PlatformView != null) + { + OnScrolled(PlatformView, EventArgs.Empty); + } + }); + } + + public static void MapContent(IScrollViewHandler handler, IScrollView scrollView) + { + if (handler.MauiContext == null || scrollView.PresentedContent == null || handler is not ScrollViewHandler sHandler || sHandler.Canvas == null) + { + return; + } + + sHandler.Canvas.UnPackAll(); + sHandler.Canvas.PackEnd(scrollView.PresentedContent.ToPlatform(handler.MauiContext)); + if (scrollView.PresentedContent.Handler is IPlatformViewHandler thandler) + { + thandler?.SetParent(sHandler); + } + sHandler.UpdateContentSize(); + } + + public static void MapHorizontalScrollBarVisibility(IScrollViewHandler handler, IScrollView scrollView) + { + handler.PlatformView?.UpdateHorizontalScrollBarVisibility(scrollView.HorizontalScrollBarVisibility); + } + + public static void MapVerticalScrollBarVisibility(IScrollViewHandler handler, IScrollView scrollView) + { + handler.PlatformView?.UpdateVerticalScrollBarVisibility(scrollView.VerticalScrollBarVisibility); + } + + public static void MapOrientation(IScrollViewHandler handler, IScrollView scrollView) + { + handler.PlatformView?.UpdateOrientation(scrollView.Orientation); + } + + public static void MapRequestScrollTo(IScrollViewHandler handler, IScrollView scrollView, object? args) + { + if (args is ScrollToRequest request) + { + var x = request.HoriztonalOffset; + var y = request.VerticalOffset; + + var region = new ElmSharp.Rect + { + X = x.ToScaledPixel(), + Y = y.ToScaledPixel(), + Width = handler.PlatformView!.Geometry.Width, + Height = handler.PlatformView!.Geometry.Height + }; + handler.PlatformView.ScrollTo(region, !request.Instant); + + if (request.Instant) + { + scrollView.ScrollFinished(); + } + } + } + } +} diff --git a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.cs b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.cs index 2c715b6c34..25acbe9628 100644 --- a/src/Core/src/Handlers/ScrollView/ScrollViewHandler.cs +++ b/src/Core/src/Handlers/ScrollView/ScrollViewHandler.cs @@ -6,7 +6,9 @@ using PlatformView = UIKit.UIScrollView; using PlatformView = Microsoft.Maui.Platform.MauiScrollView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.ScrollViewer; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.ScrollView; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/SearchBar/ISearchBarHandler.cs b/src/Core/src/Handlers/SearchBar/ISearchBarHandler.cs index 0af23fc562..dbefd33d5c 100644 --- a/src/Core/src/Handlers/SearchBar/ISearchBarHandler.cs +++ b/src/Core/src/Handlers/SearchBar/ISearchBarHandler.cs @@ -8,7 +8,10 @@ using QueryEditor = Android.Widget.EditText; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.AutoSuggestBox; using QueryEditor = Microsoft.UI.Xaml.Controls.AutoSuggestBox; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.SearchBar; +using QueryEditor = Tizen.UIExtensions.ElmSharp.EditfieldEntry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; using QueryEditor = System.Object; #endif diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs new file mode 100644 index 0000000000..e44891b2d6 --- /dev/null +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.Tizen.cs @@ -0,0 +1,149 @@ +using System; +using Tizen.UIExtensions.ElmSharp; +using EEntry = ElmSharp.Entry; +using InputPanelReturnKeyType = ElmSharp.InputPanelReturnKeyType; + +namespace Microsoft.Maui.Handlers +{ + public partial class SearchBarHandler : ViewHandler + { + EditfieldEntry? _editor; + + public EditfieldEntry? QueryEditor => _editor; + + protected override SearchBar CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + var searchBar = new SearchBar(NativeParent) + { + IsSingleLine = true + }; + searchBar.SetInputPanelReturnKeyType(InputPanelReturnKeyType.Search); + + _editor = searchBar; + return searchBar; + } + + protected override void ConnectHandler(SearchBar platformView) + { + platformView.Activated += OnActivated; + platformView.TextChanged += OnTextChanged; + platformView.PrependMarkUpFilter(MaxLengthFilter); + platformView.EntryLayoutFocused += OnFocused; + platformView.EntryLayoutUnfocused += OnUnfocused; + + } + + protected override void DisconnectHandler(SearchBar platformView) + { + platformView.Activated -= OnActivated; + platformView.TextChanged -= OnTextChanged; + platformView.EntryLayoutFocused -= OnFocused; + platformView.EntryLayoutUnfocused -= OnUnfocused; + } + + public static void MapText(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdateText(searchBar); + + // Any text update requires that we update any attributed string formatting + MapFormatting(handler, searchBar); + } + public static void MapPlaceholder(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdatePlaceholder(searchBar); + } + + public static void MapPlaceholderColor(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdatePlaceholderColor(searchBar); + } + + public static void MapFont(ISearchBarHandler handler, ISearchBar searchBar) + { + var fontManager = handler.GetRequiredService(); + + handler.PlatformView?.UpdateFont(searchBar, fontManager); + } + + public static void MapHorizontalTextAlignment(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdateHorizontalTextAlignment(searchBar); + } + + public static void MapVerticalTextAlignment(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdateVerticalTextAlignment(searchBar); + } + + public static void MapTextColor(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdateTextColor(searchBar); + } + + public static void MapMaxLength(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdateMaxLength(searchBar); + } + + public static void MapIsReadOnly(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdateIsReadOnly(searchBar); + } + + public static void MapIsTextPredictionEnabled(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdateIsTextPredictionEnabled(searchBar); + } + + public static void MapKeyboard(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdateKeyboard(searchBar); + } + + public static void MapFormatting(ISearchBarHandler handler, ISearchBar searchBar) + { + // Update all of the attributed text formatting properties + // Setting any of those may have removed text alignment settings, + // so we need to make sure those are applied, too + handler.PlatformView?.UpdateMaxLength(searchBar); + handler.PlatformView?.UpdateHorizontalTextAlignment(searchBar); + } + + public static void MapCancelButtonColor(ISearchBarHandler handler, ISearchBar searchBar) + { + handler.PlatformView?.UpdateCancelButtonColor(searchBar); + } + + [MissingMapper] + public static void MapCharacterSpacing(ISearchBarHandler handler, ISearchBar searchBar) { } + + string? MaxLengthFilter(EEntry searchBar, string s) + { + if (VirtualView == null || PlatformView == null) + return null; + + if (searchBar.Text.Length < VirtualView.MaxLength) + return s; + + return null; + } + + void OnTextChanged(object? sender, EventArgs e) + { + if (VirtualView == null || PlatformView == null) + return; + + VirtualView.Text = PlatformView.Text; + } + + void OnActivated(object? sender, EventArgs e) + { + if (PlatformView == null) + return; + + PlatformView.HideInputPanel(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/SearchBar/SearchBarHandler.cs b/src/Core/src/Handlers/SearchBar/SearchBarHandler.cs index 4b82bf00db..8a192a8b80 100644 --- a/src/Core/src/Handlers/SearchBar/SearchBarHandler.cs +++ b/src/Core/src/Handlers/SearchBar/SearchBarHandler.cs @@ -5,7 +5,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiSearchBar; using PlatformView = AndroidX.AppCompat.Widget.SearchView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.AutoSuggestBox; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.SearchBar; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/ShapeView/IShapeViewHandler.cs b/src/Core/src/Handlers/ShapeView/IShapeViewHandler.cs index 814fc0cc5d..91e328fefe 100644 --- a/src/Core/src/Handlers/ShapeView/IShapeViewHandler.cs +++ b/src/Core/src/Handlers/ShapeView/IShapeViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiShapeView; using PlatformView = Microsoft.Maui.Platform.MauiShapeView; #elif WINDOWS using PlatformView = Microsoft.Maui.Graphics.Win2D.W2DGraphicsView; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.MauiShapeView; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/ShapeView/ShapeViewHandler.Tizen.cs b/src/Core/src/Handlers/ShapeView/ShapeViewHandler.Tizen.cs new file mode 100644 index 0000000000..528167a5b6 --- /dev/null +++ b/src/Core/src/Handlers/ShapeView/ShapeViewHandler.Tizen.cs @@ -0,0 +1,76 @@ +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class ShapeViewHandler : ViewHandler + { + protected virtual double MinimumSize => 40d; + + protected override MauiShapeView CreatePlatformView() + { + return new MauiShapeView(NativeParent!) + { + MinimumWidth = MinimumSize.ToScaledPixel(), + MinimumHeight = MinimumSize.ToScaledPixel() + }; + } + + protected override void SetupContainer() + { + base.SetupContainer(); + ContainerView?.UpdateShape(VirtualView.Shape); + } + + public static void MapShape(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.UpdateShape(shapeView); + if (handler.ContainerView is WrapperView wrapperView) + wrapperView.UpdateShape(shapeView.Shape); + } + + public static void MapAspect(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + + public static void MapFill(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + + public static void MapStroke(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + + public static void MapStrokeThickness(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + + public static void MapStrokeDashPattern(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + + public static void MapStrokeDashOffset(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + + public static void MapStrokeLineCap(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + + public static void MapStrokeLineJoin(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + + public static void MapStrokeMiterLimit(IShapeViewHandler handler, IShapeView shapeView) + { + handler.PlatformView?.InvalidateShape(shapeView); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/ShapeView/ShapeViewHandler.cs b/src/Core/src/Handlers/ShapeView/ShapeViewHandler.cs index e53c785757..423bbbb094 100644 --- a/src/Core/src/Handlers/ShapeView/ShapeViewHandler.cs +++ b/src/Core/src/Handlers/ShapeView/ShapeViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiShapeView; using PlatformView = Microsoft.Maui.Platform.MauiShapeView; #elif WINDOWS using PlatformView = Microsoft.Maui.Graphics.Win2D.W2DGraphicsView; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.MauiShapeView; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Slider/ISliderHandler.cs b/src/Core/src/Handlers/Slider/ISliderHandler.cs index 8106dc4dac..77bc21bae4 100644 --- a/src/Core/src/Handlers/Slider/ISliderHandler.cs +++ b/src/Core/src/Handlers/Slider/ISliderHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UISlider; using PlatformView = Android.Widget.SeekBar; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.Slider; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.Slider; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Slider/SliderHandler.Tizen.cs b/src/Core/src/Handlers/Slider/SliderHandler.Tizen.cs new file mode 100644 index 0000000000..254294ce62 --- /dev/null +++ b/src/Core/src/Handlers/Slider/SliderHandler.Tizen.cs @@ -0,0 +1,90 @@ +using System; +using Tizen.UIExtensions.ElmSharp; +using EColor = ElmSharp.Color; +using ESlider = ElmSharp.Slider; + +namespace Microsoft.Maui.Handlers +{ + public partial class SliderHandler : ViewHandler + { + static EColor? DefaultMinTrackColor; + static EColor? DefaultMaxTrackColor; + static EColor? DefaultThumbColor; + + protected override ESlider CreatePlatformView() => new ESlider(NativeParent); + + protected override void ConnectHandler(ESlider platformView) + { + platformView!.ValueChanged += OnControlValueChanged; + platformView!.DragStarted += OnDragStarted; + platformView!.DragStopped += OnDragStopped; + } + + protected override void DisconnectHandler(ESlider platformView) + { + platformView!.ValueChanged -= OnControlValueChanged; + platformView!.DragStarted -= OnDragStarted; + platformView!.DragStopped -= OnDragStopped; + } + + void SetupDefaults(ESlider platformView) + { + DefaultMinTrackColor = platformView.GetBarColor(); + DefaultMaxTrackColor = platformView.GetBackgroundColor(); + DefaultThumbColor = platformView.GetHandlerColor(); + } + + public static void MapMinimum(ISliderHandler handler, ISlider slider) + { + handler.PlatformView?.UpdateMinimum(slider); + } + + public static void MapMaximum(ISliderHandler handler, ISlider slider) + { + handler.PlatformView?.UpdateMaximum(slider); + } + + + public static void MapValue(ISliderHandler handler, ISlider slider) + { + handler.PlatformView?.UpdateValue(slider); + } + + public static void MapMinimumTrackColor(ISliderHandler handler, ISlider slider) + { + handler.PlatformView?.UpdateMinimumTrackColor(slider, DefaultMinTrackColor); + } + + public static void MapMaximumTrackColor(ISliderHandler handler, ISlider slider) + { + handler.PlatformView?.UpdateMaximumTrackColor(slider, DefaultMaxTrackColor); + } + + public static void MapThumbColor(ISliderHandler handler, ISlider slider) + { + + handler.PlatformView?.UpdateThumbColor(slider, DefaultThumbColor); + } + + [MissingMapper] + public static void MapThumbImageSource(ISliderHandler handler, ISlider slider) { } + + void OnControlValueChanged(object? sender, EventArgs eventArgs) + { + if (PlatformView == null || VirtualView == null) + return; + + VirtualView.Value = PlatformView.Value; + } + + void OnDragStarted(object? sender, EventArgs e) + { + VirtualView?.DragStarted(); + } + + void OnDragStopped(object? sender, EventArgs e) + { + VirtualView?.DragCompleted(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Slider/SliderHandler.cs b/src/Core/src/Handlers/Slider/SliderHandler.cs index d9bea82969..44dfb79097 100644 --- a/src/Core/src/Handlers/Slider/SliderHandler.cs +++ b/src/Core/src/Handlers/Slider/SliderHandler.cs @@ -5,7 +5,9 @@ using PlatformView = UIKit.UISlider; using PlatformView = Android.Widget.SeekBar; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.Slider; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.Slider; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Stepper/StepperHandler.Tizen.cs b/src/Core/src/Handlers/Stepper/StepperHandler.Tizen.cs new file mode 100644 index 0000000000..05f18aed77 --- /dev/null +++ b/src/Core/src/Handlers/Stepper/StepperHandler.Tizen.cs @@ -0,0 +1,48 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class StepperHandler : ViewHandler + { + protected override Spinner CreatePlatformView() => new Spinner(NativeParent) { IsEditable = false }; + + protected override void ConnectHandler(Spinner platformView) + { + platformView!.ValueChanged += OnValueChanged; + } + + protected override void DisconnectHandler(Spinner platformView) + { + platformView!.ValueChanged -= OnValueChanged; + } + + public static void MapMinimum(StepperHandler handler, IStepper stepper) + { + handler.PlatformView?.UpdateMinimum(stepper); + } + + public static void MapMaximum(StepperHandler handler, IStepper stepper) + { + handler.PlatformView?.UpdateMaximum(stepper); + } + + public static void MapIncrement(StepperHandler handler, IStepper stepper) + { + handler.PlatformView?.UpdateIncrement(stepper); + } + + public static void MapValue(StepperHandler handler, IStepper stepper) + { + handler.PlatformView?.UpdateValue(stepper); + } + + void OnValueChanged(object? sender, EventArgs e) + { + if (VirtualView == null || PlatformView == null) + return; + + VirtualView.Value = PlatformView.Value; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/SwipeItemMenuItem/ISwipeItemMenuItemHandler.cs b/src/Core/src/Handlers/SwipeItemMenuItem/ISwipeItemMenuItemHandler.cs index 3a5141371a..9c5cee02e6 100644 --- a/src/Core/src/Handlers/SwipeItemMenuItem/ISwipeItemMenuItemHandler.cs +++ b/src/Core/src/Handlers/SwipeItemMenuItem/ISwipeItemMenuItemHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIButton; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.SwipeItem; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.Tizen.cs b/src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.Tizen.cs new file mode 100644 index 0000000000..e5a57db528 --- /dev/null +++ b/src/Core/src/Handlers/SwipeItemMenuItem/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 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/SwipeItemMenuItem/SwipeItemMenuItemHandler.cs b/src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.cs index 371a3d8c1d..f029e52191 100644 --- a/src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.cs +++ b/src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIButton; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.SwipeItem; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/SwipeItemView/ISwipeItemViewHandler.cs b/src/Core/src/Handlers/SwipeItemView/ISwipeItemViewHandler.cs index 210985589d..950b0f48a6 100644 --- a/src/Core/src/Handlers/SwipeItemView/ISwipeItemViewHandler.cs +++ b/src/Core/src/Handlers/SwipeItemView/ISwipeItemViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.ContentView; using PlatformView = Microsoft.Maui.Platform.ContentViewGroup; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.ContentCanvas; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/SwipeItemView/SwipeItemViewHandler.Tizen.cs b/src/Core/src/Handlers/SwipeItemView/SwipeItemViewHandler.Tizen.cs new file mode 100644 index 0000000000..a02c369b2e --- /dev/null +++ b/src/Core/src/Handlers/SwipeItemView/SwipeItemViewHandler.Tizen.cs @@ -0,0 +1,73 @@ +using System; +using PlatformView = Microsoft.Maui.Platform.ContentCanvas; + +namespace Microsoft.Maui.Handlers +{ + public partial class SwipeItemViewHandler : ViewHandler, ISwipeItemViewHandler + { + IPlatformViewHandler? _contentHandler; + + 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(ISwipeItemViewHandler handler, ISwipeItemView page) + { + if (handler is SwipeItemViewHandler platformHandler) + platformHandler.UpdateContent(); + } + + public static void MapVisibility(ISwipeItemViewHandler handler, ISwipeItemView view) + { + //TODO : need to update + //var swipeView = handler.PlatformView.GetParentOfType(); + //if (swipeView != null) + // swipeView.UpdateIsVisibleSwipeItem(view); + + //handler.PlatformView.UpdateVisibility(view.Visibility); + } + } +} diff --git a/src/Core/src/Handlers/SwipeItemView/SwipeItemViewHandler.cs b/src/Core/src/Handlers/SwipeItemView/SwipeItemViewHandler.cs index a79138dffa..7809d57261 100644 --- a/src/Core/src/Handlers/SwipeItemView/SwipeItemViewHandler.cs +++ b/src/Core/src/Handlers/SwipeItemView/SwipeItemViewHandler.cs @@ -5,7 +5,9 @@ using PlatformView = Microsoft.Maui.Platform.ContentView; using PlatformView = Microsoft.Maui.Platform.ContentViewGroup; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.ContentCanvas; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/SwipeView/ISwipeViewHandler.cs b/src/Core/src/Handlers/SwipeView/ISwipeViewHandler.cs index a562934331..66f2b80199 100644 --- a/src/Core/src/Handlers/SwipeView/ISwipeViewHandler.cs +++ b/src/Core/src/Handlers/SwipeView/ISwipeViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiSwipeView; using PlatformView = Microsoft.Maui.Platform.MauiSwipeView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.SwipeControl; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif @@ -15,4 +17,4 @@ namespace Microsoft.Maui.Handlers new ISwipeView VirtualView { get; } new PlatformView PlatformView { get; } } -} \ No newline at end of file +} diff --git a/src/Core/src/Handlers/SwipeView/SwipeViewHandler.Tizen.cs b/src/Core/src/Handlers/SwipeView/SwipeViewHandler.Tizen.cs new file mode 100644 index 0000000000..c5914049c5 --- /dev/null +++ b/src/Core/src/Handlers/SwipeView/SwipeViewHandler.Tizen.cs @@ -0,0 +1,61 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class SwipeViewHandler : ViewHandler + { + // TODO : Need to implement + protected override EvasObject CreatePlatformView() + { + throw new NotImplementedException(); + } + + 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."); + } + + public static void MapContent(ISwipeViewHandler handler, ISwipeView view) + { + _ = handler.PlatformView ?? throw new InvalidOperationException($"{nameof(PlatformView)} should have been set by base class."); + _ = handler.MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + _ = handler.VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} should have been set by base class."); + } + + public static void MapSwipeTransitionMode(ISwipeViewHandler handler, ISwipeView swipeView) + { + } + + public static void MapRequestOpen(ISwipeViewHandler handler, ISwipeView swipeView, object? args) + { + if (args is not SwipeViewOpenRequest request) + { + return; + } + } + + public static void MapRequestClose(ISwipeViewHandler handler, ISwipeView swipeView, object? args) + { + if (args is not SwipeViewCloseRequest request) + { + return; + } + } + + public static void MapLeftItems(ISwipeViewHandler handler, ISwipeView view) + { + } + public static void MapTopItems(ISwipeViewHandler handler, ISwipeView view) + { + } + public static void MapRightItems(ISwipeViewHandler handler, ISwipeView view) + { + } + public static void MapBottomItems(ISwipeViewHandler handler, ISwipeView view) + { + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/SwipeView/SwipeViewHandler.cs b/src/Core/src/Handlers/SwipeView/SwipeViewHandler.cs index e0f41a232d..4f58823e10 100644 --- a/src/Core/src/Handlers/SwipeView/SwipeViewHandler.cs +++ b/src/Core/src/Handlers/SwipeView/SwipeViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = Microsoft.Maui.Platform.MauiSwipeView; using PlatformView = Microsoft.Maui.Platform.MauiSwipeView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.SwipeControl; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif @@ -53,4 +55,4 @@ namespace Microsoft.Maui.Handlers PlatformView ISwipeViewHandler.PlatformView => PlatformView; } -} \ No newline at end of file +} diff --git a/src/Core/src/Handlers/Switch/ISwitchHandler.cs b/src/Core/src/Handlers/Switch/ISwitchHandler.cs index e9b549772b..452a9a6092 100644 --- a/src/Core/src/Handlers/Switch/ISwitchHandler.cs +++ b/src/Core/src/Handlers/Switch/ISwitchHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UISwitch; using PlatformView = AndroidX.AppCompat.Widget.SwitchCompat; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.ToggleSwitch; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.Check; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Switch/SwitchHandler.Tizen.cs b/src/Core/src/Handlers/Switch/SwitchHandler.Tizen.cs new file mode 100644 index 0000000000..a41c763732 --- /dev/null +++ b/src/Core/src/Handlers/Switch/SwitchHandler.Tizen.cs @@ -0,0 +1,48 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class SwitchHandler : ViewHandler + { + protected override Check CreatePlatformView() => new Check(NativeParent) + { + Style = "toggle" + }; + + protected override void ConnectHandler(Check nativeView) + { + base.ConnectHandler(nativeView); + nativeView!.StateChanged += OnStateChanged; + } + + protected override void DisconnectHandler(Check nativeView) + { + base.DisconnectHandler(nativeView); + nativeView!.StateChanged -= OnStateChanged; + } + + public static void MapIsOn(ISwitchHandler handler, ISwitch view) + { + handler.PlatformView?.UpdateIsOn(view); + } + + public static void MapTrackColor(ISwitchHandler handler, ISwitch view) + { + handler.PlatformView?.UpdateTrackColor(view); + } + + public static void MapThumbColor(ISwitchHandler handler, ISwitch view) + { + handler.PlatformView?.UpdateThumbColor(view); + } + + void OnStateChanged(object? sender, EventArgs e) + { + if (VirtualView == null || PlatformView == null) + return; + + VirtualView.IsOn = PlatformView.IsChecked; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Switch/SwitchHandler.cs b/src/Core/src/Handlers/Switch/SwitchHandler.cs index d03bac9f40..5c36e2ee1a 100644 --- a/src/Core/src/Handlers/Switch/SwitchHandler.cs +++ b/src/Core/src/Handlers/Switch/SwitchHandler.cs @@ -5,7 +5,9 @@ using PlatformView = UIKit.UISwitch; using PlatformView = AndroidX.AppCompat.Widget.SwitchCompat; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.ToggleSwitch; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.Check; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/TabbedView/TabbedViewHandler.cs b/src/Core/src/Handlers/TabbedView/TabbedViewHandler.cs index fe4c17f3b2..61a1582160 100644 --- a/src/Core/src/Handlers/TabbedView/TabbedViewHandler.cs +++ b/src/Core/src/Handlers/TabbedView/TabbedViewHandler.cs @@ -7,7 +7,9 @@ using PlatformView = UIKit.UIView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/TimePicker/ITimePickerHandler.cs b/src/Core/src/Handlers/TimePicker/ITimePickerHandler.cs index dfc5b840ed..2cb1e4e6b4 100644 --- a/src/Core/src/Handlers/TimePicker/ITimePickerHandler.cs +++ b/src/Core/src/Handlers/TimePicker/ITimePickerHandler.cs @@ -6,7 +6,9 @@ using PlatformView = UIKit.UIDatePicker; using PlatformView = Microsoft.Maui.Platform.MauiTimePicker; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.TimePicker; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/TimePicker/TimePickerHandler.Tizen.cs b/src/Core/src/Handlers/TimePicker/TimePickerHandler.Tizen.cs new file mode 100644 index 0000000000..1ef8288daa --- /dev/null +++ b/src/Core/src/Handlers/TimePicker/TimePickerHandler.Tizen.cs @@ -0,0 +1,131 @@ +using System; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using TEntry = Tizen.UIExtensions.ElmSharp.Entry; +using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; +using EcoreMainloop = ElmSharp.EcoreMainloop; + +namespace Microsoft.Maui.Handlers +{ + public partial class TimePickerHandler : ViewHandler + { + const string DialogTitle = "Choose Time"; + Lazy? _lazyDialog; + + protected override TEntry CreatePlatformView() + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + var entry = new EditfieldEntry(NativeParent) + { + IsSingleLine = true, + HorizontalTextAlignment = TTextAlignment.Center, + InputPanelShowByOnDemand = true, + IsEditable = false + }; + entry.SetVerticalTextAlignment(0.5); + return entry; + } + + protected override void ConnectHandler(TEntry platformView) + { + _ = NativeParent ?? throw new ArgumentNullException(nameof(NativeParent)); + + platformView.TextBlockFocused += OnTextBlockFocused; + platformView.EntryLayoutFocused += OnFocused; + platformView.EntryLayoutUnfocused += OnUnfocused; + + _lazyDialog = new Lazy(() => + { + var dialog = new DateTimePickerDialog(NativeParent) + { + Mode = DateTimePickerMode.Time, + Title = DialogTitle + }; + dialog.DateTimeChanged += OnDateTimeChanged; + dialog.PickerOpened += OnPickerOpened; + dialog.PickerClosed += OnPickerClosed; + return dialog; + }); + + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(TEntry platformView) + { + if (_lazyDialog != null && _lazyDialog.IsValueCreated) + { + _lazyDialog.Value.DateTimeChanged -= OnDateTimeChanged; + _lazyDialog.Value.PickerOpened -= OnPickerOpened; + _lazyDialog.Value.PickerClosed -= OnPickerClosed; + _lazyDialog.Value.Unrealize(); + _lazyDialog = null; + } + + platformView.TextBlockFocused -= OnTextBlockFocused; + platformView.EntryLayoutFocused -= OnFocused; + platformView.EntryLayoutUnfocused -= OnUnfocused; + + base.DisconnectHandler(platformView); + } + + public static void MapFormat(ITimePickerHandler handler, ITimePicker timePicker) + { + handler.PlatformView?.UpdateFormat(timePicker); + } + + public static void MapTime(ITimePickerHandler handler, ITimePicker timePicker) + { + handler.PlatformView?.UpdateTime(timePicker); + } + + public static void MapFont(ITimePickerHandler handler, ITimePicker timePicker) + { + var fontManager = handler.GetRequiredService(); + handler.PlatformView?.UpdateFont(timePicker, fontManager); + } + + public static void MapTextColor(ITimePickerHandler handler, ITimePicker timePicker) + { + handler.PlatformView?.UpdateTextColor(timePicker); + } + + [MissingMapper] + public static void MapCharacterSpacing(ITimePickerHandler handler, ITimePicker timePicker) { } + + protected virtual void OnDateTimeChanged(object? sender, DateChangedEventArgs dcea) + { + if (VirtualView == null || PlatformView == null) + return; + + VirtualView.Time = dcea.NewDate.TimeOfDay; + } + + void OnTextBlockFocused(object? sender, EventArgs e) + { + if (VirtualView == null || PlatformView == null || _lazyDialog == null) + return; + + // For EFL Entry, the event will occur even if it is currently disabled. + // If the problem is resolved, no conditional statement is required. + if (VirtualView.IsEnabled) + { + var dialog = _lazyDialog.Value; + dialog.DateTime -= dialog.DateTime.TimeOfDay; + dialog.DateTime += VirtualView.Time; + + // You need to call Show() after ui thread occupation because of EFL problem. + // Otherwise, the content of the popup will not receive focus. + EcoreMainloop.Post(() => dialog.Show()); + } + } + + protected virtual void OnPickerOpened(object? sender, EventArgs args) + { + } + + protected virtual void OnPickerClosed(object? sender, EventArgs args) + { + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/TimePicker/TimePickerHandler.cs b/src/Core/src/Handlers/TimePicker/TimePickerHandler.cs index 84fbd67ade..8d7c558098 100644 --- a/src/Core/src/Handlers/TimePicker/TimePickerHandler.cs +++ b/src/Core/src/Handlers/TimePicker/TimePickerHandler.cs @@ -6,7 +6,9 @@ using PlatformView = UIKit.UIDatePicker; using PlatformView = Microsoft.Maui.Platform.MauiTimePicker; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.TimePicker; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Entry; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Toolbar/IToolbarHandler.cs b/src/Core/src/Handlers/Toolbar/IToolbarHandler.cs index 280bffd7b8..8e61d7a480 100644 --- a/src/Core/src/Handlers/Toolbar/IToolbarHandler.cs +++ b/src/Core/src/Handlers/Toolbar/IToolbarHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UINavigationBar; using PlatformView = Google.Android.Material.AppBar.MaterialToolbar; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.MauiToolbar; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView =ElmSharp.Toolbar; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Toolbar/ToolbarHandler.Tizen.cs b/src/Core/src/Handlers/Toolbar/ToolbarHandler.Tizen.cs new file mode 100644 index 0000000000..3603642efa --- /dev/null +++ b/src/Core/src/Handlers/Toolbar/ToolbarHandler.Tizen.cs @@ -0,0 +1,16 @@ +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class ToolbarHandler : ElementHandler + { + protected override Toolbar CreatePlatformElement() + { + throw new System.NotImplementedException(); + } + + public static void MapTitle(IToolbarHandler arg1, IToolbar arg2) + { + } + } +} diff --git a/src/Core/src/Handlers/Toolbar/ToolbarHandler.cs b/src/Core/src/Handlers/Toolbar/ToolbarHandler.cs index 93de9b2fde..1cc4a0f3e6 100644 --- a/src/Core/src/Handlers/Toolbar/ToolbarHandler.cs +++ b/src/Core/src/Handlers/Toolbar/ToolbarHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UINavigationBar; using PlatformView = Google.Android.Material.AppBar.MaterialToolbar; #elif WINDOWS using PlatformView = Microsoft.Maui.Platform.MauiToolbar; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView =ElmSharp.Toolbar; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/View/ViewHandler.Tizen.cs b/src/Core/src/Handlers/View/ViewHandler.Tizen.cs new file mode 100644 index 0000000000..7032b427d4 --- /dev/null +++ b/src/Core/src/Handlers/View/ViewHandler.Tizen.cs @@ -0,0 +1,130 @@ +using System; +using ElmSharp; +using PlatformView = ElmSharp.EvasObject; + +namespace Microsoft.Maui.Handlers +{ + public partial class ViewHandler + { + static partial void MappingFrame(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapTranslationX(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapTranslationY(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapScale(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapScaleX(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapScaleY(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapRotation(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapRotationX(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapRotationY(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapAnchorX(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + public static void MapAnchorY(IViewHandler handler, IView view) + { + UpdateTransformation(handler, view); + } + + internal static void UpdateTransformation(IViewHandler handler, IView view) + { + handler.ToPlatform()?.UpdateTransformation(view); + } + + protected virtual void OnPlatformViewDeleted() + { + } + + 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(PlatformView? platformView) + { + if (platformView == null) + return; + + + platformView.Deleted += OnPlatformViewDeleted; + + if (platformView is Widget widget) + { + widget.Focused += OnFocused; + widget.Unfocused += OnUnfocused; + } + } + + partial void DisconnectingHandler(PlatformView platformView) + { + if (platformView == null) + return; + + platformView.Deleted -= OnPlatformViewDeleted; + } + + public virtual bool NeedsContainer + { + get + { + if(VirtualView is IBorderView border) + return border?.Shape != null || border?.Stroke != null; + + return false; + } + } + + void OnPlatformViewDeleted(object? sender, EventArgs e) + { + OnPlatformViewDeleted(); + } + } +} diff --git a/src/Core/src/Handlers/View/ViewHandler.cs b/src/Core/src/Handlers/View/ViewHandler.cs index 12e0ab82fc..92ada0d938 100644 --- a/src/Core/src/Handlers/View/ViewHandler.cs +++ b/src/Core/src/Handlers/View/ViewHandler.cs @@ -7,6 +7,8 @@ using PlatformView = UIKit.UIView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; #elif NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/View/ViewHandlerOfT.Tizen.cs b/src/Core/src/Handlers/View/ViewHandlerOfT.Tizen.cs new file mode 100644 index 0000000000..06e5383c59 --- /dev/null +++ b/src/Core/src/Handlers/View/ViewHandlerOfT.Tizen.cs @@ -0,0 +1,202 @@ +using System; +using ElmSharp; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using ERect = ElmSharp.Rect; +using ESize = ElmSharp.Size; +using Point = Microsoft.Maui.Graphics.Point; +using Rect = Microsoft.Maui.Graphics.Rect; +using Size = Microsoft.Maui.Graphics.Size; + +namespace Microsoft.Maui.Handlers +{ + public abstract partial class ViewHandler : IPlatformViewHandler + { + bool _disposedValue; + + EvasObject? IPlatformViewHandler.PlatformView => this.ToPlatform(); + EvasObject? IPlatformViewHandler.ContainerView => ContainerView; + + public new WrapperView? ContainerView + { + get => (WrapperView?)base.ContainerView; + protected set => base.ContainerView = value; + } + + public void SetParent(IPlatformViewHandler parent) => Parent = parent; + + public IPlatformViewHandler? Parent { get; private set; } + + public EvasObject? NativeParent => MauiContext?.GetNativeParent(); + + ~ViewHandler() + { + Dispose(disposing: false); + } + + public override bool NeedsContainer => + VirtualView?.Background != null || + VirtualView?.Clip != null || + VirtualView?.Shadow != null || + base.NeedsContainer; + + public override void PlatformArrange(Rect frame) + { + if (NativeParent == null) + return; + + var platformView = this.ToPlatform(); + + if (platformView == null) + return; + + if (frame.Width < 0 || frame.Height < 0) + { + // This is just some initial Forms value nonsense, nothing is actually laying out yet + return; + } + + platformView.UpdateBounds(new Rect(ComputeAbsolutePoint(frame), new Size(frame.Width, frame.Height)).ToPixel()); + } + + public override Size GetDesiredSize(double widthConstraint, double heightConstraint) + { + var platformView = base.PlatformView; + + if (platformView == null || VirtualView == null || NativeParent == null) + { + return VirtualView == null || double.IsNaN(VirtualView.Width) || double.IsNaN(VirtualView.Height) ? Size.Zero : new Size(VirtualView.Width, VirtualView.Height); + } + + int availableWidth = widthConstraint.ToScaledPixel(); + int availableHeight = heightConstraint.ToScaledPixel(); + + if (availableWidth < 0) + availableWidth = int.MaxValue; + if (availableHeight < 0) + availableHeight = int.MaxValue; + + var explicitWidth = VirtualView.Width; + var explicitHeight = VirtualView.Height; + var hasExplicitWidth = explicitWidth >= 0; + var hasExplicitHeight = explicitHeight >= 0; + + Size measured; + if (platformView is IMeasurable platformViewMeasurable) + { + measured = platformViewMeasurable.Measure(availableWidth, availableHeight).ToDP(); + } + else + { + measured = Measure(availableWidth, availableHeight); + } + + return new Size(hasExplicitWidth ? explicitWidth : measured.Width, + hasExplicitHeight ? explicitHeight : measured.Height); + } + + public virtual ERect GetPlatformContentGeometry() + { + var platformView = this.ToPlatform(); + + if (platformView == null) + { + return new ERect(); + } + return platformView.Geometry; + } + + protected virtual Size Measure(double availableWidth, double availableHeight) + { + var platformView = this.ToPlatform(); + + if (platformView == null) + { + return new Size(0, 0); + } + return new ESize(platformView.MinimumWidth, platformView.MinimumHeight).ToDP(); + } + + protected virtual double ComputeAbsoluteX(Rect frame) + { + if (Parent != null) + { + return frame.X + Parent.GetPlatformContentGeometry().X.ToScaledDP(); + } + else + { + return frame.X; + } + } + + protected virtual double ComputeAbsoluteY(Rect frame) + { + if (Parent != null) + { + return frame.Y + Parent.GetPlatformContentGeometry().Y.ToScaledDP(); + } + else + { + return frame.Y; + } + } + + protected virtual Point ComputeAbsolutePoint(Rect frame) + { + return new Point(ComputeAbsoluteX(frame), ComputeAbsoluteY(frame)); + } + + protected override void SetupContainer() + { + var parent = Parent?.PlatformView as IContainable; + parent?.Children.Remove(PlatformView!); + + ContainerView ??= new WrapperView(NativeParent!); + ContainerView.Show(); + ContainerView.Content = PlatformView; + + parent?.Children?.Add(ContainerView); + } + + protected override void RemoveContainer() + { + var parent = Parent?.PlatformView as IContainable; + parent?.Children.Remove(ContainerView!); + + ContainerView!.Content = null; + ContainerView?.Unrealize(); + ContainerView = null; + + parent?.Children.Add(PlatformView!); + } + + protected override void OnPlatformViewDeleted() + { + Dispose(); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + var platformView = base.PlatformView; + (this as IElementHandler)?.DisconnectHandler(); + platformView?.Unrealize(); + ContainerView?.Unrealize(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override finalizer + // TODO: set large fields to null + _disposedValue = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Core/src/Handlers/View/ViewHandlerOfT.cs b/src/Core/src/Handlers/View/ViewHandlerOfT.cs index 4f58c487f9..26c1b90ab9 100644 --- a/src/Core/src/Handlers/View/ViewHandlerOfT.cs +++ b/src/Core/src/Handlers/View/ViewHandlerOfT.cs @@ -5,7 +5,9 @@ using PlatformView = UIKit.UIView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif @@ -13,7 +15,7 @@ namespace Microsoft.Maui.Handlers { public abstract partial class ViewHandler : ViewHandler, IViewHandler where TVirtualView : class, IView -#if !NETSTANDARD || IOS || ANDROID || WINDOWS +#if !NETSTANDARD || IOS || ANDROID || WINDOWS || TIZEN where TPlatformView : PlatformView #else where TPlatformView : class diff --git a/src/Core/src/Handlers/WebView/IWebViewHandler.cs b/src/Core/src/Handlers/WebView/IWebViewHandler.cs index 478a0d4523..a1c83577b1 100644 --- a/src/Core/src/Handlers/WebView/IWebViewHandler.cs +++ b/src/Core/src/Handlers/WebView/IWebViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = WebKit.WKWebView; using PlatformView = Android.Webkit.WebView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.WebView2; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.MauiWebView; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/WebView/WebViewHandler.Tizen.cs b/src/Core/src/Handlers/WebView/WebViewHandler.Tizen.cs new file mode 100644 index 0000000000..0fad49fc97 --- /dev/null +++ b/src/Core/src/Handlers/WebView/WebViewHandler.Tizen.cs @@ -0,0 +1,80 @@ +using System; +using Tizen.UIExtensions.ElmSharp; +using TChromium = Tizen.WebView.Chromium; +using TWebView = Tizen.WebView.WebView; + +namespace Microsoft.Maui.Handlers +{ + public partial class WebViewHandler : ViewHandler + { + protected virtual double MinimumSize => 44d; + + TWebView PlatformWebView => PlatformView.WebView; + + public static void MapSource(IWebViewHandler handler, IWebView webView) + { + IWebViewDelegate? webViewDelegate = handler.PlatformView as IWebViewDelegate; + handler.PlatformView?.UpdateSource(webView, webViewDelegate); + } + + public static void MapGoBack(IWebViewHandler handler, IWebView webView, object? arg) + { + handler.PlatformView?.UpdateGoBack(webView); + } + + public static void MapGoForward(IWebViewHandler handler, IWebView webView, object? arg) + { + handler.PlatformView?.UpdateGoForward(webView); + } + + public static void MapReload(IWebViewHandler handler, IWebView webView, object? arg) + { + handler.PlatformView?.UpdateReload(webView); + } + + public static void MapEval(IWebViewHandler handler, IWebView webView, object? arg) + { + if (arg is not string script) + return; + + handler.PlatformView?.Eval(webView, script); + } + + public static void MapEvaluateJavaScriptAsync(IWebViewHandler handler, IWebView webView, object? arg) + { + if (arg is not string script) + return; + + handler.PlatformView?.Eval(webView, script); + } + + protected override MauiWebView CreatePlatformView() + { + _ = NativeParent ?? throw new InvalidOperationException($"{nameof(NativeParent)} should have been set by base class."); + return new MauiWebView(NativeParent) + { + MinimumHeight = MinimumSize.ToScaledPixel(), + MinimumWidth = MinimumSize.ToScaledPixel() + }; + } + + protected override void ConnectHandler(MauiWebView platformView) + { + TChromium.Initialize(); + MauiApplication.Current.Terminated += (sender, arg) => TChromium.Shutdown(); + PlatformWebView.LoadFinished += OnLoadFinished; + } + + protected override void DisconnectHandler(MauiWebView platformView) + { + PlatformWebView.StopLoading(); + PlatformWebView.LoadFinished -= OnLoadFinished; + base.DisconnectHandler(platformView); + } + + void OnLoadFinished(object? sender, EventArgs e) + { + PlatformWebView.SetFocus(true); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/WebView/WebViewHandler.cs b/src/Core/src/Handlers/WebView/WebViewHandler.cs index 03abec556b..b21dd79a26 100644 --- a/src/Core/src/Handlers/WebView/WebViewHandler.cs +++ b/src/Core/src/Handlers/WebView/WebViewHandler.cs @@ -4,7 +4,9 @@ using PlatformView = WebKit.WKWebView; using PlatformView = Android.Webkit.WebView; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Controls.WebView2; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Microsoft.Maui.Platform.MauiWebView; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Window/IWindowHandler.cs b/src/Core/src/Handlers/Window/IWindowHandler.cs index 0a26f19dd4..762a0c9d69 100644 --- a/src/Core/src/Handlers/Window/IWindowHandler.cs +++ b/src/Core/src/Handlers/Window/IWindowHandler.cs @@ -4,7 +4,9 @@ using PlatformView = UIKit.UIWindow; using PlatformView = Android.App.Activity; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Window; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.Window; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/Handlers/Window/WindowHandler.Tizen.cs b/src/Core/src/Handlers/Window/WindowHandler.Tizen.cs new file mode 100644 index 0000000000..7c381ea88a --- /dev/null +++ b/src/Core/src/Handlers/Window/WindowHandler.Tizen.cs @@ -0,0 +1,32 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Handlers +{ + public partial class WindowHandler : ElementHandler + { + public static void MapTitle(IWindowHandler handler, IWindow window) { } + + public static void MapContent(IWindowHandler handler, IWindow window) + { + _ = handler.MauiContext ?? throw new InvalidOperationException($"{nameof(MauiContext)} should have been set by base class."); + + var nativeContent = window.Content.ToContainerView(handler.MauiContext); + + nativeContent.SetAlignment(-1, -1); + nativeContent.SetWeight(1, 1); + nativeContent.Show(); + handler.MauiContext.GetModalStack().Reset(); + handler.MauiContext.GetModalStack().Push(nativeContent); + + if (window.VisualDiagnosticsOverlay != null) + window.VisualDiagnosticsOverlay.Initialize(); + } + + public static void MapRequestDisplayDensity(IWindowHandler handler, IWindow window, object? args) + { + if (args is DisplayDensityRequest request) + request.SetResult(handler.PlatformView.GetDisplayDensity()); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Handlers/Window/WindowHandler.cs b/src/Core/src/Handlers/Window/WindowHandler.cs index a77f2dcef5..6781f370c8 100644 --- a/src/Core/src/Handlers/Window/WindowHandler.cs +++ b/src/Core/src/Handlers/Window/WindowHandler.cs @@ -6,6 +6,8 @@ using PlatformView = UIKit.UIWindow; using PlatformView = Android.App.Activity; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Window; +#elif TIZEN +using PlatformView = ElmSharp.Window; #endif namespace Microsoft.Maui.Handlers diff --git a/src/Core/src/Hosting/EssentialsMauiAppBuilderExtensions.cs b/src/Core/src/Hosting/EssentialsMauiAppBuilderExtensions.cs index f79dcec33b..d6814ea51f 100644 --- a/src/Core/src/Hosting/EssentialsMauiAppBuilderExtensions.cs +++ b/src/Core/src/Hosting/EssentialsMauiAppBuilderExtensions.cs @@ -74,6 +74,8 @@ namespace Microsoft.Maui.Hosting { ApplicationModel.Platform.OnLaunched(args); })); +#elif TIZEN + #endif }); @@ -134,12 +136,14 @@ namespace Microsoft.Maui.Hosting ApplicationModel.Platform.MapServiceToken = _essentialsBuilder.MapServiceToken; #endif +#if !TIZEN AppActions.OnAppAction += HandleOnAppAction; if (_essentialsBuilder.AppActions is not null) { SetAppActions(services, _essentialsBuilder.AppActions); } +#endif if (_essentialsBuilder.TrackVersions) VersionTracking.Track(); @@ -203,4 +207,4 @@ namespace Microsoft.Maui.Hosting } } } -} \ No newline at end of file +} diff --git a/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Tizen.cs b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Tizen.cs new file mode 100644 index 0000000000..42c2ba653d --- /dev/null +++ b/src/Core/src/Hosting/LifecycleEvents/AppHostBuilderExtensions.Tizen.cs @@ -0,0 +1,37 @@ +using System; +using Microsoft.Maui.Hosting; +using Microsoft.Maui.LifecycleEvents; + +namespace Microsoft.Maui.LifecycleEvents +{ + public static partial class AppHostBuilderExtensions + { + internal static MauiAppBuilder ConfigureCrossPlatformLifecycleEvents(this MauiAppBuilder builder) => + builder.ConfigureLifecycleEvents(events => events.AddTizen(OnConfigureLifeCycle)); + + static void OnConfigureLifeCycle(ITizenLifecycleBuilder tizen) + { + tizen + .OnCreate((app) => + { + // OnCreate is only ever called once when the app is initally created + app.GetWindow().Created(); + }) + .OnResume(app => + { + app.GetWindow().Resumed(); + app.GetWindow().Activated(); + + }) + .OnPause(app => + { + app.GetWindow().Deactivated(); + app.GetWindow().Stopped(); + }) + .OnTerminate(app => + { + app.GetWindow().Destroying(); + }); + } + } +} diff --git a/src/Core/src/IMauiContext.cs b/src/Core/src/IMauiContext.cs index 28f3b12ad7..cf899f3188 100644 --- a/src/Core/src/IMauiContext.cs +++ b/src/Core/src/IMauiContext.cs @@ -12,4 +12,4 @@ namespace Microsoft.Maui Android.Content.Context? Context { get; } #endif } -} +} \ No newline at end of file diff --git a/src/Core/src/ImageSources/FileImageSourceService/FileImageSourceService.Tizen.cs b/src/Core/src/ImageSources/FileImageSourceService/FileImageSourceService.Tizen.cs new file mode 100644 index 0000000000..3d14433c3c --- /dev/null +++ b/src/Core/src/ImageSources/FileImageSourceService/FileImageSourceService.Tizen.cs @@ -0,0 +1,88 @@ +#nullable enable +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Tizen.UIExtensions.ElmSharp; +using AppFW = Tizen.Applications; + +namespace Microsoft.Maui +{ + public partial class FileImageSourceService + { + public override Task?> GetImageAsync(IImageSource imageSource, Image image, CancellationToken cancellationToken = default) => + GetImageAsync((IFileImageSource)imageSource, image, cancellationToken); + + public async Task?> GetImageAsync(IFileImageSource imageSource, Image image, CancellationToken cancellationToken = default) + { + if (imageSource.IsEmpty) + return null; + + var filename = imageSource.File; + try + { + if (!string.IsNullOrEmpty(filename)) + { + var isLoadComplated = await image.LoadAsync(GetPath(filename), cancellationToken); + + if (!isLoadComplated) + { + //If it fails, call the Load function to remove the previous image. + image.Load(string.Empty); + throw new InvalidOperationException("Unable to load image file."); + } + + var result = new ImageSourceServiceResult(image); + return result; + } + else + { + throw new InvalidOperationException("Unable to load image file."); + } + } + catch (Exception ex) + { + Logger?.LogWarning(ex, "Unable to load image file '{File}'.", filename); + throw; + } + } + + static string GetPath(string res) + { + if (Path.IsPathRooted(res)) + { + return res; + } + + foreach (AppFW.ResourceManager.Category category in Enum.GetValues(typeof(AppFW.ResourceManager.Category))) + { + foreach (var file in new[] { res, res + ".jpg", res + ".png", res + ".gif" }) + { + var path = AppFW.ResourceManager.TryGetPath(category, file); + + if (path != null) + { + return path; + } + } + } + + AppFW.Application app = AppFW.Application.Current; + if (app != null) + { + string resPath = app.DirectoryInfo.Resource + res; + + foreach (var file in new []{ resPath, resPath + ".jpg", resPath + ".png", resPath + ".gif" }) + { + if (File.Exists(file)) + { + return resPath; + } + } + } + + return res; + } + } +} \ No newline at end of file diff --git a/src/Core/src/ImageSources/FontImageSourceService/FontImageSourceService.Tizen.cs b/src/Core/src/ImageSources/FontImageSourceService/FontImageSourceService.Tizen.cs new file mode 100644 index 0000000000..e725701113 --- /dev/null +++ b/src/Core/src/ImageSources/FontImageSourceService/FontImageSourceService.Tizen.cs @@ -0,0 +1,40 @@ +#nullable enable +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui +{ + public partial class FontImageSourceService + { + public override Task?> GetImageAsync(IImageSource imageSource, Image image, CancellationToken cancellationToken = default) => + GetImageAsync((IFontImageSource)imageSource, image, cancellationToken); + + public async Task?> GetImageAsync(IFontImageSource imageSource, Image image, CancellationToken cancellationToken = default) + { + if (imageSource.IsEmpty) + return null; + + try + { + //TODO : Fix me correctly later. + var isLoadComplated = await image.LoadAsync(string.Empty, cancellationToken); + + if (!isLoadComplated) + { + throw new InvalidOperationException("Unable to load image file."); + } + + var result = new ImageSourceServiceResult(image); + return result; + } + catch (Exception ex) + { + Logger?.LogWarning(ex, "Unable to generate font image '{Glyph}'.", imageSource.Glyph); + throw; + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/ImageSources/IImageSourceService.cs b/src/Core/src/ImageSources/IImageSourceService.cs index 51fff6161b..51a4fc4fb4 100644 --- a/src/Core/src/ImageSources/IImageSourceService.cs +++ b/src/Core/src/ImageSources/IImageSourceService.cs @@ -21,6 +21,11 @@ namespace Microsoft.Maui IImageSource imageSource, float scale = 1, CancellationToken cancellationToken = default); +#elif TIZEN || __TIZEN__ + Task?> GetImageAsync( + IImageSource imageSource, + Tizen.UIExtensions.ElmSharp.Image image, + CancellationToken cancellationToken = default); #elif WINDOWS Task?> GetImageSourceAsync( IImageSource imageSource, diff --git a/src/Core/src/ImageSources/ImageSourceExtensions.cs b/src/Core/src/ImageSources/ImageSourceExtensions.cs index da67d1ecd6..adcf6d5129 100644 --- a/src/Core/src/ImageSources/ImageSourceExtensions.cs +++ b/src/Core/src/ImageSources/ImageSourceExtensions.cs @@ -10,7 +10,9 @@ using PlatformImage = UIKit.UIImage; using PlatformImage = Android.Graphics.Drawables.Drawable; #elif WINDOWS using PlatformImage = Microsoft.UI.Xaml.Media.ImageSource; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformImage = Tizen.UIExtensions.ElmSharp.Image; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformImage = System.Object; #endif @@ -52,6 +54,9 @@ namespace Microsoft.Maui return imageSourceService.GetDrawableAsync(imageSource, mauiContext.Context!); #elif WINDOWS return imageSourceService.GetImageSourceAsync(imageSource); +#elif TIZEN + var platformImage = new PlatformImage(mauiContext.GetNativeParent()); + return imageSourceService.GetImageAsync(imageSource, platformImage); #else throw new NotImplementedException(); #endif diff --git a/src/Core/src/ImageSources/ImageSourceService.cs b/src/Core/src/ImageSources/ImageSourceService.cs index e37edb6ef8..c79d0fe768 100644 --- a/src/Core/src/ImageSources/ImageSourceService.cs +++ b/src/Core/src/ImageSources/ImageSourceService.cs @@ -47,6 +47,11 @@ namespace Microsoft.Maui IImageSource imageSource, float scale = 1, CancellationToken cancellationToken = default); +#elif TIZEN || __TIZEN__ + public abstract Task?> GetImageAsync( + IImageSource imageSource, + Tizen.UIExtensions.ElmSharp.Image image, + CancellationToken cancellationToken = default); #elif WINDOWS public abstract Task?> GetImageSourceAsync( IImageSource imageSource, diff --git a/src/Core/src/ImageSources/ImageSourceServiceResult.cs b/src/Core/src/ImageSources/ImageSourceServiceResult.cs index fd54df50ed..f85a6ec541 100644 --- a/src/Core/src/ImageSources/ImageSourceServiceResult.cs +++ b/src/Core/src/ImageSources/ImageSourceServiceResult.cs @@ -6,7 +6,9 @@ using PlatformView = UIKit.UIImage; using PlatformView = Android.Graphics.Drawables.Drawable; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Media.ImageSource; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = Tizen.UIExtensions.ElmSharp.Image; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; #endif diff --git a/src/Core/src/ImageSources/StreamImageSourceService/StreamImageSourceService.Tizen.cs b/src/Core/src/ImageSources/StreamImageSourceService/StreamImageSourceService.Tizen.cs new file mode 100644 index 0000000000..d6d9844ca2 --- /dev/null +++ b/src/Core/src/ImageSources/StreamImageSourceService/StreamImageSourceService.Tizen.cs @@ -0,0 +1,41 @@ +#nullable enable +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui +{ + public partial class StreamImageSourceService + { + public override Task?> GetImageAsync(IImageSource imageSource, Image image, CancellationToken cancellationToken = default) => + GetImageAsync((IStreamImageSource)imageSource, image, cancellationToken); + + public async Task?> GetImageAsync(IStreamImageSource imageSource, Image image, CancellationToken cancellationToken = default) + { + if (imageSource.IsEmpty) + return null; + + try + { + var stream = await imageSource.GetStreamAsync(cancellationToken); + + if (stream == null) + throw new InvalidOperationException("Unable to load image stream."); + + var isLoadComplated = await image.LoadAsync(stream, cancellationToken); + + if (!isLoadComplated) + throw new InvalidOperationException("Unable to decode image from stream."); + + return new ImageSourceServiceResult(image); + } + catch (Exception ex) + { + Logger?.LogWarning(ex, "Unable to load image stream."); + throw; + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/ImageSources/UriImageSourceService/UriImageSourceService.Tizen.cs b/src/Core/src/ImageSources/UriImageSourceService/UriImageSourceService.Tizen.cs new file mode 100644 index 0000000000..d28fa31bd2 --- /dev/null +++ b/src/Core/src/ImageSources/UriImageSourceService/UriImageSourceService.Tizen.cs @@ -0,0 +1,38 @@ +#nullable enable +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui +{ + public partial class UriImageSourceService + { + public override Task?> GetImageAsync(IImageSource imageSource, Image image, CancellationToken cancellationToken = default) => + GetImageAsync((IUriImageSource)imageSource, image, cancellationToken); + + public async Task?> GetImageAsync(IUriImageSource imageSource, Image image, CancellationToken cancellationToken = default) + { + if (imageSource.IsEmpty) + return null; + + var uri = imageSource.Uri; + + try + { + var isLoadComplated = await image.LoadAsync(uri, cancellationToken); + + if (!isLoadComplated) + throw new InvalidOperationException($"Unable to load image URI '{uri}'."); + + return new ImageSourceServiceResult(image); + } + catch (Exception ex) + { + Logger?.LogWarning(ex, "Unable to load image URI '{Uri}'.", uri); + throw; + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/LifecycleEvents/Tizen/ITizenLifecycleBuilder.cs b/src/Core/src/LifecycleEvents/Tizen/ITizenLifecycleBuilder.cs new file mode 100644 index 0000000000..aaef20de99 --- /dev/null +++ b/src/Core/src/LifecycleEvents/Tizen/ITizenLifecycleBuilder.cs @@ -0,0 +1,6 @@ +namespace Microsoft.Maui.LifecycleEvents +{ + public interface ITizenLifecycleBuilder : ILifecycleBuilder + { + } +} \ No newline at end of file diff --git a/src/Core/src/LifecycleEvents/Tizen/TizenLifecycle.cs b/src/Core/src/LifecycleEvents/Tizen/TizenLifecycle.cs new file mode 100644 index 0000000000..37e70e7ac9 --- /dev/null +++ b/src/Core/src/LifecycleEvents/Tizen/TizenLifecycle.cs @@ -0,0 +1,25 @@ +using Tizen.Applications; + +namespace Microsoft.Maui.LifecycleEvents +{ + public static class TizenLifecycle + { + // Events called by CoreUIApplication overrides + public delegate void OnPause(CoreApplication application); + public delegate void OnPreCreate(CoreApplication application); + public delegate void OnResume(CoreApplication application); + + // Events called by CoreApplication overrides + public delegate void OnAppControlReceived(CoreApplication application, AppControlReceivedEventArgs e); + public delegate void OnCreate(CoreApplication application); + public delegate void OnDeviceOrientationChanged(CoreApplication application, DeviceOrientationEventArgs e); + public delegate void OnLocaleChanged(CoreApplication application, LocaleChangedEventArgs e); + public delegate void OnLowBattery(CoreApplication application, LowBatteryEventArgs e); + public delegate void OnLowMemory(CoreApplication application, LowMemoryEventArgs e); + public delegate void OnRegionFormatChanged(CoreApplication application, RegionFormatChangedEventArgs e); + public delegate void OnTerminate(CoreApplication application); + + // Internal events + internal delegate void OnMauiContextCreated(IMauiContext mauiContext); + } +} \ No newline at end of file diff --git a/src/Core/src/LifecycleEvents/Tizen/TizenLifecycleBuilderExtensions.cs b/src/Core/src/LifecycleEvents/Tizen/TizenLifecycleBuilderExtensions.cs new file mode 100644 index 0000000000..c1b5de9a15 --- /dev/null +++ b/src/Core/src/LifecycleEvents/Tizen/TizenLifecycleBuilderExtensions.cs @@ -0,0 +1,19 @@ +namespace Microsoft.Maui.LifecycleEvents +{ + public static class TizenLifecycleBuilderExtensions + { + public static ITizenLifecycleBuilder OnPause(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnPause del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnPreCreate(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnPreCreate del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnResume(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnResume del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnAppControlReceived(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnAppControlReceived del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnCreate(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnCreate del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnDeviceOrientationChanged(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnDeviceOrientationChanged del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnLocaleChanged(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnLocaleChanged del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnLowBattery(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnLowBattery del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnLowMemory(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnLowMemory del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnRegionFormatChanged(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnRegionFormatChanged del) => lifecycle.OnEvent(del); + public static ITizenLifecycleBuilder OnTerminate(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnTerminate del) => lifecycle.OnEvent(del); + + internal static ITizenLifecycleBuilder OnMauiContextCreated(this ITizenLifecycleBuilder lifecycle, TizenLifecycle.OnMauiContextCreated del) => lifecycle.OnEvent(del); + } +} \ No newline at end of file diff --git a/src/Core/src/LifecycleEvents/Tizen/TizenLifecycleExtensions.cs b/src/Core/src/LifecycleEvents/Tizen/TizenLifecycleExtensions.cs new file mode 100644 index 0000000000..b1328b2782 --- /dev/null +++ b/src/Core/src/LifecycleEvents/Tizen/TizenLifecycleExtensions.cs @@ -0,0 +1,32 @@ +using System; + +namespace Microsoft.Maui.LifecycleEvents +{ + public static class TizenLifecycleExtensions + { + public static ILifecycleBuilder AddTizen(this ILifecycleBuilder builder, Action configureDelegate) + { + var lifecycle = new LifecycleBuilder(builder); + + configureDelegate?.Invoke(lifecycle); + + return builder; + } + + class LifecycleBuilder : ITizenLifecycleBuilder + { + readonly ILifecycleBuilder _builder; + + public LifecycleBuilder(ILifecycleBuilder builder) + { + _builder = builder; + } + + public void AddEvent(string eventName, TDelegate action) + where TDelegate : Delegate + { + _builder.AddEvent(eventName, action); + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/MauiContextExtensions.cs b/src/Core/src/MauiContextExtensions.cs index 46d3f326da..5532ec4177 100644 --- a/src/Core/src/MauiContextExtensions.cs +++ b/src/Core/src/MauiContextExtensions.cs @@ -14,6 +14,9 @@ using NativeWindow = UIKit.UIWindow; #elif __ANDROID__ using NativeApplication = Android.App.Application; using NativeWindow = Android.App.Activity; +#elif TIZEN +using NativeApplication = Tizen.Applications.CoreApplication; +using NativeWindow = ElmSharp.Window; #else using NativeApplication = System.Object; using NativeWindow = System.Object; diff --git a/src/Core/src/Platform/ElementExtensions.cs b/src/Core/src/Platform/ElementExtensions.cs index 3f2efe33c6..a0bda15d13 100644 --- a/src/Core/src/Platform/ElementExtensions.cs +++ b/src/Core/src/Platform/ElementExtensions.cs @@ -15,7 +15,12 @@ using PlatformView = Microsoft.UI.Xaml.FrameworkElement; using BasePlatformType = WinRT.IWinRTObject; using PlatformWindow = Microsoft.UI.Xaml.Window; using PlatformApplication = Microsoft.UI.Xaml.Application; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +using BasePlatformType = System.Object; +using PlatformWindow = ElmSharp.Window; +using PlatformApplication = Tizen.Applications.CoreUIApplication; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformView = System.Object; using BasePlatformType = System.Object; using IPlatformViewHandler = Microsoft.Maui.IViewHandler; diff --git a/src/Core/src/Platform/ImageSourcePartLoader.cs b/src/Core/src/Platform/ImageSourcePartLoader.cs index 8cb4c404ce..98359ed696 100644 --- a/src/Core/src/Platform/ImageSourcePartLoader.cs +++ b/src/Core/src/Platform/ImageSourcePartLoader.cs @@ -11,9 +11,12 @@ using PlatformView = Android.Views.View; #elif WINDOWS using PlatformImage = Microsoft.UI.Xaml.Media.ImageSource; using PlatformView = Microsoft.UI.Xaml.FrameworkElement; -#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID) -using PlatformView = System.Object; +#elif TIZEN +using PlatformImage = Tizen.UIExtensions.ElmSharp.Image; +using PlatformView = ElmSharp.EvasObject; +#elif NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using PlatformImage = System.Object; +using PlatformView = System.Object; #endif namespace Microsoft.Maui.Platform @@ -60,6 +63,12 @@ namespace Microsoft.Maui.Platform var result = await imageSource.UpdateSourceAsync(PlatformView, ImageSourceServiceProvider, SetImage!, token) .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; diff --git a/src/Core/src/Platform/Tizen/ActivityIndicatorExtensions.cs b/src/Core/src/Platform/Tizen/ActivityIndicatorExtensions.cs new file mode 100644 index 0000000000..2bffe4750a --- /dev/null +++ b/src/Core/src/Platform/Tizen/ActivityIndicatorExtensions.cs @@ -0,0 +1,18 @@ +using ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class ActivityIndicatorExtensions + { + public static void UpdateIsRunning(this ProgressBar activityIndicatorView, IActivityIndicator activityIndicator) + { + if (activityIndicator.IsRunning) + activityIndicatorView.PlayPulse(); + else + activityIndicatorView.StopPulse(); + } + + public static void UpdateColor(this ProgressBar activityIndicatorView, IActivityIndicator activityIndicator) + => activityIndicatorView.Color = activityIndicator.Color.ToPlatformEFL(); + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/AspectExtensions.cs b/src/Core/src/Platform/Tizen/AspectExtensions.cs new file mode 100644 index 0000000000..0036fda1ec --- /dev/null +++ b/src/Core/src/Platform/Tizen/AspectExtensions.cs @@ -0,0 +1,16 @@ +using TAspect = Tizen.UIExtensions.Common.Aspect; + +namespace Microsoft.Maui.Platform +{ + public static class AspectExtensions + { + public static TAspect ToPlatform(this Aspect aspect) => + aspect switch + { + Aspect.AspectFit => TAspect.AspectFit, + Aspect.AspectFill => TAspect.AspectFill, + Aspect.Fill => TAspect.Fill, + _ => TAspect.AspectFit, + }; + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/BorderView.cs b/src/Core/src/Platform/Tizen/BorderView.cs new file mode 100644 index 0000000000..62a35d25bd --- /dev/null +++ b/src/Core/src/Platform/Tizen/BorderView.cs @@ -0,0 +1,29 @@ +using ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public class BorderView : ContentCanvas + { + WrapperView? _wrapperView; + IBorderView _borderView; + + public BorderView(EvasObject parent, IBorderView view) : base(parent, view) + { + _borderView = view; + } + + public WrapperView? ContainerView + { + get + { + return _wrapperView; + } + set + { + _wrapperView = value; + _wrapperView?.UpdateBorder(_borderView); + _wrapperView?.UpdateBackground(_borderView.Background); + } + } + } +} diff --git a/src/Core/src/Platform/Tizen/ButtonExtensions.cs b/src/Core/src/Platform/Tizen/ButtonExtensions.cs new file mode 100644 index 0000000000..209cfc50ed --- /dev/null +++ b/src/Core/src/Platform/Tizen/ButtonExtensions.cs @@ -0,0 +1,17 @@ +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class ButtonExtensions + { + public static void UpdateTextColor(this Button platformButton, ITextStyle button) + { + platformButton.TextColor = button.TextColor.ToPlatform(); + } + + public static void UpdateText(this Button platformButton, IText button) + { + platformButton.Text = button.Text ?? ""; + } + } +} diff --git a/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs b/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs new file mode 100644 index 0000000000..34f9ecdf59 --- /dev/null +++ b/src/Core/src/Platform/Tizen/CheckBoxExtensions.cs @@ -0,0 +1,22 @@ +using ElmSharp; +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Platform +{ + public static class CheckBoxExtensions + { + public static void UpdateIsChecked(this Check platformCheck, ICheckBox check) + { + platformCheck.IsChecked = check.IsChecked; + } + + 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) + { + platformCheck.Color = solid.Color.ToPlatformEFL(); + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ColorExtensions.cs b/src/Core/src/Platform/Tizen/ColorExtensions.cs new file mode 100644 index 0000000000..74f5e2f970 --- /dev/null +++ b/src/Core/src/Platform/Tizen/ColorExtensions.cs @@ -0,0 +1,39 @@ +using Microsoft.Maui.Graphics; +using TLog = Tizen.UIExtensions.Common.Log; +using TColor = Tizen.UIExtensions.Common.Color; +using EColor = ElmSharp.Color; + +namespace Microsoft.Maui.Platform +{ + public static class ColorExtensions + { + public static TColor ToPlatform(this Color c) + { + return c == null ? TColor.Default : new TColor(c.Red, c.Green, c.Blue, c.Alpha); + } + + public static EColor ToPlatformEFL(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)); + } + + public static Color WithAlpha(this Color color, double alpha) + { + return new Color(color.Red, color.Green, color.Blue, (int)(255 * alpha)); + } + + 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); + } + + internal static string ToHex(this TColor c) + { + if (c.IsDefault) + { + TLog.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); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ContainerView.cs b/src/Core/src/Platform/Tizen/ContainerView.cs new file mode 100644 index 0000000000..f2986b46c0 --- /dev/null +++ b/src/Core/src/Platform/Tizen/ContainerView.cs @@ -0,0 +1,74 @@ +using System; +using Microsoft.Maui.HotReload; +using ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public class ContainerView : Box, IReloadHandler + { + readonly IMauiContext? _context; + + EvasObject? _mainView; + IElement? _view; + + public ContainerView(IMauiContext context) : this(context.GetNativeParent(), context) + { + } + + public ContainerView(EvasObject parent, IMauiContext context) : base(parent) + { + _context = context; + } + + public EvasObject? MainView + { + get => _mainView; + set + { + if (_mainView != null) + { + UnPack(_mainView); + } + + _mainView = value; + + if (_mainView != null) + { + _mainView.SetAlignment(-1, -1); + _mainView.SetWeight(1, 1); + PackEnd(_mainView); + } + } + } + + public IElement? CurrentView + { + get => _view; + set => SetView(value); + } + + void SetView(IElement? view, bool forceRefresh = false) + { + if (view == _view && !forceRefresh) + return; + + _view = view; + + if (_view is IHotReloadableView ihr) + { + ihr.ReloadHandler = this; + MauiHotReloadHelper.AddActiveView(ihr); + } + + MainView = null; + + if (_view != null) + { + _ = _context ?? throw new ArgumentNullException(nameof(_context)); + MainView = _view.ToPlatform(_context); + } + } + + public void Reload() => SetView(CurrentView, true); + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ContentCanvas.cs b/src/Core/src/Platform/Tizen/ContentCanvas.cs new file mode 100644 index 0000000000..c47a45d99b --- /dev/null +++ b/src/Core/src/Platform/Tizen/ContentCanvas.cs @@ -0,0 +1,49 @@ +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 ContentCanvas : Canvas, IMeasurable + { + IView _virtualView; + Size _measureCache; + + public ContentCanvas(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/CoreAppExtensions.cs b/src/Core/src/Platform/Tizen/CoreAppExtensions.cs new file mode 100644 index 0000000000..027e69ca6f --- /dev/null +++ b/src/Core/src/Platform/Tizen/CoreAppExtensions.cs @@ -0,0 +1,98 @@ +using System; +using System.Reflection; +using ElmSharp; +using Microsoft.Maui.LifecycleEvents; +using Tizen.Applications; +using EWindow = ElmSharp.Window; + +namespace Microsoft.Maui.Platform +{ + internal static class CoreAppExtensions + { + public static Window? MainWindow { get; set; } + + public static IWindow GetWindow(this CoreApplication application) + { + foreach (var window in MauiApplication.Current.Application.Windows) + { + if (window?.Handler?.PlatformView is EWindow win && win == MainWindow) + return window; + } + + throw new InvalidOperationException("Window Not Found"); + } + + public static void RequestNewWindow(this CoreApplication platformApplication, 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 CoreApplication platformApplication, IApplication application) + { + if (application.Handler?.MauiContext is not IMauiContext applicationContext) + return; + + var tizenWindow = GetDefaultWindow(); + if (tizenWindow == null) + throw new InvalidOperationException($"The {nameof(tizenWindow)} instance was not found."); + + var mauiContext = applicationContext.MakeWindowScope(tizenWindow, out var windowScope); + + tizenWindow.SetWindowCloseRequestHandler(() => platformApplication.Exit()); + + applicationContext.Services.InvokeLifecycleEvents(del => del(mauiContext)); + + 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; + } + + public static EWindow GetDefaultWindow() + { + if (MainWindow != null) + return MainWindow; + + return MainWindow = GetPreloadedWindow() ?? new EWindow("MauiDefaultWindow"); + } + + static EWindow? GetPreloadedWindow() + { + 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); + + return (EWindow?)methodInfo?.Invoke(null, new object[] { "FormsWindow" }); + } + } +} diff --git a/src/Core/src/Platform/Tizen/DPExtensions.cs b/src/Core/src/Platform/Tizen/DPExtensions.cs new file mode 100644 index 0000000000..5bb53ef49c --- /dev/null +++ b/src/Core/src/Platform/Tizen/DPExtensions.cs @@ -0,0 +1,122 @@ +using System; +using Microsoft.Maui.Graphics; +using ERect = ElmSharp.Rect; +using ESize = ElmSharp.Size; +using TRect = Tizen.UIExtensions.Common.Rect; +using TSize = Tizen.UIExtensions.Common.Size; +using DeviceInfo = Tizen.UIExtensions.Common.DeviceInfo; +using Point = Microsoft.Maui.Graphics.Point; +using EPoint = ElmSharp.Point; + +namespace Microsoft.Maui.Platform +{ + public static class DPExtensions + { + public static Rect ToDP(this ERect rect) + { + return new Rect(ConvertToScaledDP(rect.X), ConvertToScaledDP(rect.Y), ConvertToScaledDP(rect.Width), ConvertToScaledDP(rect.Height)); + } + + public static ERect ToEFLPixel(this Rect rect) + { + return new ERect(ConvertToScaledPixel(rect.X), ConvertToScaledPixel(rect.Y), ConvertToScaledPixel(rect.Width), ConvertToScaledPixel(rect.Height)); + } + + public static Size ToDP(this ESize size) + { + return new Size(ConvertToScaledDP(size.Width), ConvertToScaledDP(size.Height)); + } + + public static ESize ToEFLPixel(this Size size) + { + return new ESize(ConvertToScaledPixel(size.Width), ConvertToScaledPixel(size.Height)); + } + + public static Rect ToDP(this TRect rect) + { + return new Rect(ConvertToScaledDP(rect.X), ConvertToScaledDP(rect.Y), ConvertToScaledDP(rect.Width), ConvertToScaledDP(rect.Height)); + } + + public static TRect ToPixel(this Rect rect) + { + return new TRect(ConvertToScaledPixel(rect.X), ConvertToScaledPixel(rect.Y), ConvertToScaledPixel(rect.Width), ConvertToScaledPixel(rect.Height)); + } + + public static Size ToDP(this TSize size) + { + return new Size(ConvertToScaledDP(size.Width), ConvertToScaledDP(size.Height)); + } + + public static TSize ToPixel(this Size size) + { + return new TSize(ConvertToScaledPixel(size.Width), ConvertToScaledPixel(size.Height)); + } + + public static int ToPixel(this double dp) + { + return (int)Math.Round(dp * DeviceInfo.DPI / 160.0); + } + + public static float ToScaledDP(this float pixel) + { + return pixel / (float)DeviceInfo.ScalingFactor; + } + + public static double ToScaledDP(this double pixel) + { + return pixel / DeviceInfo.ScalingFactor; + } + + public static int ToEflFontPoint(this double sp) + { + return (int)Math.Round(ConvertToScaledPixel(sp) * DeviceInfo.ElmScale); + } + + public static double ToDPFont(this int eflPt) + { + return ConvertToScaledDP(eflPt / DeviceInfo.ElmScale); + } + + public static int ConvertToPixel(double dp) + { + return (int)Math.Round(dp * DeviceInfo.DPI / 160.0); + } + + public static int ConvertToScaledPixel(double dp) + { + return (int)Math.Round(dp * DeviceInfo.ScalingFactor); + } + + public static double ConvertToScaledDP(int pixel) + { + if (pixel == int.MaxValue) + return double.PositiveInfinity; + return pixel / DeviceInfo.ScalingFactor; + } + + public static double ConvertToScaledDP(double pixel) + { + return pixel / DeviceInfo.ScalingFactor; + } + + public static int ConvertToEflFontPoint(double sp) + { + return (int)Math.Round(ConvertToScaledPixel(sp) * DeviceInfo.ElmScale); + } + + public static double ConvertToDPFont(int eflPt) + { + return ConvertToScaledDP(eflPt / DeviceInfo.ElmScale); + } + + public static Point ToPoint(this EPoint point) + { + return new Point(DPExtensions.ConvertToScaledDP(point.X), DPExtensions.ConvertToScaledDP(point.Y)); + } + + public static PointF ToPointF(this EPoint point) + { + return new PointF((float)DPExtensions.ConvertToScaledDP(point.X), (float)DPExtensions.ConvertToScaledDP(point.Y)); + } + } +} diff --git a/src/Core/src/Platform/Tizen/DatePickerExtensions.cs b/src/Core/src/Platform/Tizen/DatePickerExtensions.cs new file mode 100644 index 0000000000..ac4efb0252 --- /dev/null +++ b/src/Core/src/Platform/Tizen/DatePickerExtensions.cs @@ -0,0 +1,17 @@ +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class DatePickerExtensions + { + public static void UpdateFormat(this Entry platformDatePicker, IDatePicker datePicker) + { + UpdateDate(platformDatePicker, datePicker); + } + + public static void UpdateDate(this Entry platformDatePicker, IDatePicker datePicker) + { + platformDatePicker.Text = datePicker.Date.ToString(datePicker.Format); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/EditorExtensions.cs b/src/Core/src/Platform/Tizen/EditorExtensions.cs new file mode 100644 index 0000000000..b9726aceb8 --- /dev/null +++ b/src/Core/src/Platform/Tizen/EditorExtensions.cs @@ -0,0 +1,12 @@ +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class EditorExtensions + { + public static void UpdatePlaceholderColor(this Entry platformEntry, IEditor editor) + { + platformEntry.PlaceholderColor = editor.PlaceholderColor.ToPlatform(); + } + } +} diff --git a/src/Core/src/Platform/Tizen/ElementExtensions.cs b/src/Core/src/Platform/Tizen/ElementExtensions.cs new file mode 100644 index 0000000000..6c876fc7ba --- /dev/null +++ b/src/Core/src/Platform/Tizen/ElementExtensions.cs @@ -0,0 +1,10 @@ +using ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static partial class ElementExtensions + { + public static EvasObject ToContainerView(this IElement view, IMauiContext context) => + new ContainerView(context) { CurrentView = view }; + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/EntryExtensions.cs b/src/Core/src/Platform/Tizen/EntryExtensions.cs new file mode 100644 index 0000000000..93f68f5d74 --- /dev/null +++ b/src/Core/src/Platform/Tizen/EntryExtensions.cs @@ -0,0 +1,215 @@ +using System; +using System.Runtime.InteropServices; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using InputPanelReturnKeyType = ElmSharp.InputPanelReturnKeyType; +using TTextAlignment = Tizen.UIExtensions.Common.TextAlignment; + +namespace Microsoft.Maui.Platform +{ + public static class EntryExtensions + { + public static void UpdateText(this Entry platformEntry, IText entry) + { + platformEntry.Text = entry.Text ?? ""; + } + + public static void UpdateTextColor(this Entry platformEntry, ITextStyle entry) + { + platformEntry.TextColor = entry.TextColor.ToPlatform(); + } + + public static void UpdateHorizontalTextAlignment(this Entry platformEntry, ITextAlignment entry) + { + platformEntry.HorizontalTextAlignment = entry.HorizontalTextAlignment.ToPlatform(); + } + + public static void UpdateVerticalTextAlignment(this Entry platformEntry, ITextAlignment entry) + { + platformEntry.SetVerticalTextAlignment(entry.VerticalTextAlignment.ToPlatformDouble()); + platformEntry.SetVerticalPlaceHolderTextAlignment(entry.VerticalTextAlignment.ToPlatformDouble()); + } + + public static void UpdateIsPassword(this Entry platformEntry, IEntry entry) + { + platformEntry.IsPassword = entry.IsPassword; + } + + public static void UpdateReturnType(this Entry platformEntry, IEntry entry) + { + platformEntry.SetInputPanelReturnKeyType(entry.ReturnType.ToInputPanelReturnKeyType()); + } + + public static void UpdateClearButtonVisibility(this Entry platformEntry, IEntry entry) + { + if (entry.ClearButtonVisibility == ClearButtonVisibility.WhileEditing) + { + if (platformEntry is EditfieldEntry editfieldEntry) + { + editfieldEntry.EnableClearButton = true; + } + } + else + { + if (platformEntry is EditfieldEntry editfieldEntry) + { + editfieldEntry.EnableClearButton = false; + } + } + } + + public static void UpdateFont(this Entry platformEntry, ITextStyle textStyle, IFontManager fontManager) + { + platformEntry.BatchBegin(); + platformEntry.FontSize = textStyle.Font.Size > 0 ? textStyle.Font.Size : 25.ToDPFont(); + platformEntry.FontAttributes = textStyle.Font.GetFontAttributes(); + platformEntry.FontFamily = fontManager.GetFontFamily(textStyle.Font.Family) ?? ""; + platformEntry.BatchCommit(); + } + + public static void UpdatePlaceholder(this Entry platformEntry, ITextInput entry) + { + platformEntry.Placeholder = entry.Placeholder ?? string.Empty; + } + + public static void UpdatePlaceholderColor(this Entry platformEntry, ITextInput entry) + { + platformEntry.PlaceholderColor = entry.PlaceholderColor.ToPlatform(); + } + + public static void UpdateIsReadOnly(this Entry platformEntry, ITextInput entry) + { + platformEntry.IsEditable = !entry.IsReadOnly; + } + + public static void UpdateIsTextPredictionEnabled(this Entry platformEntry, ITextInput entry) + { + platformEntry.InputHint = entry.Keyboard.ToInputHints(true, entry.IsTextPredictionEnabled); + } + + public static void UpdateKeyboard(this Entry platformEntry, ITextInput entry) + { + platformEntry.UpdateKeyboard(entry.Keyboard, true, entry.IsTextPredictionEnabled); + } + + public static void UpdateMaxLength(this Entry platformEntry, ITextInput entry) + { + if (entry.MaxLength > 0 && platformEntry.Text.Length > entry.MaxLength) + platformEntry.Text = platformEntry.Text.Substring(0, entry.MaxLength); + } + + /* Updates both the IEntry.CursorPosition and IEntry.SelectionLength properties. */ + [PortHandler] + public static void UpdateSelectionLength(this Entry platformEntry, ITextInput entry) + { + if (platformEntry.IsUpdatingCursorPosition) + return; + + int start = GetSelectionStart(platformEntry, entry); + int end = GetSelectionEnd(platformEntry, entry, start); + + if (start < end) + { + platformEntry.SetSelectionRegion(start, end); + } + else + { + platformEntry.CursorPosition = entry.CursorPosition; + } + } + + static int GetSelectionStart(Entry platformEntry, ITextInput entry) + { + int start = platformEntry.Text?.Length ?? 0; + int cursorPosition = entry.CursorPosition; + + if (!string.IsNullOrEmpty(platformEntry.Text)) + start = Math.Min(start, cursorPosition); + + if (start != cursorPosition) + entry.CursorPosition = start; + + return start; + } + + static int GetSelectionEnd(Entry platformEntry, ITextInput entry, int start) + { + 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; + return end; + } + + public 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 TTextAlignment ToPlatform(this TextAlignment alignment) + { + switch (alignment) + { + case TextAlignment.Center: + return TTextAlignment.Center; + + case TextAlignment.Start: + return TTextAlignment.Start; + + case TextAlignment.End: + return TTextAlignment.End; + + default: + Log.Warn("Warning: unrecognized HorizontalTextAlignment value {0}. " + + "Expected: {Start|Center|End}.", alignment); + Log.Debug("Falling back to platform's default settings."); + return TTextAlignment.Auto; + } + } + + public static double ToPlatformDouble(this TextAlignment alignment) + { + switch (alignment) + { + case TextAlignment.Center: + return 0.5d; + + case TextAlignment.Start: + return 0; + + case TextAlignment.End: + return 1d; + + default: + Log.Warn("Warning: unrecognized HorizontalTextAlignment value {0}. " + + "Expected: {Start|Center|End}.", alignment); + Log.Debug("Falling back to platform's default settings."); + return 0.5d; + } + } + + public static void GetSelectRegion(this Entry 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/Core/src/Platform/Tizen/FlowDirectionExtensions.cs b/src/Core/src/Platform/Tizen/FlowDirectionExtensions.cs new file mode 100644 index 0000000000..39b4f27bbc --- /dev/null +++ b/src/Core/src/Platform/Tizen/FlowDirectionExtensions.cs @@ -0,0 +1,13 @@ +using System; +using ElmSharp; + +namespace Microsoft.Maui.Platform +{ + internal static class FlowDirectionExtensions + { + internal static void UpdateFlowDirection(this EvasObject platformView, IView view) + { + // TODO: Need to impl + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/GraphicsExtensions.cs b/src/Core/src/Platform/Tizen/GraphicsExtensions.cs new file mode 100644 index 0000000000..fd943a2f9f --- /dev/null +++ b/src/Core/src/Platform/Tizen/GraphicsExtensions.cs @@ -0,0 +1,19 @@ +using System; +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Platform +{ + internal static class GraphicsExtensions + { + public static Rect ExpandTo(this Rect geometry, Thickness shadowMargin) + { + var canvasGeometry = new Rect( + geometry.X - shadowMargin.Left, + geometry.Y - shadowMargin.Top, + geometry.Width + shadowMargin.HorizontalThickness, + geometry.Height + shadowMargin.VerticalThickness); + + return canvasGeometry; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs b/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs new file mode 100644 index 0000000000..b6ee57a02f --- /dev/null +++ b/src/Core/src/Platform/Tizen/GraphicsViewExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.Maui.Graphics.Skia.Views; + +namespace Microsoft.Maui.Platform +{ + public static class GraphicsViewExtensions + { + public static void UpdateDrawable(this SkiaGraphicsView platformGraphicsView, IGraphicsView graphicsView) + { + platformGraphicsView.Drawable = graphicsView.Drawable; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/IWrapperViewDrawables.cs b/src/Core/src/Platform/Tizen/IWrapperViewDrawables.cs new file mode 100644 index 0000000000..8265a81363 --- /dev/null +++ b/src/Core/src/Platform/Tizen/IWrapperViewDrawables.cs @@ -0,0 +1,13 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Platform +{ + public interface IWrapperViewDrawables : IDrawable + { + IDrawable? ShadowDrawable { get; set; } + + IDrawable? BackgroundDrawable { get; set; } + + IDrawable? BorderDrawable { get; set; } + } +} diff --git a/src/Core/src/Platform/Tizen/ImageExtensions.cs b/src/Core/src/Platform/Tizen/ImageExtensions.cs new file mode 100644 index 0000000000..607b99cdc0 --- /dev/null +++ b/src/Core/src/Platform/Tizen/ImageExtensions.cs @@ -0,0 +1,22 @@ +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class ImageExtensions + { + public static void Clear(this Image platformImage) + { + } + + public static void UpdateAspect(this Image platformImage, IImage image) + { + platformImage.Aspect = image.Aspect.ToPlatform(); + } + + public static void UpdateIsAnimationPlaying(this Image platformImage, IImageSourcePart image) + { + platformImage.IsAnimated = image.IsAnimationPlaying; + platformImage.IsAnimationPlaying = image.IsAnimationPlaying; + } + } +} diff --git a/src/Core/src/Platform/Tizen/ImageSourcePartExtensions.cs b/src/Core/src/Platform/Tizen/ImageSourcePartExtensions.cs new file mode 100644 index 0000000000..61be6a98dd --- /dev/null +++ b/src/Core/src/Platform/Tizen/ImageSourcePartExtensions.cs @@ -0,0 +1,63 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class ImageSourcePartExtensions + { + 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; + } + } +} diff --git a/src/Core/src/Platform/Tizen/KeyboardExtensions.cs b/src/Core/src/Platform/Tizen/KeyboardExtensions.cs new file mode 100644 index 0000000000..2377eeac84 --- /dev/null +++ b/src/Core/src/Platform/Tizen/KeyboardExtensions.cs @@ -0,0 +1,76 @@ +using ElmSharp; +using TKeyboard = Tizen.UIExtensions.Common.Keyboard; +using TEntry = Tizen.UIExtensions.ElmSharp.Entry; + +namespace Microsoft.Maui.Platform +{ + public static class KeyboardExtensions + { + public static TKeyboard ToPlatform(this Keyboard keyboard) + { + if (keyboard == Keyboard.Numeric) + { + return TKeyboard.Numeric; + } + else if (keyboard == Keyboard.Telephone) + { + return TKeyboard.PhoneNumber; + } + else if (keyboard == Keyboard.Email) + { + return TKeyboard.Email; + } + else if (keyboard == Keyboard.Url) + { + return TKeyboard.Url; + } + else + { + return TKeyboard.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 TEntry control, Keyboard keyboard, bool isSpellCheckEnabled, bool isTextPredictionEnabled) + { + control.Keyboard = keyboard.ToPlatform(); + if (keyboard is CustomKeyboard customKeyboard) + { + control.AutoCapital = customKeyboard.Flags.ToAutoCapital(); + } + else + { + control.AutoCapital = AutoCapital.None; + } + control.InputHint = keyboard.ToInputHints(isSpellCheckEnabled, isTextPredictionEnabled); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/LabelExtensions.cs b/src/Core/src/Platform/Tizen/LabelExtensions.cs new file mode 100644 index 0000000000..37946a2423 --- /dev/null +++ b/src/Core/src/Platform/Tizen/LabelExtensions.cs @@ -0,0 +1,88 @@ +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using TLineBreakMode = Tizen.UIExtensions.Common.LineBreakMode; +using TTextDecorationse = Tizen.UIExtensions.Common.TextDecorations; + +namespace Microsoft.Maui.Platform +{ + public static class LabelExtensions + { + public static void UpdateText(this Label platformLabel, ILabel label) + { + platformLabel.Text = label.Text ?? ""; + } + + public static void UpdateTextColor(this Label platformLabel, ILabel label) + { + platformLabel.TextColor = label.TextColor.ToPlatform(); + } + + public static void UpdateFont(this Label platformLabel, ILabel label, IFontManager fontManager) + { + platformLabel.BatchBegin(); + platformLabel.FontSize = label.Font.Size > 0 ? label.Font.Size : 25.ToDPFont(); + platformLabel.FontAttributes = label.Font.GetFontAttributes(); + platformLabel.FontFamily = fontManager.GetFontFamily(label.Font.Family)??""; + platformLabel.BatchCommit(); + } + + public static void UpdateHorizontalTextAlignment(this Label platformLabel, ILabel label) + { + platformLabel.HorizontalTextAlignment = label.HorizontalTextAlignment.ToPlatform(); + } + + public static void UpdateVerticalTextAlignment(this Label platformLabel, ILabel label) + { + platformLabel.VerticalTextAlignment = label.VerticalTextAlignment.ToPlatform(); + } + + public static void UpdateTextDecorations(this Label platformLabel, ILabel label) + { + platformLabel.TextDecorations = label.TextDecorations.ToPlatform(); + } + + public static FontAttributes GetFontAttributes(this Font font) + { + FontAttributes attributes = font.Weight == FontWeight.Bold ? FontAttributes.Bold : FontAttributes.None; + if (font.Slant != FontSlant.Default) + { + if (attributes == FontAttributes.None) + attributes = FontAttributes.Italic; + else + attributes = attributes | FontAttributes.Italic; + } + return attributes; + } + + public static TLineBreakMode ToPlatform(this LineBreakMode mode) + { + switch (mode) + { + case LineBreakMode.CharacterWrap: + return TLineBreakMode.CharacterWrap; + case LineBreakMode.HeadTruncation: + return TLineBreakMode.HeadTruncation; + case LineBreakMode.MiddleTruncation: + return TLineBreakMode.MiddleTruncation; + case LineBreakMode.NoWrap: + return TLineBreakMode.NoWrap; + case LineBreakMode.TailTruncation: + return TLineBreakMode.TailTruncation; + case LineBreakMode.WordWrap: + default: + return TLineBreakMode.WordWrap; + } + } + + public static TTextDecorationse ToPlatform(this TextDecorations td) + { + if (td == TextDecorations.Strikethrough) + return TTextDecorationse.Strikethrough; + else if (td == TextDecorations.Underline) + return TTextDecorationse.Underline; + else + return TTextDecorationse.None; + } + + } +} diff --git a/src/Core/src/Platform/Tizen/LayoutCanvas.cs b/src/Core/src/Platform/Tizen/LayoutCanvas.cs new file mode 100644 index 0000000000..7aa89aa8eb --- /dev/null +++ b/src/Core/src/Platform/Tizen/LayoutCanvas.cs @@ -0,0 +1,49 @@ +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/LayoutCanvasExtensions.cs b/src/Core/src/Platform/Tizen/LayoutCanvasExtensions.cs new file mode 100644 index 0000000000..f9c8d3dba1 --- /dev/null +++ b/src/Core/src/Platform/Tizen/LayoutCanvasExtensions.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Maui.Platform +{ + public static class LayoutCanvasExtensions + { + public static void UpdateClipsToBounds(this LayoutCanvas layoutCanvas, ILayout layout) + { + //TODO: Need to impl + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiApplication.cs b/src/Core/src/Platform/Tizen/MauiApplication.cs new file mode 100644 index 0000000000..044ac49a0c --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiApplication.cs @@ -0,0 +1,117 @@ +using System; +using ElmSharp; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui.Hosting; +using Microsoft.Maui.LifecycleEvents; +using Tizen.Applications; + +namespace Microsoft.Maui +{ + public abstract class MauiApplication : CoreUIApplication, IPlatformApplication + { + IMauiContext _applicationContext = null!; + + protected MauiApplication() + { + Current = this; + IPlatformApplication.Current = this; + } + + protected abstract MauiApp CreateMauiApp(); + + protected override void OnPreCreate() + { + base.OnPreCreate(); + + Elementary.Initialize(); + Elementary.ThemeOverlay(); + + var mauiApp = CreateMauiApp(); + + var rootContext = new MauiContext(mauiApp.Services); + + var platformWindow = CoreAppExtensions.GetDefaultWindow(); + platformWindow.Initialize(); + rootContext.AddWeakSpecific(platformWindow); + + _applicationContext = rootContext.MakeApplicationScope(this); + + Services = _applicationContext.Services; + + Current.Services?.InvokeLifecycleEvents(del => del(this)); + } + + protected override void OnCreate() + { + base.OnCreate(); + + Application = Services.GetRequiredService(); + + this.SetApplicationHandler(Application, _applicationContext); + + this.CreateNativeWindow(Application); + + Current.Services?.InvokeLifecycleEvents(del => del(this)); + } + + protected override void OnAppControlReceived(AppControlReceivedEventArgs e) + { + base.OnAppControlReceived(e); + Current.Services?.InvokeLifecycleEvents(del => del(this, e)); + } + + protected override void OnDeviceOrientationChanged(DeviceOrientationEventArgs e) + { + base.OnDeviceOrientationChanged(e); + Current.Services?.InvokeLifecycleEvents(del => del(this, e)); + } + + protected override void OnLocaleChanged(LocaleChangedEventArgs e) + { + base.OnLocaleChanged(e); + Current.Services?.InvokeLifecycleEvents(del => del(this, e)); + } + + protected override void OnLowBattery(LowBatteryEventArgs e) + { + base.OnLowBattery(e); + Current.Services?.InvokeLifecycleEvents(del => del(this, e)); + } + + protected override void OnLowMemory(LowMemoryEventArgs e) + { + base.OnLowMemory(e); + Current.Services?.InvokeLifecycleEvents(del => del(this, e)); + } + + protected override void OnPause() + { + base.OnPause(); + Current.Services?.InvokeLifecycleEvents(del => del(this)); + } + + protected override void OnRegionFormatChanged(RegionFormatChangedEventArgs e) + { + base.OnRegionFormatChanged(e); + Current.Services?.InvokeLifecycleEvents(del => del(this, e)); + } + + protected override void OnResume() + { + base.OnResume(); + Current.Services?.InvokeLifecycleEvents(del => del(this)); + } + + protected override void OnTerminate() + { + base.OnTerminate(); + Current.Services?.InvokeLifecycleEvents(del => del(this)); + } + + public static new MauiApplication Current { get; private set; } = null!; + + public IServiceProvider Services { get; protected set; } = null!; + + public IApplication Application { get; protected set; } = null!; + } +} diff --git a/src/Core/src/Platform/Tizen/MauiBoxView.cs b/src/Core/src/Platform/Tizen/MauiBoxView.cs new file mode 100644 index 0000000000..628c31233d --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiBoxView.cs @@ -0,0 +1,12 @@ +using ElmSharp; +using Microsoft.Maui.Graphics.Skia.Views; + +namespace Microsoft.Maui.Platform +{ + public class MauiBoxView : SkiaGraphicsView + { + public MauiBoxView(EvasObject parent) : base(parent) + { + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiContextExtensions.cs b/src/Core/src/Platform/Tizen/MauiContextExtensions.cs new file mode 100644 index 0000000000..b8d9cc9aaa --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiContextExtensions.cs @@ -0,0 +1,18 @@ +using ElmSharp; +using Microsoft.Extensions.DependencyInjection; +using ELayout = ElmSharp.Layout; + +namespace Microsoft.Maui.Platform +{ + internal static partial class MauiContextExtensions + { + public static Window GetNativeWindow(this IMauiContext mauiContext) => + mauiContext.Services.GetRequiredService(); + + public static ELayout GetNativeParent(this IMauiContext mauiContext) => + mauiContext.GetNativeWindow().GetBaseLayout(); + + public static ModalStack GetModalStack(this IMauiContext mauiContext) => + mauiContext.GetNativeWindow().GetModalStack(); + } +} diff --git a/src/Core/src/Platform/Tizen/MauiImageButton.cs b/src/Core/src/Platform/Tizen/MauiImageButton.cs new file mode 100644 index 0000000000..c34f6a68e4 --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiImageButton.cs @@ -0,0 +1,65 @@ +using System; +using ElmSharp; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using TButton = Tizen.UIExtensions.ElmSharp.Button; +using TImage = Tizen.UIExtensions.ElmSharp.Image; + +namespace Microsoft.Maui.Platform +{ + public class MauiImageButton : Canvas + { + TImage _image; + TButton _button; + + public MauiImageButton(EvasObject parent) : base(parent) + { + _image = new TImage(parent); + _button = new TButton(parent); + + _button.Clicked += OnClicked; + _button.Pressed += OnPressed; + _button.Released += OnReleased; + _button.SetTransparentStyle(); + + Children.Add(_image); + _image.RaiseTop(); + + Children.Add(_button); + _button.SetTransparentStyle(); + _button.RaiseTop(); + + LayoutUpdated += OnLayout; + } + + public TImage ImageView + { + get => _image; + } + + public event EventHandler? Clicked; + public event EventHandler? Pressed; + public event EventHandler? Released; + + void OnReleased(object? sender, EventArgs e) + { + Released?.Invoke(this, EventArgs.Empty); + } + + void OnPressed(object? sender, EventArgs e) + { + Pressed?.Invoke(this, EventArgs.Empty); + } + + void OnClicked(object? sender, EventArgs e) + { + Clicked?.Invoke(this, EventArgs.Empty); + } + + void OnLayout(object? sender, LayoutEventArgs e) + { + _button.Geometry = Geometry; + _image.Geometry = Geometry; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiIndicatorViewExtensions.cs b/src/Core/src/Platform/Tizen/MauiIndicatorViewExtensions.cs new file mode 100644 index 0000000000..0b1b1c05ae --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiIndicatorViewExtensions.cs @@ -0,0 +1,20 @@ +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class MauiIndicatorViewExtensions + { + public static void UpdateIndicatorCount(this IndicatorView platformView, IIndicatorView indicator) + { + platformView.ClearIndex(); + platformView.AppendIndex(indicator.Count); + platformView.Update(0); + platformView.UpdatePosition(indicator); + } + + public static void UpdatePosition(this IndicatorView platformView, IIndicatorView indicator) + { + platformView.UpdateSelectedIndex(indicator.Position); + } + } +} diff --git a/src/Core/src/Platform/Tizen/MauiRadioButton.cs b/src/Core/src/Platform/Tizen/MauiRadioButton.cs new file mode 100644 index 0000000000..c1ee2dd443 --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiRadioButton.cs @@ -0,0 +1,145 @@ +using System; +using ElmSharp; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using TSize = Tizen.UIExtensions.Common.Size; +using TColor = Tizen.UIExtensions.Common.Color; + +namespace Microsoft.Maui.Platform +{ + public class MauiRadioButton : Radio, IMeasurable, IBatchable + { + public MauiRadioButton(EvasObject parent) : base(parent) + { + } + + readonly Span _span = new Span(); + + public override string Text + { + get + { + return _span.Text; + } + + set + { + if (value != _span.Text) + { + _span.Text = value; + ApplyTextAndStyle(); + } + } + } + + public TColor TextColor + { + get + { + return _span.ForegroundColor; + } + + set + { + if (!_span.ForegroundColor.Equals(value)) + { + _span.ForegroundColor = value; + ApplyTextAndStyle(); + } + } + } + + public string FontFamily + { + get + { + return _span.FontFamily; + } + + set + { + if (value != _span.FontFamily) + { + _span.FontFamily = value; + ApplyTextAndStyle(); + } + } + } + + public FontAttributes FontAttributes + { + get + { + return _span.FontAttributes; + } + + set + { + if (value != _span.FontAttributes) + { + _span.FontAttributes = value; + ApplyTextAndStyle(); + } + } + } + + public double FontSize + { + get + { + return _span.FontSize; + } + + set + { + if (value != _span.FontSize) + { + _span.FontSize = value; + ApplyTextAndStyle(); + } + } + } + + public virtual TSize Measure(double availableWidth, double availableHeight) + { + Resize(availableWidth.ToScaledPixel(), Geometry.Height); + var formattedSize = this.GetTextBlockFormattedSize(); + Resize(Geometry.Width, Geometry.Height); + return new TSize + { + Width = MinimumWidth + formattedSize.Width, + Height = Math.Max(MinimumHeight, formattedSize.Height) + }; + } + + void IBatchable.OnBatchCommitted() + { + ApplyTextAndStyle(); + } + + void ApplyTextAndStyle() + { + if (!this.IsBatched()) + { + SetInternalTextAndStyle(_span.GetDecoratedText(), _span.GetStyle()); + } + } + + void SetInternalTextAndStyle(string formattedText, string textStyle) + { + bool isVisible = true; + if (string.IsNullOrEmpty(formattedText)) + { + base.Text = null; + this.SetTextBlockStyle(""); + this.SendTextVisibleSignal(false); + } + else + { + base.Text = formattedText; + this.SetTextBlockStyle(textStyle); + this.SendTextVisibleSignal(isVisible); + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiShapeView.cs b/src/Core/src/Platform/Tizen/MauiShapeView.cs new file mode 100644 index 0000000000..6baeb99bcc --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiShapeView.cs @@ -0,0 +1,12 @@ +using ElmSharp; +using Microsoft.Maui.Graphics.Skia.Views; + +namespace Microsoft.Maui.Platform +{ + public class MauiShapeView : SkiaGraphicsView + { + public MauiShapeView(EvasObject parent) : base(parent) + { + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/MauiWebView.cs b/src/Core/src/Platform/Tizen/MauiWebView.cs new file mode 100644 index 0000000000..e099eac33f --- /dev/null +++ b/src/Core/src/Platform/Tizen/MauiWebView.cs @@ -0,0 +1,41 @@ +using System; +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; +using TWebView = Tizen.WebView.WebView; + +namespace Microsoft.Maui.Platform +{ + public class MauiWebView : WidgetLayout, IWebViewDelegate + { + public TWebView WebView { get; } + + public MauiWebView(EvasObject parent) : base(parent) + { + WebView = new TWebView(parent); + SetContent(WebView); + AllowFocus(true); + Focused += OnFocused; + Unfocused += OnUnfocused; + } + + void IWebViewDelegate.LoadHtml(string? html, string? baseUrl) + { + WebView.LoadHtml(baseUrl ?? string.Empty, html ?? string.Empty); + } + + void IWebViewDelegate.LoadUrl(string? url) + { + WebView.LoadUrl(url ?? string.Empty); + } + + void OnFocused(object? sender, EventArgs e) + { + WebView.SetFocus(true); + } + + void OnUnfocused(object? sender, EventArgs e) + { + WebView.SetFocus(false); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ModalStack.cs b/src/Core/src/Platform/Tizen/ModalStack.cs new file mode 100644 index 0000000000..e6da597eff --- /dev/null +++ b/src/Core/src/Platform/Tizen/ModalStack.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.Linq; +using ElmSharp; +using EBox = ElmSharp.Box; + +namespace Microsoft.Maui.Platform +{ + public class ModalStack : EBox + { + EvasObject? _lastTop; + + public ModalStack(EvasObject parent) : base(parent) + { + InternalStack = new List(); + SetLayoutCallback(OnLayout); + } + + List InternalStack { get; set; } + + public IReadOnlyList Stack => InternalStack; + + public void Push(EvasObject view) + { + InternalStack.Add(view); + PackEnd(view); + UpdateTopView(); + } + + public void Pop() + { + if (_lastTop != null) + { + var tobeRemoved = _lastTop; + InternalStack.Remove(tobeRemoved); + UnPack(tobeRemoved); + UpdateTopView(); + // if Pop was called by removed page, + // Unrealize cause deletation of NativeCallback, it could be a cause of crash + EcoreMainloop.Post(() => + { + tobeRemoved.Unrealize(); + }); + } + } + + public void PopToRoot() + { + while (InternalStack.Count > 1) + { + Pop(); + } + } + + public void Insert(EvasObject before, EvasObject view) + { + view.Hide(); + var idx = InternalStack.IndexOf(before); + InternalStack.Insert(idx, view); + PackEnd(view); + UpdateTopView(); + } + + public void Remove(EvasObject view) + { + InternalStack.Remove(view); + UnPack(view); + UpdateTopView(); + EcoreMainloop.Post(() => + { + view?.Unrealize(); + }); + } + + public void Reset() + { + while (InternalStack.Count > 0) + { + Pop(); + } + } + + void UpdateTopView() + { + if (_lastTop != InternalStack.LastOrDefault()) + { + _lastTop?.Hide(); + _lastTop = InternalStack.LastOrDefault(); + _lastTop?.Show(); + (_lastTop as Widget)?.SetFocus(true); + } + } + + void OnLayout() + { + foreach (var view in Stack) + { + view.Geometry = Geometry; + } + } + } +} diff --git a/src/Core/src/Platform/Tizen/PickerExtensions.cs b/src/Core/src/Platform/Tizen/PickerExtensions.cs new file mode 100644 index 0000000000..20d6c3a060 --- /dev/null +++ b/src/Core/src/Platform/Tizen/PickerExtensions.cs @@ -0,0 +1,24 @@ +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class PickerExtensions + { + public static void UpdateTitle(this Entry platformPicker, IPicker picker) => + UpdatePicker(platformPicker, picker); + + public static void UpdateTitleColor(this Entry platformPicker, IPicker picker) => + platformPicker.PlaceholderColor = picker.TitleColor.ToPlatform(); + + public static void UpdateSelectedIndex(this Entry platformPicker, IPicker picker) => + UpdatePicker(platformPicker, picker); + + internal static void UpdatePicker(this Entry platformPicker, IPicker picker) + { + if (picker.SelectedIndex == -1 || picker.SelectedIndex >= picker.GetCount()) + platformPicker.Text = string.Empty; + else + platformPicker.Text = picker.GetItem(picker.SelectedIndex); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/PlatformTouchGraphicsView.cs b/src/Core/src/Platform/Tizen/PlatformTouchGraphicsView.cs new file mode 100644 index 0000000000..6ef97a39fe --- /dev/null +++ b/src/Core/src/Platform/Tizen/PlatformTouchGraphicsView.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ElmSharp; +using Microsoft.Maui.Graphics; +using Microsoft.Maui.Graphics.Skia.Views; + +namespace Microsoft.Maui.Platform +{ + public class PlatformTouchGraphicsView : SkiaGraphicsView + { + IGraphicsView? _graphicsView; + GestureLayer? _gestureLayer; + + public PlatformTouchGraphicsView(EvasObject? parent, IDrawable? drawable = null) : base(parent, drawable) + { + _ = parent ?? throw new ArgumentNullException(nameof(parent)); + } + + public void Connect(IGraphicsView graphicsView) + { + _graphicsView = graphicsView; + _gestureLayer = new GestureLayer(this); + _gestureLayer.Attach(this); + + _gestureLayer.SetTapCallback(GestureLayer.GestureType.Tap, GestureLayer.GestureState.Start, (_) => { OnGestureStarted(); }); + + _gestureLayer.SetTapCallback(GestureLayer.GestureType.Tap, GestureLayer.GestureState.End, (_) => { OnGestureEnded(true); }); + + _gestureLayer.SetLineCallback(GestureLayer.GestureState.Start, (_) => { OnGestureStarted(); }); + + _gestureLayer.SetLineCallback(GestureLayer.GestureState.Move, (_) => { + _graphicsView?.DragInteraction(new[] { _gestureLayer.EvasCanvas.Pointer.ToPointF() }); + }); + + _gestureLayer.SetLineCallback(GestureLayer.GestureState.End, (_) => { + OnGestureEnded(Geometry.ToDP().Contains(_gestureLayer.EvasCanvas.Pointer.ToPoint())); + }); + + _gestureLayer.SetLineCallback(GestureLayer.GestureState.Abort, (_) => { + _graphicsView?.CancelInteraction(); + }); + } + + public void Disconnect() + { + _gestureLayer?.Unrealize(); + _gestureLayer = null; + _graphicsView = null; + } + + void OnGestureStarted() + { + if (_graphicsView is null || _gestureLayer is null) + return; + + _graphicsView.StartInteraction(new[] { _gestureLayer.EvasCanvas.Pointer.ToPointF() }); + } + + void OnGestureEnded(bool isInsideBounds) + { + if (_graphicsView is null || _gestureLayer is null) + return; + + _graphicsView.EndInteraction(new[] { _gestureLayer.EvasCanvas.Pointer.ToPointF() }, isInsideBounds); + } + } +} diff --git a/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs b/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs new file mode 100644 index 0000000000..89ce8489bb --- /dev/null +++ b/src/Core/src/Platform/Tizen/ProgressBarExtensions.cs @@ -0,0 +1,17 @@ +using ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class ProgressBarExtensions + { + public static void UpdateProgress(this ProgressBar platformProgressBar, IProgress progress) + { + platformProgressBar.Value = progress.Progress; + } + + public static void UpdateProgressColor(this ProgressBar platformProgressBar, IProgress progress) + { + platformProgressBar.Color = progress.ProgressColor.ToPlatformEFL(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/RadioButtonExtensions.cs b/src/Core/src/Platform/Tizen/RadioButtonExtensions.cs new file mode 100644 index 0000000000..0c59e2de2b --- /dev/null +++ b/src/Core/src/Platform/Tizen/RadioButtonExtensions.cs @@ -0,0 +1,15 @@ +namespace Microsoft.Maui +{ + public static class RadioButtonExtensions + { + public static void UpdateIsChecked(this MauiRadioButton platformRadioButton, IRadioButton radioButton) + { + platformRadioButton.GroupValue = radioButton.IsChecked ? 1 : 0; + } + + public static void UpdateTextColor(this MauiRadioButton platformRadioButton, ITextStyle radioButton) + { + platformRadioButton.TextColor = radioButton.TextColor.ToPlatform(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/ScrollViewExtensions.cs b/src/Core/src/Platform/Tizen/ScrollViewExtensions.cs new file mode 100644 index 0000000000..6183c14009 --- /dev/null +++ b/src/Core/src/Platform/Tizen/ScrollViewExtensions.cs @@ -0,0 +1,55 @@ +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class ScrollViewExtensions + { + public static void UpdateVerticalScrollBarVisibility(this ScrollView scrollView, ScrollBarVisibility scrollBarVisibility) + { + scrollView.VerticalScrollBarVisiblePolicy = scrollBarVisibility.ToPlatform(); + } + + public static void UpdateHorizontalScrollBarVisibility(this ScrollView scrollView, ScrollBarVisibility scrollBarVisibility) + { + scrollView.HorizontalScrollBarVisiblePolicy = scrollBarVisibility.ToPlatform(); + } + + public static void UpdateOrientation(this ScrollView scrollView, ScrollOrientation scrollOrientation) + { + switch (scrollOrientation) + { + case ScrollOrientation.Horizontal: + scrollView.ScrollBlock = ScrollBlock.Vertical; + scrollView.HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Auto; + scrollView.VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible; + break; + case ScrollOrientation.Vertical: + scrollView.ScrollBlock = ScrollBlock.Horizontal; + scrollView.HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible; + scrollView.VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Auto; + break; + default: + scrollView.ScrollBlock = ScrollBlock.None; + scrollView.HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Auto; + scrollView.VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Auto; + break; + } + } + + public static ScrollBarVisiblePolicy ToPlatform(this ScrollBarVisibility visibility) + { + switch (visibility) + { + case ScrollBarVisibility.Default: + return ScrollBarVisiblePolicy.Auto; + case ScrollBarVisibility.Always: + return ScrollBarVisiblePolicy.Visible; + case ScrollBarVisibility.Never: + return ScrollBarVisiblePolicy.Invisible; + default: + return ScrollBarVisiblePolicy.Auto; + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/SearchBarExtensions.cs b/src/Core/src/Platform/Tizen/SearchBarExtensions.cs new file mode 100644 index 0000000000..d2ec1b46df --- /dev/null +++ b/src/Core/src/Platform/Tizen/SearchBarExtensions.cs @@ -0,0 +1,12 @@ +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class SearchBarExtensions + { + public static void UpdateCancelButtonColor(this SearchBar platformView, ISearchBar searchBar) + { + platformView.SetClearButtonColor(searchBar.CancelButtonColor.ToPlatformEFL()); + } + } +} diff --git a/src/Core/src/Platform/Tizen/ShapeViewExtensions.cs b/src/Core/src/Platform/Tizen/ShapeViewExtensions.cs new file mode 100644 index 0000000000..e8dca6fe0c --- /dev/null +++ b/src/Core/src/Platform/Tizen/ShapeViewExtensions.cs @@ -0,0 +1,17 @@ +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Platform +{ + public static class ShapeViewExtensions + { + public static void UpdateShape(this MauiShapeView platformView, IShapeView shapeView) + { + platformView.Drawable = new ShapeDrawable(shapeView); + } + + public static void InvalidateShape(this MauiShapeView platformView, IShapeView shapeView) + { + platformView.Invalidate(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/SliderExtensions.cs b/src/Core/src/Platform/Tizen/SliderExtensions.cs new file mode 100644 index 0000000000..7996c43558 --- /dev/null +++ b/src/Core/src/Platform/Tizen/SliderExtensions.cs @@ -0,0 +1,76 @@ +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; +using EColor = ElmSharp.Color; + +namespace Microsoft.Maui.Platform +{ + public static class SliderExtensions + { + public static void UpdateMinimum(this Slider platformSlider, ISlider slider) + { + platformSlider.Minimum = slider.Minimum; + } + + public static void UpdateMaximum(this Slider platformSlider, ISlider slider) + { + platformSlider.Maximum = slider.Maximum; + } + + public static void UpdateValue(this Slider platformSlider, ISlider slider) + { + platformSlider.Value = slider.Value; + } + + public static void UpdateMinimumTrackColor(this Slider platformSlider, ISlider slider) + { + UpdateMinimumTrackColor(platformSlider, slider, null); + } + + public static void UpdateMinimumTrackColor(this Slider platformSlider, ISlider slider, EColor? defaultMinTrackColor) + { + if (slider.MinimumTrackColor == null) + { + if (defaultMinTrackColor != null) + platformSlider.SetBarColor(defaultMinTrackColor.Value); + } + else + platformSlider.SetBarColor(slider.MinimumTrackColor.ToPlatformEFL()); + } + + public static void UpdateMaximumTrackColor(this Slider platformSlider, ISlider slider) + { + UpdateMaximumTrackColor(platformSlider, slider, null); + } + + public static void UpdateMaximumTrackColor(this Slider platformSlider, ISlider slider, EColor? defaultMaxTrackColor) + { + if (slider.MaximumTrackColor == null) + { + if (defaultMaxTrackColor != null) + platformSlider.SetBackgroundColor(defaultMaxTrackColor.Value); + } + else + { + platformSlider.SetBackgroundColor(slider.MaximumTrackColor.ToPlatformEFL()); + } + } + + public static void UpdateThumbColor(this Slider platformSlider, ISlider slider) + { + UpdateThumbColor(platformSlider, slider, null); + } + + public static void UpdateThumbColor(this Slider platformSlider, ISlider slider, EColor? defaultThumbColor) + { + if (slider.ThumbColor == null) + { + if (defaultThumbColor != null) + platformSlider.SetHandlerColor(defaultThumbColor.Value); + } + else + { + platformSlider.SetHandlerColor(slider.ThumbColor.ToPlatformEFL()); + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/StepperExtensions.cs b/src/Core/src/Platform/Tizen/StepperExtensions.cs new file mode 100644 index 0000000000..8a0d17b2db --- /dev/null +++ b/src/Core/src/Platform/Tizen/StepperExtensions.cs @@ -0,0 +1,56 @@ +using ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class StepperExtensions + { + public static void UpdateMinimum(this Spinner nativeStepper, IStepper stepper) + { + nativeStepper.Minimum = stepper.Minimum; + } + + public static void UpdateMaximum(this Spinner nativeStepper, IStepper stepper) + { + nativeStepper.Maximum = stepper.Maximum; + } + + public static void UpdateIncrement(this Spinner nativeStepper, IStepper stepper) + { + var increment = stepper.Interval; + + if (increment > 0) + { + nativeStepper.LabelFormat = string.Format("%.{0}f", GetRequiredPrecision(increment)); + nativeStepper.Step = stepper.Interval; + } + } + + public static void UpdateValue(this Spinner nativeStepper, IStepper stepper) + { + if (nativeStepper.Value != stepper.Value) + nativeStepper.Value = stepper.Value; + } + + static int GetRequiredPrecision(double step) + { + // Determines how many decimal places are there in current Stepper's value. + // The 15 pound characters below correspond to the maximum precision of Double type. + var decimalValue = decimal.Parse(step.ToString("0.###############")); + + // GetBits() method returns an array of four 32-bit integer values. + // The third (0-indexing) element of an array contains the following information: + // bits 00-15: unused, required to be 0 + // bits 16-23: an exponent between 0 and 28 indicating the power of 10 to divide the integer number passed as a parameter. + // Conversely this is the number of decimal digits in the number as well. + // bits 24-30: unused, required to be 0 + // bit 31: indicates the sign. 0 means positive number, 1 is for negative numbers. + // + // The precision information needs to be extracted from bits 16-23 of third element of an array + // returned by GetBits() call. Right-shifting by 16 bits followed by zeroing anything else results + // in a nice conversion of this data to integer variable. + var precision = (decimal.GetBits(decimalValue)[3] >> 16) & 0x000000FF; + + return precision; + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/StrokeExtensions.cs b/src/Core/src/Platform/Tizen/StrokeExtensions.cs new file mode 100644 index 0000000000..02de4b0067 --- /dev/null +++ b/src/Core/src/Platform/Tizen/StrokeExtensions.cs @@ -0,0 +1,100 @@ +using ElmSharp; +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Platform +{ + public static class StrokeExtensions + { + public static void UpdateStrokeShape(this EvasObject platformView, IBorderStroke border) + { + var borderShape = border.Shape; + var canvas = platformView as BorderView; + if (canvas == null && borderShape == null) + return; + + platformView.UpdateMauiDrawable(border); + } + + public static void UpdateStroke(this EvasObject platformView, IBorderStroke border) + { + var stroke = border.Stroke; + var canvas = platformView as BorderView; + if (canvas == null && stroke.IsNullOrEmpty()) + return; + + platformView.UpdateMauiDrawable(border); + } + + public static void UpdateStrokeThickness(this EvasObject platformView, IBorderStroke border) + { + var canvas = platformView as BorderView; + bool hasBorder = border.Shape != null && border.Stroke != null; + if (canvas == null && !hasBorder) + return; + + platformView.UpdateMauiDrawable(border); + } + + public static void UpdateStrokeDashPattern(this EvasObject platformView, IBorderStroke border) + { + var strokeDashPattern = border.StrokeDashPattern; + var canvas = platformView as BorderView; + bool hasBorder = border.Shape != null && border.Stroke != null; + if (canvas == null && !hasBorder && (strokeDashPattern == null || strokeDashPattern.Length == 0)) + return; + + platformView.UpdateMauiDrawable(border); + } + + public static void UpdateStrokeDashOffset(this EvasObject platformView, IBorderStroke border) + { + var canvas = platformView as BorderView; + bool hasBorder = border.Shape != null && border.Stroke != null; + if (canvas == null && !hasBorder) + return; + + platformView.UpdateMauiDrawable(border); + } + + public static void UpdateStrokeMiterLimit(this EvasObject platformView, IBorderStroke border) + { + var canvas = platformView as BorderView; + bool hasBorder = border.Shape != null && border.Stroke != null; + if (canvas == null && !hasBorder) + return; + + platformView.UpdateMauiDrawable(border); + } + + public static void UpdateStrokeLineCap(this EvasObject platformView, IBorderStroke border) + { + var canvas = platformView as BorderView; + bool hasBorder = border.Shape != null && border.Stroke != null; + if (canvas == null && !hasBorder) + return; + platformView.UpdateMauiDrawable(border); + } + + public static void UpdateStrokeLineJoin(this EvasObject platformView, IBorderStroke border) + { + var canvas = platformView as BorderView; + bool hasBorder = border.Shape != null && border.Stroke != null; + if (canvas == null && !hasBorder) + return; + + platformView.UpdateMauiDrawable(border); + } + + internal static void UpdateMauiDrawable(this EvasObject platformView, IBorderStroke border) + { + bool hasBorder = border.Shape != null && border.Stroke != null; + if (!hasBorder) + return; + + if (platformView is BorderView borderView) + { + borderView.ContainerView?.UpdateBorder(border); + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/SwitchExtensions.cs b/src/Core/src/Platform/Tizen/SwitchExtensions.cs new file mode 100644 index 0000000000..1eb9659a59 --- /dev/null +++ b/src/Core/src/Platform/Tizen/SwitchExtensions.cs @@ -0,0 +1,33 @@ +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class SwitchExtensions + { + public static void UpdateIsOn(this Check platformCheck, ISwitch view) + { + platformCheck.IsChecked = view.IsOn; + } + + public static void UpdateTrackColor(this Check platformCheck, ISwitch view) + { + if (view.ThumbColor != null) + { + platformCheck.Color = view.TrackColor.ToPlatformEFL(); + } + } + + public static void UpdateThumbColor(this Check platformCheck, ISwitch view) + { + if (view.ThumbColor == null) + { + platformCheck.DeleteOnColors(); + } + else + { + platformCheck.SetOnColors(view.ThumbColor.ToPlatformEFL()); + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/TimePickerExtensions.cs b/src/Core/src/Platform/Tizen/TimePickerExtensions.cs new file mode 100644 index 0000000000..21cff819a8 --- /dev/null +++ b/src/Core/src/Platform/Tizen/TimePickerExtensions.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class TimePickerExtensions + { + static readonly string s_defaultFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern; + static TimeSpan Time = DateTime.Now.TimeOfDay; + + public static void UpdateFormat(this Entry platformTimePicker, ITimePicker timePicker) + { + UpdateTime(platformTimePicker, timePicker); + } + + public static void UpdateTime(this Entry platformTimePicker, ITimePicker timePicker) + { + // Xamarin using DateTime formatting (https://developer.xamarin.com/api/property/Xamarin.Forms.TimePicker.Format/) + platformTimePicker.Text = new DateTime(Time.Ticks).ToString(timePicker.Format ?? s_defaultFormat); + } + + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/TransformationExtensions.cs b/src/Core/src/Platform/Tizen/TransformationExtensions.cs new file mode 100644 index 0000000000..22f6251c7e --- /dev/null +++ b/src/Core/src/Platform/Tizen/TransformationExtensions.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using ElmSharp; +using Tizen.UIExtensions.ElmSharp; + +namespace Microsoft.Maui.Platform +{ + public static class TransformationExtensions + { + static Dictionary s_movedHandlers = new Dictionary(); + + public static void UpdateTransformation(this EvasObject platformView, IView? view) + { + if (view == null) + return; + + // prepare the EFL effect structure + Rect geometry = platformView.Geometry; + EvasMap map = new EvasMap(4); + map.PopulatePoints(geometry, 0); + + bool changed = false; + view.ApplyScale(map, geometry, ref changed); + view.ApplyRotation(platformView, map, geometry, ref changed); + view.ApplyTranslation(map, geometry, ref changed); + + platformView.IsMapEnabled = changed; + + if (changed) + { + platformView.EvasMap = map; + if (!s_movedHandlers.ContainsKey(platformView)) + { + // not registered moved handler + s_movedHandlers[platformView] = () => platformView.UpdateTransformation(view); + platformView.Moved += OnMoved; + } + } + else + { + if (s_movedHandlers.ContainsKey(platformView)) + { + // need to unregister moved handler + platformView.Moved -= OnMoved; + s_movedHandlers.Remove(platformView); + } + } + } + + static void OnMoved(object? sender, EventArgs e) + { + if (sender is EvasObject platformView) + { + s_movedHandlers[platformView].Invoke(); + } + } + + internal static void ApplyScale(this IView view, EvasMap map, Rect geometry, ref bool changed) + { + var scale = view.Scale; + var scaleX = view.ScaleX * scale; + var scaleY = view.ScaleY * scale; + + // apply scale factor + if (scaleX != 1.0 || scaleY != 1.0) + { + map.Zoom(scaleX, scaleY, + geometry.X + (int)(geometry.Width * view.AnchorX), + geometry.Y + (int)(geometry.Height * view.AnchorY)); + changed = true; + } + } + + internal static void ApplyRotation(this IView view, EvasObject platformView, EvasMap map, Rect geometry, ref bool changed) + { + var rotationX = view.RotationX; + var rotationY = view.RotationY; + var rotationZ = view.Rotation; + var anchorX = view.AnchorX; + var anchorY = view.AnchorY; + + // apply rotations + if (rotationX != 0 || rotationY != 0 || rotationZ != 0) + { + map.Rotate3D(rotationX, rotationY, rotationZ, (int)(geometry.X + geometry.Width * anchorX), + (int)(geometry.Y + geometry.Height * anchorY), 0); + // the last argument is focal length, it determine the strength of distortion. We compared it with the Android implementation + map.Perspective3D(geometry.X + geometry.Width / 2, geometry.Y + geometry.Height / 2, 0, (int)(1.3 * Math.Max(geometry.Height, geometry.Width))); + // Need to unset clip because perspective 3d rotation is going beyond the container bound + platformView.SetClip(null); + changed = true; + } + } + + internal static void ApplyTranslation(this IView view, EvasMap map, Rect geometry, ref bool changed) + { + var shiftX = view.TranslationX.ToScaledPixel(); + var shiftY = view.TranslationY.ToScaledPixel(); + + // apply translation, i.e. move/shift the object a little + if (shiftX != 0 || shiftY != 0) + { + if (changed) + { + // special care is taken to apply the translation last + Point3D p; + for (int i = 0; i < 4; i++) + { + p = map.GetPointCoordinate(i); + p.X += shiftX; + p.Y += shiftY; + map.SetPointCoordinate(i, p); + } + } + else + { + // in case when we only need translation, then construct the map in a simpler way + geometry.X += shiftX; + geometry.Y += shiftY; + map.PopulatePoints(geometry, 0); + + changed = true; + } + } + } + + 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); + IntPtr? handle = (IntPtr?)propInfo?.GetValue(map); + if (handle != null) + evas_map_util_3d_perspective(handle.Value, 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/Core/src/Platform/Tizen/ViewExtensions.cs b/src/Core/src/Platform/Tizen/ViewExtensions.cs new file mode 100644 index 0000000000..dfa133c55c --- /dev/null +++ b/src/Core/src/Platform/Tizen/ViewExtensions.cs @@ -0,0 +1,275 @@ +using System; +using System.Diagnostics; +using System.Numerics; +using System.Threading.Tasks; +using Microsoft.Maui.Graphics; +using ElmSharp; +using ElmSharp.Accessible; +using Tizen.UIExtensions.ElmSharp; +using static Microsoft.Maui.Primitives.Dimension; +using Rect = Microsoft.Maui.Graphics.Rect; + +namespace Microsoft.Maui.Platform +{ + public static partial class ViewExtensions + { + public static void UpdateIsEnabled(this EvasObject platformView, IView view) + { + if (!(platformView is Widget widget)) + return; + + widget.IsEnabled = view.IsEnabled; + } + + public static void Focus(this EvasObject platformView, FocusRequest request) + { + // TODO: Implement Focus on Tizen (ref #4588) + } + + public static void Unfocus(this EvasObject platformView, IView view) + { + // TODO: Implement Unfocus on Tizen (ref #4588) + } + + public static void UpdateVisibility(this EvasObject platformView, IView view) + { + if (view.Visibility.ToPlatformVisibility()) + { + platformView.Show(); + } + else + { + platformView.Hide(); + } + } + + public static bool ToPlatformVisibility(this Visibility visibility) + { + return visibility switch + { + Visibility.Hidden => false, + Visibility.Collapsed => false, + _ => true, + }; + } + + public static void UpdateBackground(this EvasObject platformView, IView view) + { + var paint = view.Background; + + if (platformView is WrapperView wrapperView) + { + wrapperView.UpdateBackground(paint); + } + else if (platformView is BorderView borderView) + { + borderView.ContainerView?.UpdateBackground(paint); + } + else if (paint is not null) + { + platformView.UpdateBackgroundColor(paint.ToPlatform()); + } + } + + public static void UpdateBorder(this EvasObject platformView, IView view) + { + var border = (view as IBorder)?.Border; + + if (platformView is WrapperView wrapperView) + wrapperView.Border = border; + } + + public static void UpdateOpacity(this EvasObject platformView, IView view) + { + if (platformView is Widget widget) + { + widget.Opacity = (int)(view.Opacity * 255.0); + } + } + + public static void UpdateClip(this EvasObject platformView, IView view) + { + if (platformView is WrapperView wrapper) + wrapper.Clip = view.Clip; + } + + public static void UpdateShadow(this EvasObject platformView, IView view) + { + if (platformView is WrapperView wrapper) + wrapper.Shadow = view.Shadow; + } + + public static void UpdateAutomationId(this EvasObject platformView, IView view) + { + { + //TODO: EvasObject.AutomationId is supported from tizen60. + //platformView.AutomationId = view.AutomationId; + } + } + + public static void UpdateSemantics(this EvasObject platformView, IView view) + { + var semantics = view.Semantics; + var accessibleObject = platformView as IAccessibleObject; + + if (semantics == null || accessibleObject == null) + return; + + accessibleObject.Name = semantics.Description; + accessibleObject.Description = semantics.Hint; + } + + public static void InvalidateMeasure(this EvasObject platformView, IView view) + { + platformView.MarkChanged(); + } + + public static void UpdateWidth(this EvasObject platformView, IView view) + { + UpdateSize(platformView, view); + } + + public static void UpdateHeight(this EvasObject platformView, IView view) + { + UpdateSize(platformView, view); + } + + public static void UpdateMinimumWidth(this EvasObject platformView, IView view) + { + UpdateSize(platformView, view); + } + + public static void UpdateMinimumHeight(this EvasObject platformView, IView view) + { + UpdateSize(platformView, view); + } + + public static void UpdateMaximumWidth(this EvasObject platformView, IView view) + { + UpdateSize(platformView, view); + } + + public static void UpdateMaximumHeight(this EvasObject platformView, IView view) + { + UpdateSize(platformView, view); + } + + public static void UpdateInputTransparent(this EvasObject platformView, IViewHandler handler, IView view) + { + platformView.PassEvents = view.InputTransparent; + } + + public static void UpdateSize(EvasObject platformView, IView view) + { + if (!IsExplicitSet(view.Width) || !IsExplicitSet(view.Height)) + { + // Ignore the initial setting of the value; the initial layout will take care of it + return; + } + + // Updating the frame (assuming it's an actual change) will kick off a layout update + // Handling of the default (-1) width/height will be taken care of by GetDesiredSize + platformView.Resize(view.Width.ToScaledPixel(), view.Height.ToScaledPixel()); + } + + internal static Rect GetPlatformViewBounds(this IView view) + { + var platformView = view?.ToPlatform(); + if (platformView == null) + { + return new Rect(); + } + + return platformView.GetPlatformViewBounds(); + } + + internal static Rect GetPlatformViewBounds(this EvasObject platformView) + { + if (platformView == null) + return new Rect(); + + return platformView.Geometry.ToDP(); + } + + internal static Matrix4x4 GetViewTransform(this IView view) + { + var platformView = view?.ToPlatform(); + if (platformView == null) + return new Matrix4x4(); + return platformView.GetViewTransform(); + } + + internal static Matrix4x4 GetViewTransform(this EvasObject platformView) + => new Matrix4x4(); + + internal static Rect GetBoundingBox(this IView view) + => view.ToPlatform().GetBoundingBox(); + + internal static Rect GetBoundingBox(this EvasObject? platformView) + { + if (platformView == null) + return new Rect(); + + return platformView.Geometry.ToDP(); + } + + internal static EvasObject? GetParent(this EvasObject? view) + { + return view?.Parent; + } + + // TODO : Should consider a better way to determine that the view has been loaded/unloaded. + internal static bool IsLoaded(this EvasObject view) => + view.IsRealized; + + internal static IDisposable OnLoaded(this EvasObject view, Action action) + { + if (view.IsLoaded()) + { + action(); + return new ActionDisposable(() => { }); + } + + EventHandler? renderPostEventHandler = null; + ActionDisposable disposable = new ActionDisposable(() => + { + if (renderPostEventHandler != null) + view.RenderPost -= renderPostEventHandler; + }); + + renderPostEventHandler = (_, __) => + { + disposable.Dispose(); + action(); + }; + + view.RenderPost += renderPostEventHandler; + return disposable; + } + + internal static IDisposable OnUnloaded(this EvasObject view, Action action) + { + if (!view.IsLoaded()) + { + action(); + return new ActionDisposable(() => { }); + } + + EventHandler? deletedEventHandler = null; + ActionDisposable disposable = new ActionDisposable(() => + { + if (deletedEventHandler != null) + view.Deleted -= deletedEventHandler; + }); + + deletedEventHandler = (_, __) => + { + disposable.Dispose(); + action(); + }; + + view.Deleted += deletedEventHandler; + return disposable; + } + } +} diff --git a/src/Core/src/Platform/Tizen/WebViewExtensions.cs b/src/Core/src/Platform/Tizen/WebViewExtensions.cs new file mode 100644 index 0000000000..02bafd7ed8 --- /dev/null +++ b/src/Core/src/Platform/Tizen/WebViewExtensions.cs @@ -0,0 +1,57 @@ + +namespace Microsoft.Maui.Platform +{ + public static class WebViewExtensions + { + public static void UpdateSource(this MauiWebView platformWebView, IWebView webView) + { + platformWebView.UpdateSource(webView, null); + } + + public static void UpdateSource(this MauiWebView platformWebView, IWebView webView, IWebViewDelegate? webViewDelegate) + { + if (webViewDelegate != null) + webView.Source?.Load(webViewDelegate); + } + + public static void UpdateGoBack(this MauiWebView platformWebView, IWebView webView) + { + if (platformWebView == null) + return; + + if (platformWebView.WebView.CanGoBack()) + platformWebView.WebView.GoBack(); + + platformWebView.UpdateCanGoBackForward(webView); + } + + public static void UpdateGoForward(this MauiWebView platformWebView, IWebView webView) + { + if (platformWebView == null) + return; + + if (platformWebView.WebView.CanGoForward()) + platformWebView.WebView.GoForward(); + + platformWebView.UpdateCanGoBackForward(webView); + } + + public static void UpdateReload(this MauiWebView platformWebView, IWebView webView) + { + // TODO: Sync Cookies + + platformWebView?.WebView.Reload(); + } + + internal static void UpdateCanGoBackForward(this MauiWebView platformWebView, IWebView webView) + { + webView.CanGoBack = platformWebView.WebView.CanGoBack(); + webView.CanGoForward = platformWebView.WebView.CanGoForward(); + } + + public static void Eval(this MauiWebView platformWebView, IWebView webView, string script) + { + platformWebView.WebView.Eval(script); + } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Tizen/WindowExtensions.cs b/src/Core/src/Platform/Tizen/WindowExtensions.cs new file mode 100644 index 0000000000..b21b0972d5 --- /dev/null +++ b/src/Core/src/Platform/Tizen/WindowExtensions.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading.Tasks; +using ElmSharp; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using ELayout = ElmSharp.Layout; + +namespace Microsoft.Maui.Platform +{ + public static partial 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 platformWindow) + { + var baseLayout = (ELayout?)platformWindow.GetType().GetProperty("BaseLayout")?.GetValue(platformWindow); + + if (baseLayout == null) + { + var conformant = new Conformant(platformWindow); + conformant.Show(); + + var layout = new ApplicationLayout(conformant); + layout.Show(); + + baseLayout = layout; + conformant.SetContent(baseLayout); + } + platformWindow.SetBaseLayout(baseLayout); + var modalStack = new ModalStack(baseLayout) + { + AlignmentX = -1, + AlignmentY = -1, + WeightX = 1, + WeightY = 1, + }; + modalStack.Show(); + baseLayout.SetContent(modalStack); + platformWindow.SetModalStack(modalStack); + + platformWindow.Active(); + platformWindow.Show(); + platformWindow.AvailableRotations = DisplayRotation.Degree_0 | DisplayRotation.Degree_90 | DisplayRotation.Degree_180 | DisplayRotation.Degree_270; + + platformWindow.RotationChanged += (sender, e) => + { + // TODO : should update later + }; + + platformWindow.BackButtonPressed += (s, e) => OnBackButtonPressed(platformWindow); + } + + 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; + } + + public static float GetDisplayDensity(this Window window) + { + return (float)DeviceInfo.ScalingFactor; + } + + 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 diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs new file mode 100644 index 0000000000..bbd979f9ad --- /dev/null +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -0,0 +1,310 @@ +using System; +using System.Runtime.InteropServices; +using ElmSharp; +using Microsoft.Maui.Graphics; +using Microsoft.Maui.Graphics.Skia; +using Microsoft.Maui.Graphics.Skia.Views; +using SkiaSharp.Views.Tizen; +using Tizen.UIExtensions.Common; +using Tizen.UIExtensions.ElmSharp; +using Rect = Microsoft.Maui.Graphics.Rect; + +namespace Microsoft.Maui.Platform +{ + public partial class WrapperView : Canvas + { + Lazy _drawableCanvas; + Lazy _clipperView; + EvasObject? _content; + + public WrapperView(EvasObject parent) : base(parent) + { + _drawableCanvas = new Lazy(() => + { + var view = new SkiaGraphicsView(parent) + { + IgnorePixelScaling = true, + Drawable = new MauiDrawable(), + PassEvents = true + }; + view.Show(); + Children.Add(view); + view.Lower(); + Content?.RaiseTop(); + return view; + }); + + _clipperView = new Lazy(() => + { + var clipper = new SKClipperView(parent) + { + PassEvents = true + }; + clipper.DrawClip += OnClipPaint; + clipper.Show(); + clipper.DeviceScalingFactor = (float)DeviceInfo.ScalingFactor; + Children.Add(clipper); + clipper.Lower(); + Content?.RaiseTop(); + return clipper; + }); + + LayoutUpdated += OnLayout; + } + + public void UpdateBackground(Paint? paint) + { + UpdateDrawableCanvas(paint); + } + + public void UpdateShape(IShape? shape) + { + UpdateDrawableCanvas(shape); + } + + public void UpdateBorder(IBorderStroke border) + { + ((MauiDrawable)_drawableCanvas.Value.Drawable).Border = border; + UpdateShape(border.Shape); + } + + partial void ShadowChanged() + { + if (!_drawableCanvas.IsValueCreated && Shadow is null) + return; + + ((MauiDrawable)_drawableCanvas.Value.Drawable).Shadow = Shadow; + + if (Shadow != null) + { + _drawableCanvas.Value.SetClip(null); + } + UpdateDrawableCanvas(true); + } + + partial void ClipChanged() + { + if (_drawableCanvas.IsValueCreated || Clip is not null) + { + ((MauiDrawable)_drawableCanvas.Value.Drawable).Clip = Clip; + UpdateDrawableCanvas(false); + } + + if (_clipperView.IsValueCreated || Clip is not null) + _clipperView.Value.Invalidate(); + } + + void UpdateDrawableCanvas(Paint? paint) + { + if (_drawableCanvas.IsValueCreated || paint is not null) + { + ((MauiDrawable)_drawableCanvas.Value.Drawable).Background = paint; + _drawableCanvas.Value.Invalidate(); + } + } + + void UpdateDrawableCanvas(IShape? shape) + { + if (_drawableCanvas.IsValueCreated || shape is not null) + { + ((MauiDrawable)_drawableCanvas.Value.Drawable).Shape = shape; + _drawableCanvas.Value.Invalidate(); + } + } + + void UpdateDrawableCanvas(bool isShadowUpdated) + { + if (isShadowUpdated) + { + UpdateDrawableCanvasGeometry(); + } + _drawableCanvas.Value.Invalidate(); + } + + void OnClipPaint(object? sender, DrawClipEventArgs e) + { + var canvas = e.Canvas; + var width = e.DirtyRect.Width; + var height = e.DirtyRect.Height; + + canvas.FillColor = Colors.Transparent; + canvas.FillRectangle(e.DirtyRect); + + canvas.FillColor = Colors.White; + var clipPath = Clip?.PathForBounds(new Rect(0, 0, width, height)) ?? null; + if (clipPath == null) + { + return; + } + canvas.FillPath(clipPath); + Content?.SetClipperCanvas(_clipperView.Value); + if (_drawableCanvas.IsValueCreated) + { + _drawableCanvas.Value.SetClipperCanvas(_clipperView.Value); + } + } + + void OnLayout(object? sender, LayoutEventArgs e) + { + if (Content != null) + { + Content.Geometry = Geometry; + } + + if (_drawableCanvas.IsValueCreated) + { + UpdateDrawableCanvas(true); + } + + if (_clipperView.IsValueCreated) + { + _clipperView.Value.Geometry = Geometry; + _clipperView.Value.Invalidate(); + if (Shadow != null) + { + _drawableCanvas.Value.SetClip(null); + } + } + } + + public EvasObject? Content + { + get => _content; + set + { + if (_content != value) + { + if (_content != null) + { + Children.Remove(_content); + _content = null; + } + _content = value; + if (_content != null) + { + Children.Add(_content); + _content.RaiseTop(); + } + } + } + } + + void UpdateDrawableCanvasGeometry() + { + if (_drawableCanvas.IsValueCreated) + { + var shadowMargin = GetShadowMargin(Shadow); + _drawableCanvas.Value.UpdateBounds(Geometry.ToDP().ExpandTo(shadowMargin).ToPixel()); + ((MauiDrawable)_drawableCanvas.Value.Drawable).ShadowThickness = shadowMargin; + } + } + + Thickness GetShadowMargin(IShadow? shadow) + { + double left = 0; + double top = 0; + double right = 0; + double bottom = 0; + + var offsetX = shadow == null ? 0 : shadow.Offset.X; + var offsetY = shadow == null ? 0 : shadow.Offset.Y; + var blurRadius = shadow == null ? 0 : ((double)shadow.Radius); + var spreadSize = blurRadius * 3; + var spreadLeft = offsetX - spreadSize; + var spreadRight = offsetX + spreadSize; + var spreadTop = offsetY - spreadSize; + var spreadBottom = offsetY + spreadSize; + if (left > spreadLeft) + left = spreadLeft; + if (top > spreadTop) + top = spreadTop; + if (right < spreadRight) + right = spreadRight; + if (bottom < spreadBottom) + bottom = spreadBottom; + + return new Thickness(Math.Abs(left), Math.Abs(top), Math.Abs(right), Math.Abs(bottom)); + } + } + + public class DrawClipEventArgs : EventArgs + { + public DrawClipEventArgs(ICanvas canvas, RectF dirtyRect) + { + Canvas = canvas; + DirtyRect = dirtyRect; + } + + public ICanvas Canvas { get; set; } + + public RectF DirtyRect { get; set; } + } + + public class SKClipperView : SKCanvasView + { + 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() + { + ClippingRequired = true; + 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 RectF(0, 0, width, height))); + _scalingCanvas.RestoreState(); + } + } + + public static class ClipperExtension + { + 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); + } +} diff --git a/src/Core/src/Platform/Tizen/WrapperViewDrawables.cs b/src/Core/src/Platform/Tizen/WrapperViewDrawables.cs new file mode 100644 index 0000000000..5a5e19200c --- /dev/null +++ b/src/Core/src/Platform/Tizen/WrapperViewDrawables.cs @@ -0,0 +1,65 @@ +using System; +using Microsoft.Maui.Graphics; + +namespace Microsoft.Maui.Platform +{ + public class WrapperViewDrawables : IWrapperViewDrawables + { + public event EventHandler? Invalidated; + + IDrawable? _shadowDrawable; + IDrawable? _backgroundDrawable; + IDrawable? _borderDrawable; + + public IDrawable? ShadowDrawable + { + get + { + return _shadowDrawable; + } + set + { + _shadowDrawable = value; + SendInvalidated(); + } + } + + public IDrawable? BackgroundDrawable + { + get + { + return _backgroundDrawable; + } + set + { + _backgroundDrawable = value; + SendInvalidated(); + } + } + + public IDrawable? BorderDrawable + { + get + { + return _borderDrawable; + } + set + { + _borderDrawable = value; + SendInvalidated(); + } + } + + public void Draw(ICanvas canvas, RectF dirtyRect) + { + _shadowDrawable?.Draw(canvas, dirtyRect); + _backgroundDrawable?.Draw(canvas, dirtyRect); + _borderDrawable?.Draw(canvas, dirtyRect); + } + + public void SendInvalidated() + { + Invalidated?.Invoke(this, EventArgs.Empty); + } + } +} diff --git a/src/Core/src/Platform/ViewExtensions.cs b/src/Core/src/Platform/ViewExtensions.cs index b78a073cad..53408473dd 100644 --- a/src/Core/src/Platform/ViewExtensions.cs +++ b/src/Core/src/Platform/ViewExtensions.cs @@ -17,6 +17,9 @@ using ParentView = Android.Views.IViewParent; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; using ParentView = Microsoft.UI.Xaml.DependencyObject; +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +using ParentView = ElmSharp.EvasObject; #else using PlatformView = System.Object; using ParentView = System.Object; diff --git a/src/Core/src/Properties/AssemblyInfo.cs b/src/Core/src/Properties/AssemblyInfo.cs index 7fb9f923b2..26da9521f6 100644 --- a/src/Core/src/Properties/AssemblyInfo.cs +++ b/src/Core/src/Properties/AssemblyInfo.cs @@ -7,8 +7,10 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Maps.Android")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.iOS")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Windows")] +[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.Tizen")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.ControlGallery")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.ControlGallery.Android")] +[assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Compatibility.ControlGallery.Tizen")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Xaml")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.Xaml.UnitTests")] [assembly: InternalsVisibleTo("Microsoft.Maui.Controls.HotReload.Forms")] diff --git a/src/Core/src/SemanticExtensions.cs b/src/Core/src/SemanticExtensions.cs index 311f83a05f..e66534e5b5 100644 --- a/src/Core/src/SemanticExtensions.cs +++ b/src/Core/src/SemanticExtensions.cs @@ -9,6 +9,10 @@ using Android.Views.Accessibility; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; +#elif TIZEN +using ElmSharp; +using ElmSharp.Accessible; +using PlatformView = ElmSharp.EvasObject; #elif NETSTANDARD using PlatformView = System.Object; #endif @@ -26,7 +30,9 @@ namespace Microsoft.Maui platformView.SendAccessibilityEvent(EventTypes.ViewHoverEnter); #elif __IOS__ || MACCATALYST UIAccessibility.PostNotification(UIAccessibilityPostNotification.LayoutChanged, platformView); +#elif TIZEN + (platformView as IAccessibleObject)?.Highlight(); #endif } } -} \ No newline at end of file +} diff --git a/src/Core/src/ViewExtensions.cs b/src/Core/src/ViewExtensions.cs index 8655de37b8..8e40698967 100644 --- a/src/Core/src/ViewExtensions.cs +++ b/src/Core/src/ViewExtensions.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Microsoft.Maui.Media; using System.IO; -#if NETSTANDARD || (NET6_0 && !IOS && !ANDROID) +#if NETSTANDARD || (NET6_0 && !IOS && !ANDROID && !TIZEN) using IPlatformViewHandler = Microsoft.Maui.IViewHandler; #endif #if IOS || MACCATALYST @@ -14,6 +14,9 @@ using ParentView = Android.Views.IViewParent; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; using ParentView = Microsoft.UI.Xaml.DependencyObject; +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; +using ParentView = ElmSharp.EvasObject; #else using PlatformView = System.Object; using ParentView = System.Object; diff --git a/src/Core/src/VisualDiagnostics/VisualDiagnosticsOverlay.Tizen.cs b/src/Core/src/VisualDiagnostics/VisualDiagnosticsOverlay.Tizen.cs new file mode 100644 index 0000000000..47afc488be --- /dev/null +++ b/src/Core/src/VisualDiagnostics/VisualDiagnosticsOverlay.Tizen.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using ElmSharp; + +namespace Microsoft.Maui +{ + /// + /// Visual Diagnostics Overlay. + /// + public partial class VisualDiagnosticsOverlay + { + readonly Dictionary _scrollViews = new(); + + public void AddScrollableElementHandler(IScrollView scrollBar) + { + var nativeScroll = scrollBar.ToPlatform(); + if (nativeScroll != null) + { + _scrollViews.Add(scrollBar, nativeScroll); + if (nativeScroll is Scroller scroller) + { + scroller.Scrolled += OnScrolled; + } + } + } + + public override void HandleUIChange() + { + base.HandleUIChange(); + + if (WindowElements.Count > 0) + RemoveAdorners(); + + Invalidate(); + } + + /// + public void RemoveScrollableElementHandler() + { + foreach (var scroll in _scrollViews.Values) + { + if (scroll is Scroller scroller) + { + scroller.Scrolled -= OnScrolled; + } + } + _scrollViews.Clear(); + } + + void OnScrolled(object? sender, EventArgs e) + { + Invalidate(); + } + } +} \ No newline at end of file diff --git a/src/Core/src/WindowExtensions.cs b/src/Core/src/WindowExtensions.cs index 5502c210e4..82d6300d79 100644 --- a/src/Core/src/WindowExtensions.cs +++ b/src/Core/src/WindowExtensions.cs @@ -7,6 +7,8 @@ using PlatformView = UIKit.UIWindow; using PlatformView = Android.App.Activity; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.Window; +#elif TIZEN +using PlatformView = ElmSharp.Window; #endif namespace Microsoft.Maui diff --git a/src/Core/src/WindowOverlay/WindowOverlay.Tizen.cs b/src/Core/src/WindowOverlay/WindowOverlay.Tizen.cs new file mode 100644 index 0000000000..e22b038c00 --- /dev/null +++ b/src/Core/src/WindowOverlay/WindowOverlay.Tizen.cs @@ -0,0 +1,77 @@ +using ElmSharp; +using Microsoft.Maui.Graphics.Skia.Views; +using Point = Microsoft.Maui.Graphics.Point; + +namespace Microsoft.Maui +{ + public partial class WindowOverlay + { + SkiaGraphicsView? _graphicsView; + GestureLayer? _touchLayer; + + public virtual bool Initialize() + { + if (IsPlatformViewInitialized) + return true; + + if (Window == null) + return false; + + var platformWindow = Window.Content?.ToPlatform() as Window; + if (platformWindow == null) + return false; + + var handler = Window.Handler as WindowHandler; + if (handler?.MauiContext == null) + return false; + + _graphicsView = new SkiaGraphicsView(platformWindow); + _graphicsView.Drawable = this; + _graphicsView.RepeatEvents = !DisableUITouchEventPassthrough; + + _touchLayer = new GestureLayer(platformWindow); + _touchLayer.Attach(_graphicsView); + _touchLayer.SetTapCallback(GestureLayer.GestureType.Tap, GestureLayer.GestureState.Start, (data) => + { + var x = _touchLayer.EvasCanvas.Pointer.X; + var y = _touchLayer.EvasCanvas.Pointer.Y; + OnTappedInternal(new Point(DPExtensions.ConvertToScaledDP(x), DPExtensions.ConvertToScaledDP(y))); + }); + + platformWindow.SetOverlay(_graphicsView); + IsPlatformViewInitialized = true; + return IsPlatformViewInitialized; + } + + public void Invalidate() + { + _graphicsView?.Invalidate(); + } + + void DeinitializePlatformDependencies() + { + if (Window == null) + return; + + var platformWindow = Window?.Content?.ToPlatform(); + if (platformWindow == null) + return; + + var handler = Window?.Handler as WindowHandler; + if (handler?.MauiContext == null) + return; + + _graphicsView?.Unrealize(); + _graphicsView = null; + IsPlatformViewInitialized = false; + } + + partial void OnDisableUITouchEventPassthroughSet() + { + if (_graphicsView != null) + { + _graphicsView.RepeatEvents = !DisableUITouchEventPassthrough; + } + } + } +} \ No newline at end of file diff --git a/src/Core/src/WindowOverlay/WindowOverlay.cs b/src/Core/src/WindowOverlay/WindowOverlay.cs index 6ace5c31ad..03d6524a19 100644 --- a/src/Core/src/WindowOverlay/WindowOverlay.cs +++ b/src/Core/src/WindowOverlay/WindowOverlay.cs @@ -9,6 +9,8 @@ using PlatformView = UIKit.UIView; using PlatformView = Android.Views.View; #elif WINDOWS using PlatformView = Microsoft.UI.Xaml.FrameworkElement; +#elif TIZEN +using PlatformView = ElmSharp.EvasObject; #elif NETSTANDARD using PlatformView = System.Object; #endif diff --git a/src/DotNet/Dependencies/Workloads.csproj b/src/DotNet/Dependencies/Workloads.csproj index 310f70e787..5d1e5e0c78 100644 --- a/src/DotNet/Dependencies/Workloads.csproj +++ b/src/DotNet/Dependencies/Workloads.csproj @@ -10,5 +10,6 @@ + \ No newline at end of file diff --git a/src/DotNet/DotNet.csproj b/src/DotNet/DotNet.csproj index b496dad564..2ccc823eeb 100644 --- a/src/DotNet/DotNet.csproj +++ b/src/DotNet/DotNet.csproj @@ -75,7 +75,7 @@ - + @@ -118,6 +118,7 @@ <_WorkloadIds Include="macos" /> <_WorkloadIds Include="ios" /> <_WorkloadIds Include="tvos" /> + <_WorkloadIds Include="tizen" /> <_WorkloadFiles Include="$(_WorkloadManifestDir)microsoft.net.*/*/data/WorkloadManifest.*" /> + <_WorkloadFiles Include="$(_WorkloadManifestDir)samsung.net.sdk.*/*/data/WorkloadManifest.*" /> 1 + + + + diff --git a/src/Essentials/samples/Samples/Platforms/Tizen/CustomViewCellRenderer.cs b/src/Essentials/samples/Samples/Platforms/Tizen/CustomViewCellRenderer.cs deleted file mode 100644 index ddca32c29d..0000000000 --- a/src/Essentials/samples/Samples/Platforms/Tizen/CustomViewCellRenderer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using ElmSharp; -using Microsoft.Maui; -using Microsoft.Maui.Controls; -using Samples.Tizen; -using Xamarin.Forms.Platform.Tizen; - -[assembly: ExportCell(typeof(ViewCell), typeof(CustomViewCellRenderer))] - -namespace Samples.Tizen -{ - public sealed class CustomViewCellRenderer : ViewCellRenderer - { - protected override EvasObject OnGetContent(Cell cell, string part) - { - var view = base.OnGetContent(cell, part); - view.PropagateEvents = true; - return view; - } - } -} diff --git a/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs b/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs index cc8575ab4c..4602bc64c8 100644 --- a/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs +++ b/src/Essentials/samples/Samples/Platforms/Tizen/Program.cs @@ -1,28 +1,15 @@ using Microsoft.Maui; -using Microsoft.Maui.Controls; -using Tizen.NET.MaterialComponents; -using Xamarin.Forms.Platform.Tizen; +using Microsoft.Maui.Hosting; namespace Samples.Tizen { - class Program : FormsApplication + class Program : MauiApplication { - static App formsApp; - - protected override void OnCreate() - { - base.OnCreate(); - - MaterialComponents.Init(DirectoryInfo.Resource); - Microsoft.Maui.Essentials.Platform.Init(MainWindow); - LoadApplication(formsApp ??= new App()); - } + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); static void Main(string[] args) { var app = new Program(); - Forms.Init(app); - Microsoft.Maui.Essentials.Platform.MapServiceToken = "MAP_SERVICE_KEY"; app.Run(args); } } diff --git a/src/Essentials/samples/Samples/Platforms/Tizen/tizen-manifest.xml b/src/Essentials/samples/Samples/Platforms/Tizen/tizen-manifest.xml index 934859bc5f..c84a6dcf56 100644 --- a/src/Essentials/samples/Samples/Platforms/Tizen/tizen-manifest.xml +++ b/src/Essentials/samples/Samples/Platforms/Tizen/tizen-manifest.xml @@ -1,7 +1,7 @@  - + - + Samples.Tizen.png diff --git a/src/Essentials/samples/Samples/Startup.cs b/src/Essentials/samples/Samples/Startup.cs index 995d029691..b85505ad73 100644 --- a/src/Essentials/samples/Samples/Startup.cs +++ b/src/Essentials/samples/Samples/Startup.cs @@ -1,4 +1,7 @@ -using Microsoft.Maui; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Maui; +using Microsoft.Maui.Controls.Compatibility; +using Microsoft.Maui.Controls.Compatibility.Hosting; using Microsoft.Maui.Controls.Hosting; using Microsoft.Maui.Hosting; using Microsoft.Maui.LifecycleEvents; @@ -13,6 +16,9 @@ namespace Samples builder .UseMauiApp() +#if TIZEN + .UseMauiCompatibility() +#endif .ConfigureEssentials(essentials => { essentials.UseVersionTracking(); diff --git a/src/Essentials/samples/Samples/View/HomePage.xaml b/src/Essentials/samples/Samples/View/HomePage.xaml index 31a76b69b1..1e6c1097b8 100644 --- a/src/Essentials/samples/Samples/View/HomePage.xaml +++ b/src/Essentials/samples/Samples/View/HomePage.xaml @@ -50,4 +50,4 @@ - \ No newline at end of file + diff --git a/src/Essentials/src/Accelerometer/Accelerometer.tizen.cs b/src/Essentials/src/Accelerometer/Accelerometer.tizen.cs index d0054512a9..7ec85b8498 100644 --- a/src/Essentials/src/Accelerometer/Accelerometer.tizen.cs +++ b/src/Essentials/src/Accelerometer/Accelerometer.tizen.cs @@ -1,3 +1,4 @@ +using Microsoft.Maui.ApplicationModel; using Tizen.Sensor; using TizenAccelerometer = Tizen.Sensor.Accelerometer; @@ -6,9 +7,9 @@ namespace Microsoft.Maui.Devices.Sensors partial class AccelerometerImplementation { internal static TizenAccelerometer DefaultSensor => - (TizenAccelerometer)Platform.GetDefaultSensor(SensorType.Accelerometer); + (TizenAccelerometer)PlatformUtils.GetDefaultSensor(SensorType.Accelerometer); - internal static bool IsSupported => + public bool IsSupported => TizenAccelerometer.IsSupported; void PlatformStart(SensorSpeed sensorSpeed) diff --git a/src/Essentials/src/AppInfo/AppInfo.tizen.cs b/src/Essentials/src/AppInfo/AppInfo.tizen.cs index c0d8f05952..321e0ed0cc 100644 --- a/src/Essentials/src/AppInfo/AppInfo.tizen.cs +++ b/src/Essentials/src/AppInfo/AppInfo.tizen.cs @@ -3,7 +3,7 @@ using Tizen.Applications; namespace Microsoft.Maui.ApplicationModel { - class AppInfoImplementation + class AppInfoImplementation : IAppInfo { public string PackageName => Application.Current.ApplicationInfo.PackageId; @@ -19,7 +19,7 @@ namespace Microsoft.Maui.ApplicationModel public string BuildString => Version.Build.ToString(CultureInfo.InvariantCulture); - public void PlatformShowSettingsUI() + public void ShowSettingsUI() { Permissions.EnsureDeclared(); AppControl.SendLaunchRequest(new AppControl() { Operation = AppControlOperations.Setting }); @@ -29,5 +29,8 @@ namespace Microsoft.Maui.ApplicationModel => AppTheme.Unspecified; public AppPackagingModel PackagingModel => AppPackagingModel.Packaged; + + public LayoutDirection RequestedLayoutDirection + => LayoutDirection.LeftToRight; } } diff --git a/src/Essentials/src/Barometer/Barometer.tizen.cs b/src/Essentials/src/Barometer/Barometer.tizen.cs index fd4f95478a..3add4eb3c4 100644 --- a/src/Essentials/src/Barometer/Barometer.tizen.cs +++ b/src/Essentials/src/Barometer/Barometer.tizen.cs @@ -1,16 +1,17 @@ using System; +using Microsoft.Maui.ApplicationModel; using Tizen.Sensor; using TizenBarometerSensor = Tizen.Sensor.PressureSensor; namespace Microsoft.Maui.Devices.Sensors { - class BarometerImplementation : IBarometer + partial class BarometerImplementation : IBarometer { public bool IsSupported => TizenBarometerSensor.IsSupported; TizenBarometerSensor DefaultSensor - => (TizenBarometerSensor)Platform.GetDefaultSensor(SensorType.Barometer); + => (TizenBarometerSensor)PlatformUtils.GetDefaultSensor(SensorType.Barometer); TizenBarometerSensor sensor = null; @@ -23,7 +24,7 @@ namespace Microsoft.Maui.Devices.Sensors } void DataUpdated(object sender, PressureSensorDataUpdatedEventArgs e) - => RaiseDataChanged(new BarometerData(e.Pressure)); + => RaiseReadingChanged(new BarometerData(e.Pressure)); void PlatformStop() { diff --git a/src/Essentials/src/Battery/Battery.tizen.cs b/src/Essentials/src/Battery/Battery.tizen.cs index 8631755f54..6aee8be5fa 100755 --- a/src/Essentials/src/Battery/Battery.tizen.cs +++ b/src/Essentials/src/Battery/Battery.tizen.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Maui.ApplicationModel; using TizenBattery = Tizen.System.Battery; namespace Microsoft.Maui.Devices diff --git a/src/Essentials/src/Browser/Browser.tizen.cs b/src/Essentials/src/Browser/Browser.tizen.cs index ae06dc054b..df8d64b450 100755 --- a/src/Essentials/src/Browser/Browser.tizen.cs +++ b/src/Essentials/src/Browser/Browser.tizen.cs @@ -8,7 +8,7 @@ namespace Microsoft.Maui.ApplicationModel { partial class BrowserImplementation : IBrowser { - public Task PlatformOpenAsync(Uri uri, BrowserLaunchOptions launchMode) + public Task OpenAsync(Uri uri, BrowserLaunchOptions launchMode) { if (uri == null) throw new ArgumentNullException(nameof(uri)); diff --git a/src/Essentials/src/Compass/Compass.tizen.cs b/src/Essentials/src/Compass/Compass.tizen.cs index 97f081d4b1..dd38854755 100644 --- a/src/Essentials/src/Compass/Compass.tizen.cs +++ b/src/Essentials/src/Compass/Compass.tizen.cs @@ -1,3 +1,4 @@ +using Microsoft.Maui.ApplicationModel; using Tizen.Sensor; using TizenCompass = Tizen.Sensor.OrientationSensor; @@ -6,7 +7,7 @@ namespace Microsoft.Maui.Devices.Sensors partial class CompassImplementation : ICompass { static TizenCompass DefaultSensor => - (TizenCompass)Platform.GetDefaultSensor(SensorType.Compass); + (TizenCompass)PlatformUtils.GetDefaultSensor(SensorType.Compass); bool PlatformIsSupported => TizenCompass.IsSupported; diff --git a/src/Essentials/src/Connectivity/Connectivity.tizen.cs b/src/Essentials/src/Connectivity/Connectivity.tizen.cs index 259f6faa80..3994748400 100644 --- a/src/Essentials/src/Connectivity/Connectivity.tizen.cs +++ b/src/Essentials/src/Connectivity/Connectivity.tizen.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.Maui.ApplicationModel; using Tizen.Network.Connection; namespace Microsoft.Maui.Networking @@ -37,7 +38,7 @@ namespace Microsoft.Maui.Networking break; } } - Connectivity.OnConnectivityChanged(); + OnConnectivityChanged(); } public NetworkAccess NetworkAccess diff --git a/src/Essentials/src/Contacts/Contacts.tizen.cs b/src/Essentials/src/Contacts/Contacts.tizen.cs index 699c28ee8d..bf33e366ca 100644 --- a/src/Essentials/src/Contacts/Contacts.tizen.cs +++ b/src/Essentials/src/Contacts/Contacts.tizen.cs @@ -11,11 +11,11 @@ using TizenNumber = Tizen.Pims.Contacts.ContactsViews.Number; namespace Microsoft.Maui.ApplicationModel.Communication { - static partial class Contacts + class ContactsImplementation:IContacts { static ContactsManager manager = new ContactsManager(); - static async Task PlatformPickContactAsync() + public async Task PickContactAsync() { Permissions.EnsureDeclared(); Permissions.EnsureDeclared(); @@ -50,7 +50,7 @@ namespace Microsoft.Maui.ApplicationModel.Communication return await tcs.Task; } - static Task> PlatformGetAllAsync(CancellationToken cancellationToken) + public Task> GetAllAsync(CancellationToken cancellationToken) { var contactsList = manager.Database.GetAll(TizenContact.Uri, 0, 0); diff --git a/src/Essentials/src/DeviceDisplay/DeviceDisplay.shared.cs b/src/Essentials/src/DeviceDisplay/DeviceDisplay.shared.cs index 30b104457c..ffaa16bbb4 100644 --- a/src/Essentials/src/DeviceDisplay/DeviceDisplay.shared.cs +++ b/src/Essentials/src/DeviceDisplay/DeviceDisplay.shared.cs @@ -45,7 +45,7 @@ namespace Microsoft.Maui.Devices #if WINDOWS internal const float BaseLogicalDpi = 96.0f; -#elif ANDROID +#elif ANDROID || TIZEN internal const float BaseLogicalDpi = 160.0f; #endif diff --git a/src/Essentials/src/DeviceDisplay/DeviceDisplay.tizen.cs b/src/Essentials/src/DeviceDisplay/DeviceDisplay.tizen.cs index 4dec01f1d5..cda04e217a 100644 --- a/src/Essentials/src/DeviceDisplay/DeviceDisplay.tizen.cs +++ b/src/Essentials/src/DeviceDisplay/DeviceDisplay.tizen.cs @@ -1,6 +1,7 @@ -#nullable enable using System; using System.Runtime.InteropServices; +using Microsoft.Maui.ApplicationModel; +using Tizen.Applications; namespace Microsoft.Maui.Devices { @@ -12,6 +13,13 @@ namespace Microsoft.Maui.Devices [DllImport("libcapi-system-device.so.0", EntryPoint = "device_power_release_lock")] static extern void ReleaseKeepScreenOn(int type = 1); + static CoreUIApplication CoreUIApplication => Application.Current as CoreUIApplication; + static int displayWidth = PlatformUtils.GetFeatureInfo("screen.width"); + static int displayHeight = PlatformUtils.GetFeatureInfo("screen.height"); + static int displayDpi = DeviceInfo.Idiom == DeviceIdiom.TV ? 72 : PlatformUtils.GetFeatureInfo("screen.dpi"); + DisplayOrientation displayOrientation; + DisplayRotation displayRotation = DisplayRotation.Rotation0; + bool keepScreenOn = false; protected override bool GetKeepScreenOn() => keepScreenOn; @@ -27,50 +35,69 @@ namespace Microsoft.Maui.Devices protected override DisplayInfo GetMainDisplayInfo() { - var display = Platform.MainWindow; return new DisplayInfo( - width: display.ScreenSize.Width, - height: display.ScreenSize.Height, - density: display.ScreenDpi.X / (DeviceInfo.Idiom == DeviceIdiom.TV ? 72.0 : 160.0), - orientation: GetOrientation(), - rotation: GetRotation()); - } - - static DisplayOrientation GetOrientation() - { - return Platform.MainWindow.Rotation switch - { - 0 => DisplayOrientation.Portrait, - 90 => DisplayOrientation.Landscape, - 180 => DisplayOrientation.Portrait, - 270 => DisplayOrientation.Landscape, - _ => DisplayOrientation.Unknown, - }; - } - - static DisplayRotation GetRotation() - { - return Platform.MainWindow.Rotation switch - { - 0 => DisplayRotation.Rotation0, - 90 => DisplayRotation.Rotation90, - 180 => DisplayRotation.Rotation180, - 270 => DisplayRotation.Rotation270, - _ => DisplayRotation.Unknown, - }; + width: displayWidth, + height: displayHeight, + density: displayDpi / DeviceDisplay.BaseLogicalDpi, + orientation: GetNaturalDisplayOrientation(), + rotation: displayRotation + ); } protected override void StartScreenMetricsListeners() { - Platform.MainWindow.RotationChanged += OnRotationChanged; + if (CoreUIApplication != null) + { + CoreUIApplication.DeviceOrientationChanged += OnRotationChanged; + } } protected override void StopScreenMetricsListeners() { - Platform.MainWindow.RotationChanged -= OnRotationChanged; + if (CoreUIApplication != null) + { + CoreUIApplication.DeviceOrientationChanged -= OnRotationChanged; + } } - void OnRotationChanged(object s, EventArgs e) => + DisplayOrientation GetNaturalDisplayOrientation() + { + if (displayHeight >= displayWidth) + { + return DisplayOrientation.Portrait; + } + else + { + return DisplayOrientation.Landscape; + } + } + + void OnRotationChanged(object s, DeviceOrientationEventArgs e) + { + switch (e.DeviceOrientation) + { + case DeviceOrientation.Orientation_0: + displayRotation = DisplayRotation.Rotation0; + displayOrientation = GetNaturalDisplayOrientation(); + break; + case DeviceOrientation.Orientation_90: + displayRotation = DisplayRotation.Rotation90; + displayOrientation = GetNaturalDisplayOrientation() == DisplayOrientation.Portrait ? DisplayOrientation.Landscape : DisplayOrientation.Portrait; + break; + case DeviceOrientation.Orientation_180: + displayRotation = DisplayRotation.Rotation180; + displayOrientation = GetNaturalDisplayOrientation(); + break; + case DeviceOrientation.Orientation_270: + displayRotation = DisplayRotation.Rotation270; + displayOrientation = GetNaturalDisplayOrientation() == DisplayOrientation.Portrait ? DisplayOrientation.Landscape : DisplayOrientation.Portrait; + break; + default: + displayRotation = DisplayRotation.Unknown; + displayOrientation = DisplayOrientation.Unknown; + break; + } OnMainDisplayInfoChanged(); + } } } diff --git a/src/Essentials/src/DeviceInfo/DeviceInfo.tizen.cs b/src/Essentials/src/DeviceInfo/DeviceInfo.tizen.cs index 79e9e8eb8d..d96c927e6d 100644 --- a/src/Essentials/src/DeviceInfo/DeviceInfo.tizen.cs +++ b/src/Essentials/src/DeviceInfo/DeviceInfo.tizen.cs @@ -1,29 +1,27 @@ +using System; +using Microsoft.Maui.ApplicationModel; + namespace Microsoft.Maui.Devices { class DeviceInfoImplementation : IDeviceInfo { - public string Model - => Platform.GetSystemInfo("model_name"); + public string Model => PlatformUtils.GetSystemInfo("model_name"); - public string Manufacturer - => Platform.GetSystemInfo("manufacturer"); + public string Manufacturer => PlatformUtils.GetSystemInfo("manufacturer"); - public string Name - => Platform.GetSystemInfo("device_name"); + public string Name => PlatformUtils.GetSystemInfo("device_name"); - public string VersionString - => Platform.GetFeatureInfo("platform.version"); + public string VersionString => PlatformUtils.GetFeatureInfo("platform.version"); public Version Version => Utils.ParseVersion(VersionString); - public DevicePlatform Platform - => DevicePlatform.Tizen; + public DevicePlatform Platform => DevicePlatform.Tizen; public DeviceIdiom Idiom { get { - var profile = Plat.GetFeatureInfo("profile")?.ToUpperInvariant(); + var profile = PlatformUtils.GetFeatureInfo("profile")?.ToUpperInvariant(); if (profile == null) return DeviceIdiom.Unknown; @@ -43,13 +41,13 @@ namespace Microsoft.Maui.Devices { get { - var arch = Platform.GetFeatureInfo("platform.core.cpu.arch"); - var armv7 = Platform.GetFeatureInfo("platform.core.cpu.arch.armv7"); - var x86 = Platform.GetFeatureInfo("platform.core.cpu.arch.x86"); + var arch = PlatformUtils.GetFeatureInfo("platform.core.cpu.arch"); + var armv7 = PlatformUtils.GetFeatureInfo("platform.core.cpu.arch.armv7"); + var x86 = PlatformUtils.GetFeatureInfo("platform.core.cpu.arch.x86"); - if (arch != null && arch.Equals("armv7") && armv7 && !x86) + if (arch != null && arch.Equals("armv7", StringComparison.Ordinal) && armv7 && !x86) return DeviceType.Physical; - else if (arch != null && arch.Equals("x86") && !armv7 && x86) + else if (arch != null && arch.Equals("x86", StringComparison.Ordinal) && !armv7 && x86) return DeviceType.Virtual; else return DeviceType.Unknown; diff --git a/src/Essentials/src/Email/Email.tizen.cs b/src/Essentials/src/Email/Email.tizen.cs index a28815452f..0b0bb9763d 100644 --- a/src/Essentials/src/Email/Email.tizen.cs +++ b/src/Essentials/src/Email/Email.tizen.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Threading.Tasks; +using Microsoft.Maui.ApplicationModel; using Tizen.Applications; namespace Microsoft.Maui.ApplicationModel.Communication @@ -7,7 +8,7 @@ namespace Microsoft.Maui.ApplicationModel.Communication partial class EmailImplementation : IEmail { public bool IsComposeSupported - => Platform.GetFeatureInfo("email"); + => PlatformUtils.GetFeatureInfo("email"); Task PlatformComposeAsync(EmailMessage message) { @@ -19,20 +20,32 @@ namespace Microsoft.Maui.ApplicationModel.Communication Uri = "mailto:", }; - if (message.Bcc.Count > 0) + if (message.Bcc?.Count > 0) appControl.ExtraData.Add(AppControlData.Bcc, message.Bcc); if (!string.IsNullOrEmpty(message.Body)) appControl.ExtraData.Add(AppControlData.Text, message.Body); - if (message.Cc.Count > 0) + if (message.Cc?.Count > 0) appControl.ExtraData.Add(AppControlData.Cc, message.Cc); if (!string.IsNullOrEmpty(message.Subject)) appControl.ExtraData.Add(AppControlData.Subject, message.Subject); - if (message.To.Count > 0) + if (message.To?.Count > 0) appControl.ExtraData.Add(AppControlData.To, message.To); AppControl.SendLaunchRequest(appControl); return Task.CompletedTask; } + + public Task ComposeAsync(string subject, string body, params string[] to) + => ComposeAsync( + new EmailMessage + { + Subject = subject, + Body = body, + To = to.ToList() + }); + + public Task ComposeAsync() + => ComposeAsync(null); } } diff --git a/src/Essentials/src/Essentials.csproj b/src/Essentials/src/Essentials.csproj index 3855a2ceef..95f21dc367 100644 --- a/src/Essentials/src/Essentials.csproj +++ b/src/Essentials/src/Essentials.csproj @@ -1,4 +1,4 @@ - + netstandard2.1;netstandard2.0;$(_MauiDotNetTfm);$(MauiPlatforms) Microsoft.Maui.Essentials @@ -61,11 +61,10 @@ --> - + + Exe MauiApp._1 true @@ -26,6 +28,7 @@ 21.0 10.0.17763.0 10.0.17763.0 + 6.5 diff --git a/src/Templates/src/templates/maui-blazor/Platforms/Tizen/Main.cs b/src/Templates/src/templates/maui-blazor/Platforms/Tizen/Main.cs new file mode 100644 index 0000000000..98ac2ef82a --- /dev/null +++ b/src/Templates/src/templates/maui-blazor/Platforms/Tizen/Main.cs @@ -0,0 +1,16 @@ +using System; +using Microsoft.Maui; +using Microsoft.Maui.Hosting; + +namespace MauiApp._1; + +class Program : MauiApplication +{ + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } +} diff --git a/src/Templates/src/templates/maui-blazor/Platforms/Tizen/tizen-manifest.xml b/src/Templates/src/templates/maui-blazor/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 0000000000..58f91fae47 --- /dev/null +++ b/src/Templates/src/templates/maui-blazor/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-contentpage-csharp/.template.config/template.json b/src/Templates/src/templates/maui-contentpage-csharp/.template.config/template.json index 34147264cf..0485fe0294 100644 --- a/src/Templates/src/templates/maui-contentpage-csharp/.template.config/template.json +++ b/src/Templates/src/templates/maui-contentpage-csharp/.template.config/template.json @@ -1,7 +1,7 @@ { "$schema": "http://json.schemastore.org/template", "author": "Microsoft", - "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "WinUI", "Xaml", "Code" ], + "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "WinUI", "Tizen", "Xaml", "Code" ], "identity": "Microsoft.Maui.CSharpContentPage", "name": ".NET MAUI ContentPage (C#) (Preview)", "shortName": "maui-page-csharp", diff --git a/src/Templates/src/templates/maui-contentpage-xaml/.template.config/template.json b/src/Templates/src/templates/maui-contentpage-xaml/.template.config/template.json index 24dec31fb1..1948845df2 100644 --- a/src/Templates/src/templates/maui-contentpage-xaml/.template.config/template.json +++ b/src/Templates/src/templates/maui-contentpage-xaml/.template.config/template.json @@ -1,7 +1,7 @@ { "$schema": "http://json.schemastore.org/template", "author": "Microsoft", - "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "WinUI", "Xaml", "Code" ], + "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "WinUI", "Tizen", "Xaml", "Code" ], "identity": "Microsoft.Maui.XamlContentPage", "name": ".NET MAUI ContentPage (XAML) (Preview)", "shortName": "maui-page-xaml", diff --git a/src/Templates/src/templates/maui-contentview-csharp/.template.config/template.json b/src/Templates/src/templates/maui-contentview-csharp/.template.config/template.json index cdc31e23d9..e5182f7059 100644 --- a/src/Templates/src/templates/maui-contentview-csharp/.template.config/template.json +++ b/src/Templates/src/templates/maui-contentview-csharp/.template.config/template.json @@ -1,7 +1,7 @@ { "$schema": "http://json.schemastore.org/template", "author": "Microsoft", - "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "WinUI", "Xaml", "Code" ], + "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "WinUI", "Tizen", "Xaml", "Code" ], "identity": "Microsoft.Maui.CSharpContentView", "name": ".NET MAUI ContentView (C#) (Preview)", "shortName": "maui-view-csharp", diff --git a/src/Templates/src/templates/maui-contentview-xaml/.template.config/template.json b/src/Templates/src/templates/maui-contentview-xaml/.template.config/template.json index eddd0216d0..54cbeff5ec 100644 --- a/src/Templates/src/templates/maui-contentview-xaml/.template.config/template.json +++ b/src/Templates/src/templates/maui-contentview-xaml/.template.config/template.json @@ -1,7 +1,7 @@ { "$schema": "http://json.schemastore.org/template", "author": "Microsoft", - "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "WinUI", "Xaml", "Code" ], + "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "WinUI", "Tizen", "Xaml", "Code" ], "identity": "Microsoft.Maui.XamlContentView", "name": ".NET MAUI ContentView (XAML) (Preview)", "shortName": "maui-view-xaml", diff --git a/src/Templates/src/templates/maui-lib/.template.config/template.in.json b/src/Templates/src/templates/maui-lib/.template.config/template.in.json index 927891f2ab..3490542ff6 100644 --- a/src/Templates/src/templates/maui-lib/.template.config/template.in.json +++ b/src/Templates/src/templates/maui-lib/.template.config/template.in.json @@ -1,7 +1,7 @@ { "$schema": "http://json.schemastore.org/template", "author": "Microsoft", - "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "Windows" ], + "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "Windows", "Tizen" ], "identity": "Microsoft.Maui.MauiLib", "groupIdentity": "Microsoft.Maui.Library", "name": ".NET MAUI Class Library (Preview)", diff --git a/src/Templates/src/templates/maui-lib/MauiLib1.csproj b/src/Templates/src/templates/maui-lib/MauiLib1.csproj index dfeee41120..a4739cbbd6 100644 --- a/src/Templates/src/templates/maui-lib/MauiLib1.csproj +++ b/src/Templates/src/templates/maui-lib/MauiLib1.csproj @@ -3,6 +3,8 @@ DOTNET_TFM;DOTNET_TFM-android;DOTNET_TFM-ios;DOTNET_TFM-maccatalyst $(TargetFrameworks);DOTNET_TFM-windows10.0.19041.0 + + MauiLib1 true true @@ -13,6 +15,7 @@ 21.0 10.0.17763.0 10.0.17763.0 + 6.5 diff --git a/src/Templates/src/templates/maui-lib/Platforms/Tizen/PlatformClass1.cs b/src/Templates/src/templates/maui-lib/Platforms/Tizen/PlatformClass1.cs new file mode 100644 index 0000000000..82cb63571e --- /dev/null +++ b/src/Templates/src/templates/maui-lib/Platforms/Tizen/PlatformClass1.cs @@ -0,0 +1,9 @@ +using System; + +namespace MauiLib1 +{ + // All the code in this file is only included on Tizen. + public class PlatformClass1 + { + } +} \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.cs.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.cs.json index 58202df9ae..63d3e7cbf7 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.cs.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.cs.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": "Aplikace .NET MAUI (Preview)", - "description": "Projekt pro vytvoření .NET MAUI aplikace pro iOS, Android, Mac Catalyst a WinUI", + "description": "Projekt pro vytvoření .NET MAUI aplikace pro iOS, Android, Mac Catalyst, Tizen a WinUI", "postActions/openInEditor/description": "Otevře soubor MainPage.xaml v editoru.", "symbols/applicationId/description": "Přepíše v projektu $(ApplicationId)." } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.de.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.de.json index 907e2fb5a4..488dd64f67 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.de.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.de.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": ".NET MAUI-App (Vorschau)", - "description": "Ein Projekt zum Erstellen einer .NET MAUI-Anwendung für iOS, Android, Mac Catalyst und WinUI", + "description": "Ein Projekt zum Erstellen einer .NET MAUI-Anwendung für iOS, Android, Mac Catalyst, Tizen und WinUI", "postActions/openInEditor/description": "Öffnet \"MainPage.xaml\" im Editor.", "symbols/applicationId/description": "Überschreibt $(ApplicationId) im Projekt" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.en.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.en.json index a829721cbd..ece9732b6a 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.en.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.en.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": ".NET MAUI App (Preview)", - "description": "A project for creating a .NET MAUI application for iOS, Android, Mac Catalyst, and WinUI", + "description": "A project for creating a .NET MAUI application for iOS, Android, Mac Catalyst, Tizen and WinUI", "postActions/openInEditor/description": "Opens MainPage.xaml in the editor.", "symbols/applicationId/description": "Overrides the $(ApplicationId) in the project" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.es.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.es.json index f21b031826..4dbd42091a 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.es.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.es.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": "Aplicación .NET MAUI (versión preliminar)", - "description": "Un proyecto para crear una aplicación .NET MAUI para iOS, Android, Mac Catalyst y WinUI", + "description": "Un proyecto para crear una aplicación .NET MAUI para iOS, Android, Mac Catalyst, Tizen y WinUI", "postActions/openInEditor/description": "Abre MainPage.xaml en el editor.", "symbols/applicationId/description": "Reemplaza $(ApplicationId) en el proyecto" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.fr.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.fr.json index 4138581b1a..ca7f0e392c 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.fr.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.fr.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": "Application .NET MAUI (préversion)", - "description": "Projet de création d’une application .NET MAUI pour iOS, Android, Mac Catalyst et WinUI", + "description": "Projet de création d’une application .NET MAUI pour iOS, Android, Mac Catalyst, Tizen et WinUI", "postActions/openInEditor/description": "Ouvre MainPage.xaml dans l’éditeur.", "symbols/applicationId/description": "Remplace $(ApplicationId) dans le projet" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.it.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.it.json index c7c7a04794..feb4743fa9 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.it.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.it.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": "App .NET MAUI (Anteprima)", - "description": "Progetto per la creazione di un'applicazione .NET MAUI per iOS, Android, Mac Catalyst e WinUI", + "description": "Progetto per la creazione di un'applicazione .NET MAUI per iOS, Android, Mac Catalyst, Tizen e WinUI", "postActions/openInEditor/description": "Apre MainPage.xaml nell'editor.", "symbols/applicationId/description": "Esegue l'override di $(ApplicationId) nel progetto" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ja.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ja.json index decab63ba1..034e56658c 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ja.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ja.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": ".NET MAUI アプリ (プレビュー)", - "description": "iOS、Android、Mac Catalyst、および WinUI 用の .NET MAUI アプリケーションを作成するためのプロジェクト", + "description": "iOS、Android、Mac Catalyst、Tizen、および WinUI 用の .NET MAUI アプリケーションを作成するためのプロジェクト", "postActions/openInEditor/description": "エディターで MainPage.xaml を開きます。", "symbols/applicationId/description": "プロジェクト内の $(ApplicationId) をオーバーライドします" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.json index a829721cbd..b3db9ef8dc 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": ".NET MAUI App (Preview)", - "description": "A project for creating a .NET MAUI application for iOS, Android, Mac Catalyst, and WinUI", + "description": "A project for creating a .NET MAUI application for iOS, Android, Mac Catalyst, Tizen, and WinUI", "postActions/openInEditor/description": "Opens MainPage.xaml in the editor.", "symbols/applicationId/description": "Overrides the $(ApplicationId) in the project" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ko.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ko.json index aa6e8bcbf4..35d530a6ed 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ko.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ko.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": ".NET MAUI 앱(미리 보기)", - "description": "iOS, Android, Mac Catalyst 및 WinUI용 .NET MAUI 애플리케이션을 만들기 위한 프로젝트", + "description": "iOS, Android, Mac Catalyst, Tizen 및 WinUI용 .NET MAUI 애플리케이션을 만들기 위한 프로젝트", "postActions/openInEditor/description": "편집기에서 MainPage.xaml을 엽니다.", "symbols/applicationId/description": "프로젝트에서 $(ApplicationId) 재정의" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.pl.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.pl.json index 674a4fc8dc..dd7e2c0d8e 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.pl.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.pl.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": "Aplikacja platformy .NET MAUI (wersja zapoznawcza)", - "description": "Projekt służący do tworzenia aplikacji .NET MAUI dla systemów iOS, Android, Mac Catalyst i WinUI", + "description": "Projekt służący do tworzenia aplikacji .NET MAUI dla systemów iOS, Android, Mac Catalyst, Tizen i WinUI", "postActions/openInEditor/description": "Otwiera plik MainPage.xaml w edytorze.", "symbols/applicationId/description": "Zastępuje $(ApplicationId) w projekcie" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.pt-BR.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.pt-BR.json index 610b7cf7fa..ae522526f9 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.pt-BR.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.pt-BR.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": "Aplicativo .NET MAUI (Versão Prévia)", - "description": "Um projeto para a criação de um aplicativo .NET MAUI para iOS, Android, Mac Catalyst e WinUI", + "description": "Um projeto para a criação de um aplicativo .NET MAUI para iOS, Android, Mac Catalyst, Tizen e WinUI", "postActions/openInEditor/description": "Abre MainPage.xaml no editor.", "symbols/applicationId/description": "Substitui $(ApplicationId) no projeto" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ru.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ru.json index 3a80e5fc82..c8faa9320c 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ru.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.ru.json @@ -1,7 +1,7 @@ { "author": "Майкрософт", "name": "Приложение .NET MAUI (предварительная версия)", - "description": "Проект по созданию приложения .NET MAUI для iOS, Android, Mac Catalyst и WinUI", + "description": "Проект по созданию приложения .NET MAUI для iOS, Android, Mac Catalyst, Tizen и WinUI", "postActions/openInEditor/description": "Открывает MainPage.xaml в редакторе.", "symbols/applicationId/description": "Переопределяет $(ApplicationId) в проекте" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.tr.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.tr.json index de728e8d33..92f06027fd 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.tr.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.tr.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": ".NET MAUI Uygulaması (Önizleme)", - "description": "iOS, Android, Mac Catalyst .NET MAUI ve WinUI için yeni bir uygulama oluşturmaya yönelik proje", + "description": "iOS, Android, Mac Catalyst, Tizen .NET MAUI ve WinUI için yeni bir uygulama oluşturmaya yönelik proje", "postActions/openInEditor/description": "Düzenleyicide MainPage.xaml dosyasını açar.", "symbols/applicationId/description": "Projedeki $(ApplicationId) uygulamasın geçersiz kılar" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.zh-Hans.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.zh-Hans.json index 4a3a79b21c..6d0d050e54 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.zh-Hans.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.zh-Hans.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": ".NET MAUI应用(预览)", - "description": "用于创建适用于 iOS、Android、Mac Catalyst 和 WinUI 的 .NET MAUI 应用程序的项目", + "description": "用于创建适用于 iOS、Android、Mac Catalyst、Tizen 和 WinUI 的 .NET MAUI 应用程序的项目", "postActions/openInEditor/description": "在编辑器中打开 MainPage.xaml。", "symbols/applicationId/description": "替代项目中的 $(ApplicationId)" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.zh-Hant.json b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.zh-Hant.json index f79a962155..a6a77a1066 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.zh-Hant.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/localize/templatestrings.zh-Hant.json @@ -1,7 +1,7 @@ { "author": "Microsoft", "name": ".NET MAUI 應用程式 (預覽)", - "description": "此專案可用於建立適用於 iOS、Android、Mac Catalyst 和 WinUI 的 .NET MAUI 應用程式", + "description": "此專案可用於建立適用於 iOS、Android、Mac Catalyst、Tizen 和 WinUI 的 .NET MAUI 應用程式", "postActions/openInEditor/description": "在編輯器中開啟 MainPage.xaml。", "symbols/applicationId/description": "覆寫專案中的 $(ApplicationId)" } \ No newline at end of file diff --git a/src/Templates/src/templates/maui-mobile/.template.config/template.in.json b/src/Templates/src/templates/maui-mobile/.template.config/template.in.json index 62084950aa..ac3fce8e01 100644 --- a/src/Templates/src/templates/maui-mobile/.template.config/template.in.json +++ b/src/Templates/src/templates/maui-mobile/.template.config/template.in.json @@ -1,11 +1,11 @@ { "$schema": "http://json.schemastore.org/template", "author": "Microsoft", - "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "Windows" ], + "classifications": [ "MAUI", "Android", "iOS", "macOS", "Mac Catalyst", "Windows", "Tizen" ], "identity": "Microsoft.Maui.MauiApp", "groupIdentity": "Microsoft.Maui.App", "name": ".NET MAUI App (Preview)", - "description": "A project for creating a .NET MAUI application for iOS, Android, Mac Catalyst, and WinUI", + "description": "A project for creating a .NET MAUI application for iOS, Android, Mac Catalyst, WinUI and Tizen", "shortName": "maui", "tags": { "language": "C#", diff --git a/src/Templates/src/templates/maui-mobile/MauiApp.1.csproj b/src/Templates/src/templates/maui-mobile/MauiApp.1.csproj index 8968d42fea..7f1b8c112a 100644 --- a/src/Templates/src/templates/maui-mobile/MauiApp.1.csproj +++ b/src/Templates/src/templates/maui-mobile/MauiApp.1.csproj @@ -3,6 +3,8 @@ DOTNET_TFM-android;DOTNET_TFM-ios;DOTNET_TFM-maccatalyst $(TargetFrameworks);DOTNET_TFM-windows10.0.19041.0 + + Exe MauiApp._1 true @@ -25,6 +27,7 @@ 21.0 10.0.17763.0 10.0.17763.0 + 6.5 diff --git a/src/Templates/src/templates/maui-mobile/Platforms/Tizen/Main.cs b/src/Templates/src/templates/maui-mobile/Platforms/Tizen/Main.cs new file mode 100644 index 0000000000..98ac2ef82a --- /dev/null +++ b/src/Templates/src/templates/maui-mobile/Platforms/Tizen/Main.cs @@ -0,0 +1,16 @@ +using System; +using Microsoft.Maui; +using Microsoft.Maui.Hosting; + +namespace MauiApp._1; + +class Program : MauiApplication +{ + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } +} diff --git a/src/Templates/src/templates/maui-mobile/Platforms/Tizen/tizen-manifest.xml b/src/Templates/src/templates/maui-mobile/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 0000000000..58f91fae47 --- /dev/null +++ b/src/Templates/src/templates/maui-mobile/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 2f88e55e47..2bdb652b09 100644 --- a/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj +++ b/src/Workload/Microsoft.Maui.Dependencies/Microsoft.Maui.Dependencies.csproj @@ -33,5 +33,9 @@ + + + + diff --git a/src/Workload/Microsoft.Maui.Sdk/Sdk/BundledVersions.in.targets b/src/Workload/Microsoft.Maui.Sdk/Sdk/BundledVersions.in.targets index 492b227b23..d26a80d5b3 100644 --- a/src/Workload/Microsoft.Maui.Sdk/Sdk/BundledVersions.in.targets +++ b/src/Workload/Microsoft.Maui.Sdk/Sdk/BundledVersions.in.targets @@ -14,7 +14,7 @@ - <_MauiRuntimeIdentifiers Include="android;ios;maccatalyst;win" /> + <_MauiRuntimeIdentifiers Include="android;ios;maccatalyst;win;tizen" /> + <_TargetPlatform + Condition=" '$(MauiPlatformName)' == 'tizen' " + Include="net$(_MauiDotNetVersion)-tizen$(TizenTargetFrameworkVersion)" + FullTfm="%(Identity)" + Tfm="net$(_MauiDotNetVersion)-tizen" + Profile="Tizen" + /> - <_Platforms Include="any;android;maccatalyst;ios" /> + <_Platforms Include="any;android;maccatalyst;ios;tizen" /> <_Platforms Include="win" Condition="'$(IncludeWindowsTargetFrameworks)' == 'true'" />