diff --git a/Avalonia.sln b/Avalonia.sln
index b21df07628..f33b782479 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -244,13 +244,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ItemsRepe
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ItemsRepeater.UnitTests", "tests\Avalonia.Controls.ItemsRepeater.UnitTests\Avalonia.Controls.ItemsRepeater.UnitTests.csproj", "{F4E36AA8-814E-4704-BC07-291F70F45193}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators", "src\tools\Avalonia.Generators\Avalonia.Generators.csproj", "{DDA28789-C21A-4654-86CE-D01E81F095C5}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Generators.Tests", "tests\Avalonia.Generators.Tests\Avalonia.Generators.Tests.csproj", "{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Fonts.Inter", "src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj", "{13F1135D-BA1A-435C-9C5B-A368D1D63DE4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo", "samples\SafeAreaDemo\SafeAreaDemo.csproj", "{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Android", "samples\SafeAreaDemo.Android\SafeAreaDemo.Android.csproj", "{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Desktop", "samples\SafeAreaDemo.Desktop\SafeAreaDemo.Desktop.csproj", "{4CDAD037-34A2-4CCF-A03A-C6C7B988A572}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.iOS", "samples\SafeAreaDemo.iOS\SafeAreaDemo.iOS.csproj", "{FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -595,6 +603,26 @@ Global
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4CDAD037-34A2-4CCF-A03A-C6C7B988A572}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -661,10 +689,14 @@ Global
{75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
+ {F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{2D7C812B-7E73-4252-8EFD-BC8A4D5CCB9F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
- {F4E36AA8-814E-4704-BC07-291F70F45193} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{A82AD1BC-EBE6-4FC3-A13B-D52A50297533} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+ {6B60A970-D5D2-49C2-8BAB-F9C7973B74B6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+ {22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+ {4CDAD037-34A2-4CCF-A03A-C6C7B988A572} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+ {FC956F9A-4C3A-4A1A-ACDD-BB54DCB661DD} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
diff --git a/samples/SafeAreaDemo.Android/Icon.png b/samples/SafeAreaDemo.Android/Icon.png
new file mode 100644
index 0000000000..41a2a618fb
Binary files /dev/null and b/samples/SafeAreaDemo.Android/Icon.png differ
diff --git a/samples/SafeAreaDemo.Android/MainActivity.cs b/samples/SafeAreaDemo.Android/MainActivity.cs
new file mode 100644
index 0000000000..b0f0a6e419
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/MainActivity.cs
@@ -0,0 +1,11 @@
+using Android.App;
+using Android.Content.PM;
+using Avalonia.Android;
+
+namespace SafeAreaDemo.Android
+{
+ [Activity(Label = "SafeAreaDemo.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
+ public class MainActivity : AvaloniaMainActivity
+ {
+ }
+}
diff --git a/samples/SafeAreaDemo.Android/Properties/AndroidManifest.xml b/samples/SafeAreaDemo.Android/Properties/AndroidManifest.xml
new file mode 100644
index 0000000000..b6a5777e03
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Properties/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/Resources/drawable/splash_screen.xml b/samples/SafeAreaDemo.Android/Resources/drawable/splash_screen.xml
new file mode 100644
index 0000000000..2e920b4b3b
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/drawable/splash_screen.xml
@@ -0,0 +1,13 @@
+
+
+
+ -
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/Resources/values/colors.xml b/samples/SafeAreaDemo.Android/Resources/values/colors.xml
new file mode 100644
index 0000000000..59279d5d32
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/values/colors.xml
@@ -0,0 +1,4 @@
+
+
+ #FFFFFF
+
diff --git a/samples/SafeAreaDemo.Android/Resources/values/styles.xml b/samples/SafeAreaDemo.Android/Resources/values/styles.xml
new file mode 100644
index 0000000000..2759d2904a
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/Resources/values/styles.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj b/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
new file mode 100644
index 0000000000..f5d2af79d0
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/SafeAreaDemo.Android.csproj
@@ -0,0 +1,24 @@
+
+
+ Exe
+ net7.0-android
+ 21
+ enable
+ com.avalonia.safeareademo
+ 1
+ 1.0
+ apk
+ False
+
+
+
+
+ Resources\drawable\Icon.png
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Android/SplashActivity.cs b/samples/SafeAreaDemo.Android/SplashActivity.cs
new file mode 100644
index 0000000000..621ad1c675
--- /dev/null
+++ b/samples/SafeAreaDemo.Android/SplashActivity.cs
@@ -0,0 +1,30 @@
+using Android.App;
+using Android.Content;
+using Android.OS;
+using Avalonia;
+using Avalonia.Android;
+using Application = Android.App.Application;
+
+namespace SafeAreaDemo.Android
+{
+ [Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
+ public class SplashActivity : AvaloniaSplashActivity
+ {
+ protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
+ {
+ return base.CustomizeAppBuilder(builder);
+ }
+
+ protected override void OnCreate(Bundle? savedInstanceState)
+ {
+ base.OnCreate(savedInstanceState);
+ }
+
+ protected override void OnResume()
+ {
+ base.OnResume();
+
+ StartActivity(new Intent(Application.Context, typeof(MainActivity)));
+ }
+ }
+}
diff --git a/samples/SafeAreaDemo.Desktop/Program.cs b/samples/SafeAreaDemo.Desktop/Program.cs
new file mode 100644
index 0000000000..b07682e8c8
--- /dev/null
+++ b/samples/SafeAreaDemo.Desktop/Program.cs
@@ -0,0 +1,21 @@
+using Avalonia;
+using System;
+
+namespace SafeAreaDemo.Desktop
+{
+ internal class Program
+ {
+ // Initialization code. Don't use any Avalonia, third-party APIs or any
+ // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
+ // yet and stuff might break.
+ [STAThread]
+ public static void Main(string[] args) => BuildAvaloniaApp()
+ .StartWithClassicDesktopLifetime(args);
+
+ // Avalonia configuration, don't remove; also used by visual designer.
+ public static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure()
+ .UsePlatformDetect()
+ .LogToTrace();
+ }
+}
diff --git a/samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj b/samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj
new file mode 100644
index 0000000000..619209892d
--- /dev/null
+++ b/samples/SafeAreaDemo.Desktop/SafeAreaDemo.Desktop.csproj
@@ -0,0 +1,24 @@
+
+
+ WinExe
+
+ net7.0
+ enable
+ true
+
+
+
+ app.manifest
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.Desktop/app.manifest b/samples/SafeAreaDemo.Desktop/app.manifest
new file mode 100644
index 0000000000..f0a4b00175
--- /dev/null
+++ b/samples/SafeAreaDemo.Desktop/app.manifest
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.iOS/AppDelegate.cs b/samples/SafeAreaDemo.iOS/AppDelegate.cs
new file mode 100644
index 0000000000..6990435d78
--- /dev/null
+++ b/samples/SafeAreaDemo.iOS/AppDelegate.cs
@@ -0,0 +1,17 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.iOS;
+using Avalonia.Media;
+using Foundation;
+using UIKit;
+
+namespace SafeAreaDemo.iOS
+{
+ // The UIApplicationDelegate for the application. This class is responsible for launching the
+ // User Interface of the application, as well as listening (and optionally responding) to
+ // application events from iOS.
+ [Register("AppDelegate")]
+ public partial class AppDelegate : AvaloniaAppDelegate
+ {
+ }
+}
diff --git a/samples/SafeAreaDemo.iOS/Entitlements.plist b/samples/SafeAreaDemo.iOS/Entitlements.plist
new file mode 100644
index 0000000000..0c67376eba
--- /dev/null
+++ b/samples/SafeAreaDemo.iOS/Entitlements.plist
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.iOS/Info.plist b/samples/SafeAreaDemo.iOS/Info.plist
new file mode 100644
index 0000000000..ec04bd5a87
--- /dev/null
+++ b/samples/SafeAreaDemo.iOS/Info.plist
@@ -0,0 +1,47 @@
+
+
+
+
+ CFBundleDisplayName
+ SafeAreaDemo
+ CFBundleIdentifier
+ companyName.SafeAreaDemo
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1.0
+ LSRequiresIPhoneOS
+
+ MinimumOSVersion
+ 10.0
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIStatusBarHidden
+
+ UIViewControllerBasedStatusBarAppearance
+
+
+
diff --git a/samples/SafeAreaDemo.iOS/Main.cs b/samples/SafeAreaDemo.iOS/Main.cs
new file mode 100644
index 0000000000..1c76dc6bc4
--- /dev/null
+++ b/samples/SafeAreaDemo.iOS/Main.cs
@@ -0,0 +1,15 @@
+using UIKit;
+
+namespace SafeAreaDemo.iOS
+{
+ public class Application
+ {
+ // This is the main entry point of the application.
+ static void Main(string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main(args, null, typeof(AppDelegate));
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/SafeAreaDemo.iOS/Resources/LaunchScreen.xib b/samples/SafeAreaDemo.iOS/Resources/LaunchScreen.xib
new file mode 100644
index 0000000000..c6dd636c46
--- /dev/null
+++ b/samples/SafeAreaDemo.iOS/Resources/LaunchScreen.xib
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo.iOS/SafeAreaDemo.iOS.csproj b/samples/SafeAreaDemo.iOS/SafeAreaDemo.iOS.csproj
new file mode 100644
index 0000000000..71365fe07d
--- /dev/null
+++ b/samples/SafeAreaDemo.iOS/SafeAreaDemo.iOS.csproj
@@ -0,0 +1,18 @@
+
+
+ Exe
+ net7.0-ios
+ 10.0
+ manual
+ enable
+ iossimulator-x64
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo/App.xaml b/samples/SafeAreaDemo/App.xaml
new file mode 100644
index 0000000000..f5ffbdb32a
--- /dev/null
+++ b/samples/SafeAreaDemo/App.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/SafeAreaDemo/App.xaml.cs b/samples/SafeAreaDemo/App.xaml.cs
new file mode 100644
index 0000000000..e23cb0e04a
--- /dev/null
+++ b/samples/SafeAreaDemo/App.xaml.cs
@@ -0,0 +1,36 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using SafeAreaDemo.ViewModels;
+using SafeAreaDemo.Views;
+
+namespace SafeAreaDemo
+{
+ public partial class App : Application
+ {
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = new MainWindow
+ {
+ DataContext = new MainViewModel()
+ };
+ }
+ else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
+ {
+ singleViewPlatform.MainView = new MainView
+ {
+ DataContext = new MainViewModel()
+ };
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/SafeAreaDemo/Assets/avalonia-logo.ico b/samples/SafeAreaDemo/Assets/avalonia-logo.ico
new file mode 100644
index 0000000000..da8d49ff9b
Binary files /dev/null and b/samples/SafeAreaDemo/Assets/avalonia-logo.ico differ
diff --git a/samples/SafeAreaDemo/SafeAreaDemo.csproj b/samples/SafeAreaDemo/SafeAreaDemo.csproj
new file mode 100644
index 0000000000..20bc5ec8fe
--- /dev/null
+++ b/samples/SafeAreaDemo/SafeAreaDemo.csproj
@@ -0,0 +1,27 @@
+
+
+ net7.0
+ enable
+ latest
+ true
+
+
+
+
+
+ %(Filename)
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo/ViewLocator.cs b/samples/SafeAreaDemo/ViewLocator.cs
new file mode 100644
index 0000000000..99800f81c9
--- /dev/null
+++ b/samples/SafeAreaDemo/ViewLocator.cs
@@ -0,0 +1,31 @@
+using System;
+using Avalonia.Controls;
+using Avalonia.Controls.Templates;
+using MiniMvvm;
+
+namespace SafeAreaDemo
+{
+ public class ViewLocator : IDataTemplate
+ {
+ public Control Build(object data)
+ {
+ if (data is null)
+ return null;
+
+ var name = data.GetType().FullName!.Replace("ViewModel", "View");
+ var type = Type.GetType(name);
+
+ if (type != null)
+ {
+ return (Control)Activator.CreateInstance(type)!;
+ }
+
+ return new TextBlock { Text = name };
+ }
+
+ public bool Match(object? data)
+ {
+ return data is ViewModelBase;
+ }
+ }
+}
diff --git a/samples/SafeAreaDemo/ViewModels/MainViewModel.cs b/samples/SafeAreaDemo/ViewModels/MainViewModel.cs
new file mode 100644
index 0000000000..fe58567171
--- /dev/null
+++ b/samples/SafeAreaDemo/ViewModels/MainViewModel.cs
@@ -0,0 +1,112 @@
+using Avalonia;
+using Avalonia.Controls.Platform;
+using MiniMvvm;
+
+namespace SafeAreaDemo.ViewModels
+{
+ public class MainViewModel : ViewModelBase
+ {
+ private bool _useSafeArea = true;
+ private bool _fullscreen;
+ private IInsetsManager? _insetsManager;
+ private bool _hideSystemBars;
+
+ public Thickness SafeAreaPadding
+ {
+ get
+ {
+ return _insetsManager?.SafeAreaPadding ?? default;
+ }
+ }
+
+ public Thickness ViewPadding
+ {
+ get
+ {
+ return _useSafeArea ? SafeAreaPadding : default;
+ }
+ }
+
+ public bool UseSafeArea
+ {
+ get => _useSafeArea;
+ set
+ {
+ _useSafeArea = value;
+
+ this.RaisePropertyChanged();
+
+ RaiseSafeAreaChanged();
+ }
+ }
+
+ public bool Fullscreen
+ {
+ get => _fullscreen;
+ set
+ {
+ _fullscreen = value;
+
+ if (_insetsManager != null)
+ {
+ _insetsManager.DisplayEdgeToEdge = value;
+ }
+
+ this.RaisePropertyChanged();
+
+ RaiseSafeAreaChanged();
+ }
+ }
+
+ public bool HideSystemBars
+ {
+ get => _hideSystemBars;
+ set
+ {
+ _hideSystemBars = value;
+
+ if (_insetsManager != null)
+ {
+ _insetsManager.IsSystemBarVisible = !value;
+ }
+
+ this.RaisePropertyChanged();
+
+ RaiseSafeAreaChanged();
+ }
+ }
+
+ internal IInsetsManager? InsetsManager
+ {
+ get => _insetsManager;
+ set
+ {
+ if (_insetsManager != null)
+ {
+ _insetsManager.SafeAreaChanged -= InsetsManager_SafeAreaChanged;
+ }
+
+ _insetsManager = value;
+
+ if (_insetsManager != null)
+ {
+ _insetsManager.SafeAreaChanged += InsetsManager_SafeAreaChanged;
+
+ _insetsManager.DisplayEdgeToEdge = _fullscreen;
+ _insetsManager.IsSystemBarVisible = !_hideSystemBars;
+ }
+ }
+ }
+
+ private void InsetsManager_SafeAreaChanged(object? sender, SafeAreaChangedArgs e)
+ {
+ RaiseSafeAreaChanged();
+ }
+
+ private void RaiseSafeAreaChanged()
+ {
+ this.RaisePropertyChanged(nameof(SafeAreaPadding));
+ this.RaisePropertyChanged(nameof(ViewPadding));
+ }
+ }
+}
diff --git a/samples/SafeAreaDemo/Views/MainView.xaml b/samples/SafeAreaDemo/Views/MainView.xaml
new file mode 100644
index 0000000000..a8f7c2e735
--- /dev/null
+++ b/samples/SafeAreaDemo/Views/MainView.xaml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fullscreen
+ Use Safe Area
+ Hide System Bars
+
+
+
+
+
+
+
diff --git a/samples/SafeAreaDemo/Views/MainView.xaml.cs b/samples/SafeAreaDemo/Views/MainView.xaml.cs
new file mode 100644
index 0000000000..2b651225e7
--- /dev/null
+++ b/samples/SafeAreaDemo/Views/MainView.xaml.cs
@@ -0,0 +1,25 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using SafeAreaDemo.ViewModels;
+
+namespace SafeAreaDemo.Views
+{
+ public partial class MainView : UserControl
+ {
+ public MainView()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ protected override void OnLoaded()
+ {
+ base.OnLoaded();
+
+ var insetsManager = TopLevel.GetTopLevel(this)?.InsetsManager;
+ if (insetsManager != null && DataContext is MainViewModel viewModel)
+ {
+ viewModel.InsetsManager = insetsManager;
+ }
+ }
+ }
+}
diff --git a/samples/SafeAreaDemo/Views/MainWindow.xaml b/samples/SafeAreaDemo/Views/MainWindow.xaml
new file mode 100644
index 0000000000..ccd3028bb9
--- /dev/null
+++ b/samples/SafeAreaDemo/Views/MainWindow.xaml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/samples/SafeAreaDemo/Views/MainWindow.xaml.cs b/samples/SafeAreaDemo/Views/MainWindow.xaml.cs
new file mode 100644
index 0000000000..de8f2b05ca
--- /dev/null
+++ b/samples/SafeAreaDemo/Views/MainWindow.xaml.cs
@@ -0,0 +1,13 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace SafeAreaDemo.Views
+{
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}