diff --git a/Directory.Build.props b/Directory.Build.props
index d437ceffb..3c381232f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -20,4 +20,7 @@
+
+ true
+
\ No newline at end of file
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index ddfad169d..ca7cc98ad 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -3,7 +3,7 @@ variables:
PreviewNumber: $[counter(variables['CurrentSemanticVersionBase'], 1001)]
CurrentSemanticVersion: '$(CurrentSemanticVersionBase)-preview$(PreviewNumber)'
NugetPackageVersion: '$(CurrentSemanticVersion)'
- TOOLKIT_NET_VERSION: '6.0.300'
+ TOOLKIT_NET_VERSION: '6.0.400'
LATEST_NET_VERSION: '6.0.x'
PathToLibrarySolution: 'src/CommunityToolkit.Maui.sln'
PathToSamplesSolution: 'samples/CommunityToolkit.Maui.Sample.sln'
@@ -15,7 +15,7 @@ variables:
PathToCommunityToolkitSourceGeneratorsCsproj: 'src/CommunityToolkit.Maui.SourceGenerators/CommunityToolkit.Maui.SourceGenerators.csproj'
PathToCommunityToolkitAnalyzersCodeFixCsproj: 'src/CommunityToolkit.Maui.Analyzers.CodeFixes/CommunityToolkit.Maui.Analyzers.CodeFixes.csproj'
PathToCommunityToolkitAnalyzersUnitTestCsproj: 'src/CommunityToolkit.Maui.Analyzers.UnitTests/CommunityToolkit.Maui.Analyzers.UnitTests.csproj'
- DotNetMauiRollbackFile: 'https://maui.blob.core.windows.net/metadata/rollbacks/6.0.312.json'
+ DotNetMauiRollbackFile: 'https://maui.blob.core.windows.net/metadata/rollbacks/6.0.540.json'
ShouldCheckDependencies: true
trigger:
@@ -62,6 +62,11 @@ jobs:
- powershell: dotnet workload install maui
displayName: Install Latest .NET MAUI Workload
+ - pwsh: |
+ Invoke-WebRequest 'https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.ps1' -OutFile 'workload-install.ps1'
+ .\workload-install.ps1 -DotnetTargetVersionBand $(TOOLKIT_NET_VERSION)
+ displayName: Install Tizen Workload
+
# build sample
- task: CmdLine@2
displayName: 'Build Community Toolkit Sample'
@@ -112,6 +117,11 @@ jobs:
inputs:
script: dotnet workload install maui --from-rollback-file $(DotNetMauiRollbackFile) --source https://api.nuget.org/v3/index.json
+ - pwsh: |
+ Invoke-WebRequest 'https://raw.githubusercontent.com/Samsung/Tizen.NET/main/workload/scripts/workload-install.ps1' -OutFile 'workload-install.ps1'
+ .\workload-install.ps1 -DotnetTargetVersionBand $(TOOLKIT_NET_VERSION)
+ displayName: Install Tizen Workload
+
- task: CmdLine@2
displayName: 'Build CommunityToolkit.Maui.Analyzers'
inputs:
@@ -205,4 +215,4 @@ jobs:
displayName: 'Publish NuGets'
inputs:
artifactName: nuget
- pathToPublish: '$(Build.ArtifactStagingDirectory)'
\ No newline at end of file
+ pathToPublish: '$(Build.ArtifactStagingDirectory)'
diff --git a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj
index 810750301..a130b6c23 100644
--- a/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj
+++ b/samples/CommunityToolkit.Maui.Sample/CommunityToolkit.Maui.Sample.csproj
@@ -3,6 +3,7 @@
net6.0-ios;net6.0-android;net6.0-maccatalyst
$(TargetFrameworks);net6.0-windows10.0.19041.0
+ $(TargetFrameworks);net6.0-tizen
Exe
true
true
@@ -50,6 +51,7 @@
14.0
21.0
10.0.17763.0
+ 6.5
10.0.17763.0
diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/Tizen/Main.cs b/samples/CommunityToolkit.Maui.Sample/Platforms/Tizen/Main.cs
new file mode 100644
index 000000000..c3a1b02ba
--- /dev/null
+++ b/samples/CommunityToolkit.Maui.Sample/Platforms/Tizen/Main.cs
@@ -0,0 +1,16 @@
+using System;
+using Microsoft.Maui;
+using Microsoft.Maui.Hosting;
+
+namespace CommunityToolkit.Maui.Sample;
+
+class Program : MauiApplication
+{
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+
+ static void Main(string[] args)
+ {
+ var app = new Program();
+ app.Run(args);
+ }
+}
\ No newline at end of file
diff --git a/samples/CommunityToolkit.Maui.Sample/Platforms/Tizen/tizen-manifest.xml b/samples/CommunityToolkit.Maui.Sample/Platforms/Tizen/tizen-manifest.xml
new file mode 100644
index 000000000..2233229bd
--- /dev/null
+++ b/samples/CommunityToolkit.Maui.Sample/Platforms/Tizen/tizen-manifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ maui-appicon-placeholder
+
+
+
+
+ http://tizen.org/privilege/internet
+
+
+
+
\ No newline at end of file
diff --git a/samples/CommunityToolkit.Maui.Sample/Views/Popups/ButtonPopup.xaml b/samples/CommunityToolkit.Maui.Sample/Views/Popups/ButtonPopup.xaml
index 5a5fa85cc..09436fa23 100644
--- a/samples/CommunityToolkit.Maui.Sample/Views/Popups/ButtonPopup.xaml
+++ b/samples/CommunityToolkit.Maui.Sample/Views/Popups/ButtonPopup.xaml
@@ -25,7 +25,7 @@
diff --git a/samples/CommunityToolkit.Maui.Sample/Views/Popups/MultipleButtonPopup.xaml b/samples/CommunityToolkit.Maui.Sample/Views/Popups/MultipleButtonPopup.xaml
index 0e829d0bb..c6e746967 100644
--- a/samples/CommunityToolkit.Maui.Sample/Views/Popups/MultipleButtonPopup.xaml
+++ b/samples/CommunityToolkit.Maui.Sample/Views/Popups/MultipleButtonPopup.xaml
@@ -25,7 +25,7 @@
diff --git a/samples/CommunityToolkit.Maui.Sample/Views/Popups/OpenedEventSimplePopup.xaml b/samples/CommunityToolkit.Maui.Sample/Views/Popups/OpenedEventSimplePopup.xaml
index d3db689ac..9f25f615f 100644
--- a/samples/CommunityToolkit.Maui.Sample/Views/Popups/OpenedEventSimplePopup.xaml
+++ b/samples/CommunityToolkit.Maui.Sample/Views/Popups/OpenedEventSimplePopup.xaml
@@ -24,7 +24,7 @@
diff --git a/samples/CommunityToolkit.Maui.Sample/Views/Popups/ReturnResultPopup.xaml b/samples/CommunityToolkit.Maui.Sample/Views/Popups/ReturnResultPopup.xaml
index 6e4b86b06..f6acc30ba 100644
--- a/samples/CommunityToolkit.Maui.Sample/Views/Popups/ReturnResultPopup.xaml
+++ b/samples/CommunityToolkit.Maui.Sample/Views/Popups/ReturnResultPopup.xaml
@@ -24,7 +24,7 @@
diff --git a/samples/CommunityToolkit.Maui.Sample/Views/Popups/ToggleSizePopup.xaml b/samples/CommunityToolkit.Maui.Sample/Views/Popups/ToggleSizePopup.xaml
index 43043d69d..fa0854036 100644
--- a/samples/CommunityToolkit.Maui.Sample/Views/Popups/ToggleSizePopup.xaml
+++ b/samples/CommunityToolkit.Maui.Sample/Views/Popups/ToggleSizePopup.xaml
@@ -26,7 +26,7 @@
diff --git a/src/CommunityToolkit.Maui.Core/CommunityToolkit.Maui.Core.csproj b/src/CommunityToolkit.Maui.Core/CommunityToolkit.Maui.Core.csproj
index 65df674b9..789ca7edf 100644
--- a/src/CommunityToolkit.Maui.Core/CommunityToolkit.Maui.Core.csproj
+++ b/src/CommunityToolkit.Maui.Core/CommunityToolkit.Maui.Core.csproj
@@ -3,6 +3,7 @@
net6.0;net6.0-android;net6.0-ios;net6.0-maccatalyst
$(TargetFrameworks);net6.0-windows10.0.19041.0
+ $(TargetFrameworks);net6.0-tizen
true
true
true
@@ -73,6 +74,12 @@
+
+
+
+
+
+
diff --git a/src/CommunityToolkit.Maui.Core/Handlers/DrawingView/DrawingViewHandler.shared.cs b/src/CommunityToolkit.Maui.Core/Handlers/DrawingView/DrawingViewHandler.shared.cs
index 3f72b3ad2..121ab2cac 100644
--- a/src/CommunityToolkit.Maui.Core/Handlers/DrawingView/DrawingViewHandler.shared.cs
+++ b/src/CommunityToolkit.Maui.Core/Handlers/DrawingView/DrawingViewHandler.shared.cs
@@ -49,7 +49,7 @@ public DrawingViewHandler() : this(DrawingViewMapper, DrawingViewCommandMapper)
}
}
-#if ANDROID || IOS || MACCATALYST || WINDOWS
+#if ANDROID || IOS || MACCATALYST || WINDOWS || TIZEN
public partial class DrawingViewHandler : ViewHandler, IDrawingViewHandler
{
diff --git a/src/CommunityToolkit.Maui.Core/Handlers/Popup/PopupHandler.tizen.cs b/src/CommunityToolkit.Maui.Core/Handlers/Popup/PopupHandler.tizen.cs
new file mode 100644
index 000000000..174a0a44c
--- /dev/null
+++ b/src/CommunityToolkit.Maui.Core/Handlers/Popup/PopupHandler.tizen.cs
@@ -0,0 +1,103 @@
+using CommunityToolkit.Maui.Core.Views;
+using Tizen.UIExtensions.NUI;
+
+namespace CommunityToolkit.Maui.Core.Handlers;
+
+public partial class PopupHandler : Microsoft.Maui.Handlers.ElementHandler
+{
+ ///
+ /// Action that's triggered when the Popup is closed.
+ ///
+ /// An instance of .
+ /// An instance of .
+ /// The result that should return from this Popup.
+ public static void MapOnClosed(PopupHandler handler, IPopup view, object? result)
+ {
+ var popup = handler.PlatformView;
+
+ if (popup.IsOpen)
+ {
+ popup.Close();
+ }
+
+ handler.DisconnectHandler(popup);
+ }
+
+ ///
+ /// Action that's triggered when the Popup is Opened.
+ ///
+ /// An instance of .
+ /// An instance of .
+ /// We don't need to provide the result parameter here.
+ public static void MapOnOpened(PopupHandler handler, IPopup view, object? result)
+ {
+ handler.PlatformView.ShowPopup();
+ }
+
+ ///
+ /// Action that's triggered when the Popup is dismissed by tapping outside of the Popup.
+ ///
+ /// An instance of .
+ /// An instance of .
+ /// The result that should return from this Popup.
+ public static void MapOnDismissedByTappingOutsideOfPopup(PopupHandler handler, IPopup view, object? result)
+ {
+ if (view.CanBeDismissedByTappingOutsideOfPopup)
+ {
+ view.OnDismissedByTappingOutsideOfPopup();
+ }
+ }
+
+ ///
+ /// Action that's triggered when the Popup property changes.
+ ///
+ /// An instance of .
+ /// An instance of .
+ public static void MapAnchor(PopupHandler handler, IPopup view)
+ {
+ // On Tizen, Anchor only update when popup is opened
+ }
+
+ ///
+ /// Action that's triggered when the Popup property changes.
+ ///
+ /// An instance of .
+ /// An instance of .
+ public static void MapCanBeDismissedByTappingOutsideOfPopup(PopupHandler handler, IPopup view)
+ {
+ // this property directly access on platform view
+ }
+
+ ///
+ /// Action that's triggered when the Popup property changes.
+ ///
+ /// An instance of .
+ /// An instance of .
+ public static void MapColor(PopupHandler handler, IPopup view)
+ {
+ // this property directly access on platform view
+ }
+
+ ///
+ /// Action that's triggered when the Popup property changes.
+ ///
+ /// An instance of .
+ /// An instance of .
+ public static void MapSize(PopupHandler handler, IPopup view)
+ {
+ handler.PlatformView.UpdateContentSize();
+ }
+
+ ///
+ protected override void ConnectHandler(MauiPopup platformView)
+ {
+ platformView.SetElement(VirtualView);
+ }
+
+ ///
+ protected override MauiPopup CreatePlatformElement()
+ {
+ var mauiContext = MauiContext ?? throw new InvalidOperationException("${nameof(MauiContext)} cannot be null");
+ return new MauiPopup(mauiContext);
+ }
+}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Maui.Core/Platform/StatusBar/StatusBar.tizen.cs b/src/CommunityToolkit.Maui.Core/Platform/StatusBar/StatusBar.tizen.cs
new file mode 100644
index 000000000..86c85aeaf
--- /dev/null
+++ b/src/CommunityToolkit.Maui.Core/Platform/StatusBar/StatusBar.tizen.cs
@@ -0,0 +1,18 @@
+using System.Runtime.Versioning;
+using Microsoft.Maui.Platform;
+
+namespace CommunityToolkit.Maui.Core.Platform;
+
+[UnsupportedOSPlatform("Tizen")]
+static partial class StatusBar
+{
+ static void PlatformSetColor(Color color)
+ {
+ throw new NotSupportedException("Tizen does not currently support changing the status bar color");
+ }
+
+ static void PlatformSetStyle(StatusBarStyle style)
+ {
+ throw new NotSupportedException("Tizen does not currently support changing the status bar color");
+ }
+}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Maui.Core/Views/DrawingView/PlatformView/MauiDrawingView.tizen.cs b/src/CommunityToolkit.Maui.Core/Views/DrawingView/PlatformView/MauiDrawingView.tizen.cs
new file mode 100644
index 000000000..772c45099
--- /dev/null
+++ b/src/CommunityToolkit.Maui.Core/Views/DrawingView/PlatformView/MauiDrawingView.tizen.cs
@@ -0,0 +1,78 @@
+using Microsoft.Maui.Platform;
+using NPointStateType = Tizen.NUI.PointStateType;
+
+namespace CommunityToolkit.Maui.Core.Views;
+
+public partial class MauiDrawingView : PlatformTouchGraphicsView
+{
+ ///
+ /// Initialize a new instance of .
+ ///
+ public MauiDrawingView() : base(null)
+ {
+ previousPoint = new();
+ TouchEvent += OnTouch;
+ }
+
+ ///
+ /// Initialize resources
+ ///
+ public void Initialize()
+ {
+ Drawable = new DrawingViewDrawable(this);
+ Lines.CollectionChanged += OnLinesCollectionChanged;
+ }
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ currentPath.Dispose();
+ TouchEvent -= OnTouch;
+ }
+
+ base.Dispose(disposing);
+ }
+
+ bool OnTouch(object source, TouchEventArgs e)
+ {
+ var point = new PointF(e.Touch.GetLocalPosition(0).X.ToScaledDP(), e.Touch.GetLocalPosition(0).Y.ToScaledDP());
+ var pointStateType = e.Touch.GetState(0);
+
+ switch (pointStateType)
+ {
+ case NPointStateType.Leave:
+ case NPointStateType.Stationary:
+ break;
+
+ case NPointStateType.Down:
+ OnStart(point);
+ break;
+
+ case NPointStateType.Motion:
+ OnMoving(point);
+ break;
+
+ case NPointStateType.Up:
+ OnFinish();
+ break;
+
+ case NPointStateType.Interrupted:
+ OnCancel();
+ break;
+
+ default:
+ throw new NotSupportedException($"{pointStateType} not supported");
+ }
+
+ Redraw();
+
+ return true;
+ }
+
+ void Redraw()
+ {
+ Invalidate();
+ }
+}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Maui.Core/Views/DrawingView/Service/DrawingViewService.tizen.cs b/src/CommunityToolkit.Maui.Core/Views/DrawingView/Service/DrawingViewService.tizen.cs
new file mode 100644
index 000000000..42cc97695
--- /dev/null
+++ b/src/CommunityToolkit.Maui.Core/Views/DrawingView/Service/DrawingViewService.tizen.cs
@@ -0,0 +1,222 @@
+using Microsoft.Maui.Graphics.Skia;
+using SkiaSharp;
+
+namespace CommunityToolkit.Maui.Core.Views;
+
+///
+/// Drawing view service
+///
+public static class DrawingViewService
+{
+ ///
+ /// Get image stream from points
+ ///
+ /// Drawing points
+ /// Image size
+ /// Line Width
+ /// Line color
+ /// Image background
+ /// Image stream
+ public static ValueTask GetImageStream(IList points, Size imageSize, float lineWidth, Color strokeColor, Paint? background)
+ {
+ var image = GetBitmapForPoints(points, lineWidth, strokeColor, background);
+
+ if (image is null)
+ {
+ return ValueTask.FromResult(Stream.Null);
+ }
+
+ // Defer to thread pool thread https://github.com/CommunityToolkit/Maui/pull/692#pullrequestreview-1150202727
+ return new ValueTask(Task.Run(() =>
+ {
+ var resized = image.Resize(new SKImageInfo((int)imageSize.Width, (int)imageSize.Height, SKColorType.Bgra8888, SKAlphaType.Opaque), SKFilterQuality.High);
+ var data = resized.Encode(SKEncodedImageFormat.Png, 100);
+
+ var stream = new MemoryStream();
+ data.SaveTo(stream);
+ stream.Seek(0, SeekOrigin.Begin);
+
+ return stream;
+ }));
+ }
+
+ ///
+ /// Get image stream from lines
+ ///
+ /// Drawing lines
+ /// Image size
+ /// Image background
+ /// Image stream
+ public static ValueTask GetImageStream(IList lines, Size imageSize, Paint? background)
+ {
+ var image = GetBitmapForLines(lines, background);
+
+ if (image is null)
+ {
+ return ValueTask.FromResult(Stream.Null);
+ }
+
+ // Defer to thread pool thread https://github.com/CommunityToolkit/Maui/pull/692#pullrequestreview-1150202727
+ return new ValueTask(Task.Run(() =>
+ {
+ var resized = image.Resize(new SKImageInfo((int)imageSize.Width, (int)imageSize.Height, SKColorType.Bgra8888, SKAlphaType.Opaque), SKFilterQuality.High);
+ var data = resized.Encode(SKEncodedImageFormat.Png, 100);
+
+ var stream = new MemoryStream();
+ data.SaveTo(stream);
+ stream.Seek(0, SeekOrigin.Begin);
+
+ return stream;
+ }));
+ }
+
+ static (SKBitmap?, SizeF offset) GetBitmap(in ICollection points)
+ {
+ if (points.Count is 0)
+ {
+ return (null, SizeF.Zero);
+ }
+
+ const int minSize = 1;
+ var minPointX = points.Min(static p => p.X);
+ var minPointY = points.Min(static p => p.Y);
+ var drawingWidth = points.Max(static p => p.X) - minPointX;
+ var drawingHeight = points.Max(static p => p.Y) - minPointY;
+
+ if (drawingWidth < minSize || drawingHeight < minSize)
+ {
+ return (null, SizeF.Zero);
+ }
+
+ var bitmap = new SKBitmap((int)drawingWidth, (int)drawingHeight, SKColorType.Bgra8888, SKAlphaType.Opaque);
+
+ return (bitmap, new SizeF(minPointX, minPointY));
+ }
+
+ static SKBitmap? GetBitmapForLines(in IList lines, in Paint? background)
+ {
+ var points = lines.SelectMany(static x => x.Points).ToList();
+ var (image, offset) = GetBitmap(points);
+
+ if (image is null)
+ {
+ return null;
+ }
+
+ using var canvas = new SKCanvas(image);
+
+ DrawBackground(canvas, image.Info, background);
+
+ foreach (var line in lines)
+ {
+ DrawStrokes(canvas, line.Points, line.LineWidth, line.LineColor, offset);
+ }
+
+ return image;
+ }
+
+ static SKBitmap? GetBitmapForPoints(in ICollection points, in float lineWidth, in Color strokeColor, in Paint? background)
+ {
+ var (image, offset) = GetBitmap(points);
+ if (image is null)
+ {
+ return null;
+ }
+
+ using var canvas = new SKCanvas(image);
+
+ DrawBackground(canvas, image.Info, background);
+ DrawStrokes(canvas, points, lineWidth, strokeColor, offset);
+
+ return image;
+ }
+
+ static void DrawBackground(in SKCanvas canvas, in SKImageInfo info, in Paint? brush)
+ {
+ switch (brush)
+ {
+ case SolidPaint solidColorBrush:
+ canvas.DrawColor(solidColorBrush.Color is not null
+ ? solidColorBrush.Color.AsSKColor()
+ : DrawingViewDefaults.BackgroundColor.AsSKColor());
+ break;
+
+ case LinearGradientPaint linearGradientBrush:
+ var paint = new SKPaint();
+ var colors = new SKColor[linearGradientBrush.GradientStops.Length];
+ var positions = new float[linearGradientBrush.GradientStops.Length];
+
+ for (var index = 0; index < linearGradientBrush.GradientStops.Length; index++)
+ {
+ var gradientStop = linearGradientBrush.GradientStops[index];
+ colors[index] = gradientStop.Color.AsSKColor();
+ positions[index] = gradientStop.Offset;
+ }
+
+ var x1 = (float)linearGradientBrush.StartPoint.X * info.Width;
+ var y1 = (float)linearGradientBrush.StartPoint.Y * info.Height;
+ var x2 = (float)linearGradientBrush.EndPoint.X * info.Width;
+ var y2 = (float)linearGradientBrush.EndPoint.Y * info.Height;
+
+ var shader = SKShader.CreateLinearGradient(new SKPoint(x1, y1),
+ new SKPoint(x2, y2),
+ colors,
+ positions,
+ SKShaderTileMode.Clamp);
+ paint.Shader = shader;
+ canvas.DrawRect(0, 0, info.Width, info.Height, paint);
+ break;
+
+ case RadialGradientPaint radialGradientBrush:
+ var skPaint = new SKPaint();
+ var skColors = new SKColor[radialGradientBrush.GradientStops.Length];
+ var positionsArray = new float[radialGradientBrush.GradientStops.Length];
+
+ for (var index = 0; index < radialGradientBrush.GradientStops.Length; index++)
+ {
+ var gradientStop = radialGradientBrush.GradientStops[index];
+ skColors[index] = gradientStop.Color.AsSKColor();
+ positionsArray[index] = gradientStop.Offset;
+ }
+
+ float centerX = (float)(radialGradientBrush.Center.X * info.Width);
+ float centerY = (float)(radialGradientBrush.Center.Y * info.Height);
+ float radius = (float)(radialGradientBrush.Radius * info.Width);
+
+ var skShader = SKShader.CreateRadialGradient(new SKPoint(centerX, centerX),
+ radius,
+ skColors,
+ positionsArray,
+ SKShaderTileMode.Clamp);
+ skPaint.Shader = skShader;
+ canvas.DrawRect(0, 0, info.Width, info.Height, skPaint);
+ break;
+
+ default:
+ canvas.DrawColor(DrawingViewDefaults.BackgroundColor.AsSKColor());
+ break;
+ }
+ }
+
+ static void DrawStrokes(in SKCanvas canvas, in ICollection points, in float lineWidth, in Color strokeColor, in SizeF offset)
+ {
+ using var paint = new SKPaint
+ {
+ StrokeWidth = lineWidth,
+ StrokeJoin = SKStrokeJoin.Round,
+ StrokeCap = SKStrokeCap.Round,
+ IsAntialias = true,
+ Color = strokeColor.AsSKColor(),
+ Style = SKPaintStyle.Stroke,
+ };
+
+ var pointsCount = points.Count;
+ for (var i = 0; i < pointsCount - 1; i++)
+ {
+ var p1 = points.ElementAt(i);
+ var p2 = points.ElementAt(i + 1);
+
+ canvas.DrawLine(p1.X - offset.Width, p1.Y - offset.Height, p2.X - offset.Width, p2.Y - offset.Height, paint);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Maui.Core/Views/Popup/MauiPopup.tizen.cs b/src/CommunityToolkit.Maui.Core/Views/Popup/MauiPopup.tizen.cs
new file mode 100644
index 000000000..ffd21b410
--- /dev/null
+++ b/src/CommunityToolkit.Maui.Core/Views/Popup/MauiPopup.tizen.cs
@@ -0,0 +1,138 @@
+using Microsoft.Maui.Platform;
+using Microsoft.Maui.Primitives;
+using Tizen.NUI;
+using Tizen.UIExtensions.NUI;
+using NHorizontalAlignment = Tizen.NUI.HorizontalAlignment;
+using NVerticalAlignment = Tizen.NUI.VerticalAlignment;
+
+namespace CommunityToolkit.Maui.Core.Views;
+
+///
+/// The native implementation of Popup control.
+///
+public class MauiPopup : Popup
+{
+ readonly IMauiContext mauiContext;
+
+ ///
+ /// Constructor of .
+ ///
+ /// An instance of .
+ /// If is null an exception will be thrown.
+ public MauiPopup(IMauiContext mauiContext)
+ {
+ this.mauiContext = mauiContext ?? throw new ArgumentNullException(nameof(mauiContext));
+ OutsideClicked += OnOutsideClicked;
+ }
+
+ ///
+ /// An instance of the .
+ ///
+ public IPopup? VirtualView { get; private set; }
+
+ ///
+ protected override void Dispose(bool isDisposing)
+ {
+ if (isDisposing)
+ {
+ OutsideClicked -= OnOutsideClicked;
+ }
+
+ base.Dispose(isDisposing);
+ }
+
+ ///
+ /// Method to initialize the native implementation.
+ ///
+ /// An instance of .
+ public void SetElement(IPopup? element)
+ {
+ VirtualView = element;
+ }
+
+ ///
+ /// Method to show the Popup
+ ///
+ public void ShowPopup()
+ {
+ _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} cannot be null");
+ Content = VirtualView.Content?.ToPlatform(mauiContext) ?? throw new InvalidOperationException($"{nameof(VirtualView.Content)} cannot be null");
+
+ BackgroundColor = new Tizen.NUI.Color(0.1f, 0.1f, 0.1f, 0.5f);
+ Content.BackgroundColor = (VirtualView.Color ?? Colors.Transparent).ToNUIColor();
+
+ if (VirtualView.Anchor is not null)
+ {
+ var anchorView = VirtualView.Anchor.ToPlatform();
+ var anchorPosition = anchorView.ScreenPosition;
+ Layout = new AbsoluteLayout();
+ Content.UpdatePosition(new Tizen.UIExtensions.Common.Point(anchorPosition.X, anchorPosition.Y));
+ }
+ else
+ {
+ Layout = new LinearLayout
+ {
+ LinearOrientation = LinearLayout.Orientation.Vertical,
+ VerticalAlignment = ToVerticalAlignment(VirtualView.VerticalOptions),
+ HorizontalAlignment = ToHorizontalAlignment(VirtualView.HorizontalOptions),
+ };
+ Content.UpdatePosition(new Tizen.UIExtensions.Common.Point(0, 0));
+ }
+
+ UpdateContentSize();
+
+ Open();
+ VirtualView.OnOpened();
+ }
+
+ ///
+ /// Method to update size of Content
+ ///
+ ///
+ public void UpdateContentSize()
+ {
+ _ = VirtualView ?? throw new InvalidOperationException($"{nameof(VirtualView)} cannot be null");
+ if (Content is null)
+ {
+ return;
+ }
+
+ if (VirtualView.Size.Width > 0 && VirtualView.Size.Height > 0)
+ {
+ Content.UpdateSize(VirtualView.Size.ToPixel());
+ }
+ else
+ {
+ var measured = VirtualView.Content?.Measure(double.PositiveInfinity, double.PositiveInfinity).ToPixel() ?? new Tizen.UIExtensions.Common.Size(0, 0);
+ Content.UpdateSize(measured);
+ }
+ }
+
+ static NVerticalAlignment ToVerticalAlignment(LayoutAlignment align) => align switch
+ {
+ LayoutAlignment.Start => NVerticalAlignment.Top,
+ LayoutAlignment.End => NVerticalAlignment.Bottom,
+ _ => NVerticalAlignment.Center
+ };
+
+ static NHorizontalAlignment ToHorizontalAlignment(LayoutAlignment align) => align switch
+ {
+ LayoutAlignment.Start => NHorizontalAlignment.Begin,
+ LayoutAlignment.End => NHorizontalAlignment.End,
+ _ => NHorizontalAlignment.Center
+ };
+
+ void OnOutsideClicked(object? sender, EventArgs e)
+ {
+ if (VirtualView?.Handler is null)
+ {
+ return;
+ }
+
+ if (VirtualView.CanBeDismissedByTappingOutsideOfPopup)
+ {
+ Close();
+ VirtualView.Handler.Invoke(nameof(IPopup.OnDismissedByTappingOutsideOfPopup));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Maui/Alerts/Snackbar/Snackbar.tizen.cs b/src/CommunityToolkit.Maui/Alerts/Snackbar/Snackbar.tizen.cs
new file mode 100644
index 000000000..ae9a01b8c
--- /dev/null
+++ b/src/CommunityToolkit.Maui/Alerts/Snackbar/Snackbar.tizen.cs
@@ -0,0 +1,181 @@
+using Microsoft.Maui.Platform;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using NLinearLayout = Tizen.NUI.LinearLayout;
+using NVerticalAlignment = Tizen.NUI.VerticalAlignment;
+using NView = Tizen.NUI.BaseComponents.View;
+using TButton = Tizen.UIExtensions.NUI.Button;
+using TLabel = Tizen.UIExtensions.NUI.Label;
+using TPopup = Tizen.UIExtensions.NUI.Popup;
+
+namespace CommunityToolkit.Maui.Alerts;
+
+public partial class Snackbar
+{
+ static TPopup? PopupStatic { get; set; }
+
+ TPopup? PopupInstance { get; set; }
+
+ ///
+ /// Dispose Snackbar
+ ///
+ protected virtual void Dispose(bool isDisposing)
+ {
+ if (isDisposed)
+ {
+ return;
+ }
+
+ if (isDisposing)
+ {
+ PopupInstance?.Close();
+ PopupInstance?.Dispose();
+ PopupInstance = null;
+ }
+ isDisposed = true;
+ }
+
+ ///
+ Task ShowPlatform(CancellationToken token)
+ {
+ var dispatcher = Dispatcher.GetForCurrentThread() ?? Application.Current?.Dispatcher ?? throw new InvalidOperationException($"There is no IDispatcher object, application is not initalized");
+
+ // close and cleanup the previously opened snackbar
+ if (PopupStatic is not null && PopupStatic.IsOpen)
+ {
+ PopupStatic.Close();
+ PopupStatic.Dispose();
+ PopupStatic = null;
+ }
+
+ var popup = new OutsidePassThroughPopup
+ {
+ Layout = new NLinearLayout
+ {
+ LinearOrientation = NLinearLayout.Orientation.Vertical,
+ VerticalAlignment = NVerticalAlignment.Bottom,
+ }
+ };
+
+ var content = new NView
+ {
+ Margin = new Extents((ushort)10d.ToScaledPixel()),
+ WidthSpecification = LayoutParamPolicies.MatchParent,
+ HeightSpecification = LayoutParamPolicies.WrapContent,
+
+ BackgroundColor = VisualOptions.BackgroundColor.ToNUIColor(),
+ CornerRadius = new Vector4(10, 10, 10, 10),
+ Layout = new NLinearLayout
+ {
+ LinearOrientation = NLinearLayout.Orientation.Horizontal,
+ VerticalAlignment = NVerticalAlignment.Center,
+ }
+ };
+
+ var margin = (ushort)10d.ToScaledPixel();
+
+ var message = new TLabel()
+ {
+ MultiLine = true,
+ Margin = margin,
+ WidthSpecification = LayoutParamPolicies.MatchParent,
+ Text = Text,
+ TextColor = VisualOptions.TextColor.ToPlatform(),
+ PixelSize = VisualOptions.Font.Size.ToPixel(),
+ FontAttributes = LabelExtensions.GetFontAttributes(VisualOptions.Font),
+ };
+ content.Add(message);
+
+ var actionButton = new TButton()
+ {
+ Margin = margin,
+ WidthSpecification = LayoutParamPolicies.WrapContent,
+ BackgroundColor = Tizen.NUI.Color.Transparent,
+ TextColor = VisualOptions.ActionButtonTextColor.ToPlatform(),
+ Text = ActionButtonText,
+ };
+ actionButton.TextLabel.PixelSize = 15d.ToPixel();
+ actionButton.SizeWidth = actionButton.TextLabel.NaturalSize.Width + 15d.ToPixel() * 2;
+ actionButton.Clicked += (s, e) =>
+ {
+ if (Action is not null)
+ {
+ Action.Invoke();
+ }
+ else
+ {
+ popup.Close();
+ }
+ };
+
+ content.Add(actionButton);
+ popup.Content = content;
+
+ if (Anchor is not null)
+ {
+ var anchorPlatformView = Anchor.ToPlatform();
+
+ // can't measure height of content on NUI
+ var maximumHeight = 100d.ToScaledPixel();
+ popup.SizeHeight = maximumHeight;
+
+ if (maximumHeight < anchorPlatformView.ScreenPosition.Y)
+ {
+ // display top outside of anchor
+ popup.Position = new Position(0, anchorPlatformView.ScreenPosition.Y - popup.SizeHeight);
+ }
+ else
+ {
+ // display bottom innter of anchor
+ popup.Position = new Position(0, anchorPlatformView.ScreenPosition.Y - (maximumHeight - anchorPlatformView.SizeHeight));
+ }
+ }
+ else
+ {
+ popup.Position = new Position(0, 0);
+ popup.WidthSpecification = LayoutParamPolicies.MatchParent;
+ popup.HeightSpecification = LayoutParamPolicies.MatchParent;
+ }
+
+ popup.Closed += (s, e) => OnDismissed();
+ popup.Open();
+
+ var timer = dispatcher.CreateTimer();
+ timer.IsRepeating = false;
+ timer.Interval = Duration;
+ timer.Tick += (s, e) => popup.Close();
+ timer.Start();
+
+ PopupStatic = popup;
+ PopupInstance = popup;
+
+ OnShown();
+
+ return Task.CompletedTask;
+ }
+
+ ///
+ Task DismissPlatform(CancellationToken token)
+ {
+ token.ThrowIfCancellationRequested();
+
+ if (PopupInstance is null)
+ {
+ return Task.CompletedTask;
+ }
+
+ PopupInstance.Close();
+ PopupInstance.Dispose();
+ PopupInstance = null;
+
+ return Task.CompletedTask;
+ }
+
+ class OutsidePassThroughPopup : TPopup
+ {
+ protected override bool HitTest(Touch touch)
+ {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Maui/Alerts/Toast/Toast.tizen.cs b/src/CommunityToolkit.Maui/Alerts/Toast/Toast.tizen.cs
new file mode 100644
index 000000000..02476e5ee
--- /dev/null
+++ b/src/CommunityToolkit.Maui/Alerts/Toast/Toast.tizen.cs
@@ -0,0 +1,39 @@
+namespace CommunityToolkit.Maui.Alerts;
+
+public partial class Toast
+{
+ ///
+ /// Dispose Toast
+ ///
+ protected virtual void Dispose(bool isDisposing)
+ {
+ if (isDisposed)
+ {
+ return;
+ }
+
+ isDisposed = true;
+ }
+
+ ///
+ /// Show Toast
+ ///
+ void ShowPlatform(CancellationToken token)
+ {
+ DismissPlatform(token);
+ token.ThrowIfCancellationRequested();
+
+ new Tizen.Applications.ToastMessage
+ {
+ Message = Text
+ }.Post();
+ }
+
+ ///
+ /// Dismiss Toast
+ ///
+ static void DismissPlatform(CancellationToken token)
+ {
+ token.ThrowIfCancellationRequested();
+ }
+}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/IconTintColor/IconTintColorBehavior.shared.cs b/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/IconTintColor/IconTintColorBehavior.shared.cs
index 10aa7e92f..5f122e5fd 100644
--- a/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/IconTintColor/IconTintColorBehavior.shared.cs
+++ b/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/IconTintColor/IconTintColorBehavior.shared.cs
@@ -5,7 +5,7 @@ namespace CommunityToolkit.Maui.Behaviors;
///
/// A behavior that allows you to tint an icon with a specified .
///
-[UnsupportedOSPlatform("windows")]
+[UnsupportedOSPlatform("windows"), UnsupportedOSPlatform("Tizen")]
public partial class IconTintColorBehavior : PlatformBehavior
{
///
diff --git a/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/SelectAllText/SelectAllTextBehavior.tizen.cs b/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/SelectAllText/SelectAllTextBehavior.tizen.cs
new file mode 100644
index 000000000..8cdeccfef
--- /dev/null
+++ b/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/SelectAllText/SelectAllTextBehavior.tizen.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tizen.NUI.BaseComponents;
+using NView = Tizen.NUI.BaseComponents.View;
+
+namespace CommunityToolkit.Maui.Behaviors;
+
+///
+/// A behavior that selects all text when the view is focused.
+///
+public class SelectAllTextBehavior : PlatformBehavior
+{
+ ///
+ protected override void OnAttachedTo(InputView bindable, NView platformView) => ApplyEffect(true, platformView);
+
+ ///
+ protected override void OnDetachedFrom(InputView bindable, NView platformView) => ApplyEffect(false, platformView);
+
+
+ void ApplyEffect(bool apply, NView inputView)
+ {
+ ArgumentNullException.ThrowIfNull(inputView);
+
+ inputView.FocusGained -= OnFocused;
+
+ if (apply)
+ {
+ inputView.FocusGained += OnFocused;
+ }
+
+ static void OnFocused(object? sender, EventArgs e)
+ {
+ if (sender is TextField tf && tf.HasFocus())
+ {
+ tf.SelectWholeText();
+ }
+ else if (sender is TextEditor te && te.HasFocus())
+ {
+ te.SelectWholeText();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/StatusBar/StatusBarBehavior.shared.cs b/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/StatusBar/StatusBarBehavior.shared.cs
index e33adc511..a6e9cc6f9 100644
--- a/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/StatusBar/StatusBarBehavior.shared.cs
+++ b/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/StatusBar/StatusBarBehavior.shared.cs
@@ -10,7 +10,7 @@ namespace CommunityToolkit.Maui.Behaviors;
///
/// that controls the Status bar color
///
-[UnsupportedOSPlatform("Windows"), UnsupportedOSPlatform("MacCatalyst"), UnsupportedOSPlatform("MacOS")]
+[UnsupportedOSPlatform("Windows"), UnsupportedOSPlatform("MacCatalyst"), UnsupportedOSPlatform("MacOS"), UnsupportedOSPlatform("Tizen")]
public class StatusBarBehavior : PlatformBehavior
{
///
@@ -44,7 +44,7 @@ public StatusBarStyle StatusBarStyle
set => SetValue(StatusBarStyleProperty, value);
}
-#if !(WINDOWS || MACCATALYST)
+#if !(WINDOWS || MACCATALYST || TIZEN)
///
#if IOS
diff --git a/src/CommunityToolkit.Maui/CommunityToolkit.Maui.csproj b/src/CommunityToolkit.Maui/CommunityToolkit.Maui.csproj
index a9ae3cad2..b9e2033a5 100644
--- a/src/CommunityToolkit.Maui/CommunityToolkit.Maui.csproj
+++ b/src/CommunityToolkit.Maui/CommunityToolkit.Maui.csproj
@@ -3,6 +3,7 @@
net6.0;net6.0-android;net6.0-ios;net6.0-maccatalyst
$(TargetFrameworks);net6.0-windows10.0.19041.0
+ $(TargetFrameworks);net6.0-tizen
true
true
true
@@ -74,6 +75,12 @@
+
+
+
+
+
+