diff --git a/samples/SafeAreaDemo/App.xaml b/samples/SafeAreaDemo/App.xaml
index f406bfe710..70fd759dad 100644
--- a/samples/SafeAreaDemo/App.xaml
+++ b/samples/SafeAreaDemo/App.xaml
@@ -2,7 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SafeAreaDemo"
x:Class="SafeAreaDemo.App"
- RequestedThemeVariant="Light">
+ RequestedThemeVariant="Default">
diff --git a/samples/SafeAreaDemo/Views/MainView.xaml b/samples/SafeAreaDemo/Views/MainView.xaml
index 85163e7dad..a2b336abe0 100644
--- a/samples/SafeAreaDemo/Views/MainView.xaml
+++ b/samples/SafeAreaDemo/Views/MainView.xaml
@@ -8,7 +8,6 @@
d:DesignHeight="450"
x:Class="SafeAreaDemo.Views.MainView"
x:DataType="vm:MainViewModel"
- Background="#ccc"
TopLevel.AutoSafeAreaPadding="{Binding AutoSafeAreaPadding, Mode=TwoWay}">
_view;
@@ -39,15 +36,42 @@ namespace Avalonia.Android
public object? Content
{
- get { return _root.Content; }
- set { _root.Content = value; }
+ get { return _root?.Content; }
+ set
+ {
+ _content = null;
+ if (_root != null)
+ _root.Content = value;
+ else
+ {
+ _content = value;
+ }
+ }
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
+ }
+
+ protected override void OnDetachedFromWindow()
+ {
+ base.OnDetachedFromWindow();
_root?.Dispose();
- _root = null!;
+ _root = null;
+ }
+
+ protected override void OnAttachedToWindow()
+ {
+ _root = new EmbeddableControlRoot(_view);
+ _root.Prepare();
+ if(_content != null)
+ {
+ _root.Content = _content;
+ }
+ SendConfigurationChanged(Context?.Resources?.Configuration);
+
+ base.OnAttachedToWindow();
}
public override bool DispatchKeyEvent(KeyEvent? e)
@@ -70,6 +94,8 @@ namespace Avalonia.Android
internal void OnVisibilityChanged(bool isVisible)
{
+ if (_root == null)
+ return;
if (isVisible && _timerSubscription == null)
{
if (AvaloniaLocator.Current.GetService() is ChoreographerTimer timer)
@@ -95,16 +121,17 @@ namespace Avalonia.Android
protected override void OnConfigurationChanged(Configuration? newConfig)
{
base.OnConfigurationChanged(newConfig);
- OnConfigurationChanged();
+ SendConfigurationChanged(newConfig ?? Context?.Resources?.Configuration);
}
- private void OnConfigurationChanged()
+ private void SendConfigurationChanged(Configuration? newConfig)
{
- if (Context is { } context)
+ _view?.InsetsManager?.SetDefaultSystemLightMode(!(newConfig?.UiMode.HasFlag(UiMode.NightYes) ?? false));
+ if (Context is { } context && newConfig is { } config)
{
var settings =
AvaloniaLocator.Current.GetRequiredService() as AndroidPlatformSettings;
- settings?.OnViewConfigurationChanged(context);
+ settings?.OnViewConfigurationChanged(context, config);
}
}
diff --git a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs
index 992d37ed18..ebabc50e5a 100644
--- a/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs
+++ b/src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs
@@ -166,6 +166,11 @@ namespace Avalonia.Android.Platform
return insets;
}
+ internal void SetDefaultSystemLightMode(bool islightMode)
+ {
+ _isDefaultSystemBarLightTheme = islightMode;
+ }
+
private void NotifySafeAreaChanged(Thickness safeAreaPadding)
{
Dispatcher.UIThread.Send(_ => SafeAreaChanged?.Invoke(this, new SafeAreaChangedArgs(safeAreaPadding)));
diff --git a/src/Android/Avalonia.Android/Platform/AndroidPlatformSettings.cs b/src/Android/Avalonia.Android/Platform/AndroidPlatformSettings.cs
index 3963a88203..8ca921c03c 100644
--- a/src/Android/Avalonia.Android/Platform/AndroidPlatformSettings.cs
+++ b/src/Android/Avalonia.Android/Platform/AndroidPlatformSettings.cs
@@ -22,14 +22,14 @@ internal class AndroidPlatformSettings : DefaultPlatformSettings
return _latestValues;
}
- internal void OnViewConfigurationChanged(Context context)
+ internal void OnViewConfigurationChanged(Context context, Configuration configuration)
{
- if (context.Resources?.Configuration is null)
+ if (context.Resources is null)
{
return;
}
- var systemTheme = (context.Resources.Configuration.UiMode & UiMode.NightMask) switch
+ PlatformThemeVariant systemTheme = (configuration.UiMode & UiMode.NightMask) switch
{
UiMode.NightYes => PlatformThemeVariant.Dark,
UiMode.NightNo => PlatformThemeVariant.Light,
@@ -71,7 +71,7 @@ internal class AndroidPlatformSettings : DefaultPlatformSettings
}
finally
{
- array.Recycle();
+ array.Recycle();
}
}
}
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index 79052bf9bd..8a666ecf63 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -282,9 +282,9 @@ namespace Avalonia.Android.Platform.SkiaPlatform
}
}
- public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
+ public void SetFrameThemeVariant(PlatformThemeVariant? themeVariant)
{
- if(_insetsManager != null)
+ if (_insetsManager != null)
{
_insetsManager.SystemBarTheme = themeVariant switch
{
@@ -294,7 +294,16 @@ namespace Avalonia.Android.Platform.SkiaPlatform
};
}
- AppCompatDelegate.DefaultNightMode = themeVariant == PlatformThemeVariant.Light ? AppCompatDelegate.ModeNightNo : AppCompatDelegate.ModeNightYes;
+ AppCompatDelegate.DefaultNightMode = themeVariant == null ? AppCompatDelegate.ModeNightFollowSystem :
+ themeVariant == PlatformThemeVariant.Light ? AppCompatDelegate.ModeNightNo : AppCompatDelegate.ModeNightYes;
+
+ if (AppCompatDelegate.DefaultNightMode == AppCompatDelegate.ModeNightFollowSystem && _view.Context is { } context
+ && context.Resources?.Configuration is { } config)
+ {
+ var settings =
+ AvaloniaLocator.Current.GetRequiredService() as AndroidPlatformSettings;
+ settings?.OnViewConfigurationChanged(context, config);
+ }
}
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => new AcrylicPlatformCompensationLevels(1, 1, 1);
@@ -305,6 +314,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public double Scaling => RenderScaling;
+ internal AndroidInsetsManager? InsetsManager => _insetsManager;
+
public void SetTransparencyLevelHint(IReadOnlyList transparencyLevels)
{
if (_view.Context is not AvaloniaMainActivity activity)
diff --git a/src/Avalonia.Base/Styling/ThemeVariant.cs b/src/Avalonia.Base/Styling/ThemeVariant.cs
index 23bc15dfa7..9a1fb5f931 100644
--- a/src/Avalonia.Base/Styling/ThemeVariant.cs
+++ b/src/Avalonia.Base/Styling/ThemeVariant.cs
@@ -100,11 +100,11 @@ public sealed record ThemeVariant
{
PlatformThemeVariant.Light => Light,
PlatformThemeVariant.Dark => Dark,
- _ => throw new ArgumentOutOfRangeException(nameof(themeVariant), themeVariant, null)
+ _ => Default,
};
}
- public static explicit operator PlatformThemeVariant?(ThemeVariant themeVariant)
+ public static explicit operator PlatformThemeVariant?(ThemeVariant? themeVariant)
{
if (themeVariant == Light)
{
@@ -114,7 +114,7 @@ public sealed record ThemeVariant
{
return PlatformThemeVariant.Dark;
}
- else if (themeVariant.InheritVariant is { } inheritVariant)
+ else if (themeVariant?.InheritVariant is { } inheritVariant)
{
return (PlatformThemeVariant?)inheritVariant;
}
diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs
index e48711efdb..210378b933 100644
--- a/src/Avalonia.Controls/Application.cs
+++ b/src/Avalonia.Controls/Application.cs
@@ -68,6 +68,11 @@ namespace Avalonia
///
public event EventHandler? ActualThemeVariantChanged;
+ static Application()
+ {
+ RequestedThemeVariantProperty.OverrideDefaultValue(ThemeVariant.Default);
+ }
+
///
/// Creates an instance of the class.
///
@@ -364,20 +369,19 @@ namespace Avalonia
if (change.Property == RequestedThemeVariantProperty)
{
- if (change.GetNewValue() is {} themeVariant && themeVariant != ThemeVariant.Default)
+ if (change.GetNewValue() is { } themeVariant)
SetValue(ActualThemeVariantProperty, themeVariant);
- else
- ClearValue(ActualThemeVariantProperty);
}
else if (change.Property == ActualThemeVariantProperty)
{
ActualThemeVariantChanged?.Invoke(this, EventArgs.Empty);
}
}
-
+
private void OnColorValuesChanged(object? sender, PlatformColorValues e)
{
- SetValue(ActualThemeVariantProperty, (ThemeVariant)e.ThemeVariant, BindingPriority.Template);
+ if ((RequestedThemeVariant ?? ThemeVariant.Default) == ThemeVariant.Default)
+ SetCurrentValue(ActualThemeVariantProperty, (ThemeVariant)e.ThemeVariant);
}
}
}
diff --git a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
index 14bb65f0df..5668c017b4 100644
--- a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
+++ b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
@@ -61,7 +61,7 @@ namespace Avalonia.Controls.Embedding.Offscreen
public Action? TransparencyLevelChanged { get; set; }
- public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }
+ public void SetFrameThemeVariant(PlatformThemeVariant? themeVariant) { }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1);
diff --git a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs
index 9b847d71d3..37bcc7a2b2 100644
--- a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs
+++ b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs
@@ -136,6 +136,6 @@ namespace Avalonia.Platform
/// Sets the on the frame if it should be dark or light.
/// Also applies for the mobile status bar.
///
- void SetFrameThemeVariant(PlatformThemeVariant themeVariant);
+ void SetFrameThemeVariant(PlatformThemeVariant? themeVariant);
}
}
diff --git a/src/Avalonia.Controls/ThemeVariantScope.cs b/src/Avalonia.Controls/ThemeVariantScope.cs
index f5ad4b2f94..c88dfa7dd2 100644
--- a/src/Avalonia.Controls/ThemeVariantScope.cs
+++ b/src/Avalonia.Controls/ThemeVariantScope.cs
@@ -15,6 +15,11 @@ namespace Avalonia.Controls
public static readonly StyledProperty RequestedThemeVariantProperty =
ThemeVariant.RequestedThemeVariantProperty.AddOwner();
+ static ThemeVariantScope()
+ {
+ RequestedThemeVariantProperty.OverrideDefaultValue(ThemeVariant.Default);
+ }
+
///
/// Gets or sets the UI theme variant that is used by the control (and its child elements) for resource determination.
/// The UI theme you specify with ThemeVariant can override the app-level ThemeVariant.
diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs
index b4b76085d9..2bc9270dfa 100644
--- a/src/Avalonia.Controls/TopLevel.cs
+++ b/src/Avalonia.Controls/TopLevel.cs
@@ -233,11 +233,6 @@ namespace Avalonia.Controls
impl.TransparencyLevelChanged = HandleTransparencyLevelChanged;
CreatePlatformImplBinding(TransparencyLevelHintProperty, hint => PlatformImpl.SetTransparencyLevelHint(hint ?? Array.Empty()));
- CreatePlatformImplBinding(ActualThemeVariantProperty, variant =>
- {
- variant ??= ThemeVariant.Default;
- PlatformImpl?.SetFrameThemeVariant((PlatformThemeVariant?)variant ?? PlatformThemeVariant.Light);
- });
_keyboardNavigationHandler?.SetOwner(this);
_accessKeyHandler?.SetOwner(this);
@@ -252,6 +247,16 @@ namespace Avalonia.Controls
SetValue(ActualThemeVariantProperty, _applicationThemeHost.ActualThemeVariant, BindingPriority.Template);
_applicationThemeHost.ActualThemeVariantChanged += GlobalActualThemeVariantChanged;
}
+ CreatePlatformImplBinding(ActualThemeVariantProperty, variant =>
+ {
+ if(_applicationThemeHost is AvaloniaObject element)
+ {
+ if (element.GetValue(ThemeVariantScope.RequestedThemeVariantProperty) is { } requestedThemeVariant)
+ variant = requestedThemeVariant == ThemeVariant.Default ? ThemeVariant.Default : variant;
+ }
+ variant ??= ThemeVariant.Default;
+ PlatformImpl?.SetFrameThemeVariant((PlatformThemeVariant?)variant);
+ });
ClientSize = impl.ClientSize;
@@ -878,7 +883,7 @@ namespace Avalonia.Controls
private void GlobalActualThemeVariantChanged(object? sender, EventArgs e)
{
- SetValue(ActualThemeVariantProperty, ((IThemeVariantHost)sender!).ActualThemeVariant, BindingPriority.Template);
+ SetCurrentValue(ActualThemeVariantProperty, ((IThemeVariantHost)sender!).ActualThemeVariant);
}
private void SceneInvalidated(object? sender, SceneInvalidatedEventArgs e)
diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
index e21f4dc843..65045553e0 100644
--- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs
+++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs
@@ -194,7 +194,7 @@ namespace Avalonia.DesignerSupport.Remote
public bool NeedsManagedDecorations => false;
- public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }
+ public void SetFrameThemeVariant(PlatformThemeVariant? themeVariant) { }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1);
public object TryGetFeature(Type featureType) => null;
diff --git a/src/Avalonia.Native/TopLevelImpl.cs b/src/Avalonia.Native/TopLevelImpl.cs
index c7d3305efd..c8fa6254fa 100644
--- a/src/Avalonia.Native/TopLevelImpl.cs
+++ b/src/Avalonia.Native/TopLevelImpl.cs
@@ -148,7 +148,7 @@ internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface
}
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 0, 0);
- public virtual void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
+ public virtual void SetFrameThemeVariant(PlatformThemeVariant? themeVariant)
{
//noop
}
diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs
index 29f6547c9f..ba84d1ad0a 100644
--- a/src/Avalonia.Native/WindowImplBase.cs
+++ b/src/Avalonia.Native/WindowImplBase.cs
@@ -70,9 +70,9 @@ namespace Avalonia.Native
Native?.Resize(clientSize.Width, clientSize.Height, (AvnPlatformResizeReason)reason);
}
- public override void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
+ public override void SetFrameThemeVariant(PlatformThemeVariant? themeVariant)
{
- Native?.SetFrameThemeVariant((AvnPlatformThemeVariant)themeVariant);
+ Native?.SetFrameThemeVariant((AvnPlatformThemeVariant)(themeVariant ?? PlatformThemeVariant.Light));
}
public override void Dispose()
diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs
index eb2c8dea65..963d05e161 100644
--- a/src/Avalonia.X11/X11Window.cs
+++ b/src/Avalonia.X11/X11Window.cs
@@ -1440,7 +1440,7 @@ namespace Avalonia.X11
public WindowTransparencyLevel TransparencyLevel =>
_transparencyHelper?.CurrentLevel ?? WindowTransparencyLevel.None;
- public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }
+ public void SetFrameThemeVariant(PlatformThemeVariant? themeVariant) { }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 0.8, 0.8);
diff --git a/src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs b/src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs
index 9c15d8d1a5..7785b447e1 100644
--- a/src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs
+++ b/src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs
@@ -141,7 +141,7 @@ namespace Avalonia.Browser
public Action? LostFocus { get; set; }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
- public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
+ public void SetFrameThemeVariant(PlatformThemeVariant? themeVariant)
{
// not in the standard, but we potentially can use "apple-mobile-web-app-status-bar-style" for iOS and "theme-color" for android.
}
diff --git a/src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs b/src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
index 11d62d11c6..fc2feb7f74 100644
--- a/src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
+++ b/src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
@@ -429,7 +429,7 @@ namespace Avalonia.Headless
}
- public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
+ public void SetFrameThemeVariant(PlatformThemeVariant? themeVariant)
{
}
diff --git a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
index 2dc7b36b11..c027960cde 100644
--- a/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
+++ b/src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
@@ -78,7 +78,7 @@ using Avalonia.Rendering.Composition;
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
- public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }
+ public void SetFrameThemeVariant(PlatformThemeVariant? themeVariant) { }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1);
public object TryGetFeature(Type featureType) => null;
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 5e85b2f3e7..94a4faa908 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -894,9 +894,9 @@ namespace Avalonia.Win32
}
}
- public unsafe void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
+ public unsafe void SetFrameThemeVariant(PlatformThemeVariant? themeVariant)
{
- _currentThemeVariant = themeVariant;
+ _currentThemeVariant = themeVariant ?? PlatformThemeVariant.Light;
if (Win32Platform.WindowsVersion.Build >= 22000)
{
var pvUseBackdropBrush = themeVariant == PlatformThemeVariant.Dark ? 1 : 0;
diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.cs b/src/iOS/Avalonia.iOS/AvaloniaView.cs
index ff7098251b..cc91d67836 100644
--- a/src/iOS/Avalonia.iOS/AvaloniaView.cs
+++ b/src/iOS/Avalonia.iOS/AvaloniaView.cs
@@ -238,7 +238,7 @@ namespace Avalonia.iOS
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
- public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
+ public void SetFrameThemeVariant(PlatformThemeVariant? themeVariant)
{
#if !TVOS
// TODO adjust status bar depending on full screen mode.
diff --git a/tests/Avalonia.UnitTests/CompositorTestServices.cs b/tests/Avalonia.UnitTests/CompositorTestServices.cs
index 4898604182..709b585dad 100644
--- a/tests/Avalonia.UnitTests/CompositorTestServices.cs
+++ b/tests/Avalonia.UnitTests/CompositorTestServices.cs
@@ -211,7 +211,7 @@ public class CompositorTestServices : IDisposable
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
- public void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
+ public void SetFrameThemeVariant(PlatformThemeVariant? themeVariant)
{
}