Browse Source

Merge pull request #10802 from AvaloniaUI/system_bar_color

Add SystemBarColor Attached Property to TopLevel
Max Katz 2 years ago
parent
commit
f64aafede3

+ 1 - 1
samples/ControlCatalog.Android/MainActivity.cs

@@ -5,7 +5,7 @@ using Avalonia.Android;
 
 namespace ControlCatalog.Android
 {
-    [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.Main", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)]
+    [Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.Main", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
     public class MainActivity : AvaloniaMainActivity
     {
     }

+ 4 - 0
samples/ControlCatalog.Android/Resources/values-night/colors.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+  <color name="splash_background">#212121</color>
+</resources>

+ 0 - 4
src/Android/Avalonia.Android/AvaloniaMainActivity.cs

@@ -32,10 +32,6 @@ namespace Avalonia.Android
             {
                 lifetime.View = View;
             }
-
-            Window?.ClearFlags(WindowManagerFlags.TranslucentStatus);
-            Window?.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
-
             base.OnCreate(savedInstanceState);
 
             SetContentView(View);

+ 39 - 4
src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs

@@ -2,11 +2,10 @@
 using System.Collections.Generic;
 using Android.OS;
 using Android.Views;
-using AndroidX.AppCompat.App;
 using AndroidX.Core.View;
 using Avalonia.Android.Platform.SkiaPlatform;
 using Avalonia.Controls.Platform;
-using static Avalonia.Controls.Platform.IInsetsManager;
+using Avalonia.Media;
 
 namespace Avalonia.Android.Platform
 {
@@ -20,6 +19,7 @@ namespace Avalonia.Android.Platform
         private bool? _systemUiVisibility;
         private SystemBarTheme? _statusBarTheme;
         private bool? _isDefaultSystemBarLightTheme;
+        private Color? _systemBarColor;
 
         public event EventHandler<SafeAreaChangedArgs> SafeAreaChanged;
 
@@ -36,6 +36,16 @@ namespace Avalonia.Android.Platform
                 }
 
                 WindowCompat.SetDecorFitsSystemWindows(_activity.Window, !value);
+
+                if(value)
+                {
+                    _activity.Window.AddFlags(WindowManagerFlags.TranslucentStatus);
+                    _activity.Window.AddFlags(WindowManagerFlags.TranslucentNavigation);
+                }
+                else
+                {
+                    SystemBarColor = _systemBarColor;
+                }
             }
         }
 
@@ -93,6 +103,7 @@ namespace Avalonia.Android.Platform
         public WindowInsetsCompat OnApplyWindowInsets(View v, WindowInsetsCompat insets)
         {
             NotifySafeAreaChanged(SafeAreaPadding);
+            insets = ViewCompat.OnApplyWindowInsets(v, insets);
             return insets;
         }
 
@@ -146,8 +157,6 @@ namespace Avalonia.Android.Platform
 
                 compat.AppearanceLightStatusBars = value == Controls.Platform.SystemBarTheme.Light;
                 compat.AppearanceLightNavigationBars = value == Controls.Platform.SystemBarTheme.Light;
-
-                AppCompatDelegate.DefaultNightMode = isDefault ? AppCompatDelegate.ModeNightFollowSystem : compat.AppearanceLightStatusBars ? AppCompatDelegate.ModeNightNo : AppCompatDelegate.ModeNightYes;
             }
         }
 
@@ -190,10 +199,36 @@ namespace Avalonia.Android.Platform
             }
         }
 
+        public Color? SystemBarColor
+        {
+            get => _systemBarColor; 
+            set
+            {
+                _systemBarColor = value;
+
+                if (_systemBarColor is { } color && !_displayEdgeToEdge && _activity.Window != null)
+                {
+                    _activity.Window.ClearFlags(WindowManagerFlags.TranslucentStatus);
+                    _activity.Window.ClearFlags(WindowManagerFlags.TranslucentNavigation);
+                    _activity.Window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
+
+                    var androidColor = global::Android.Graphics.Color.Argb(color.A, color.R, color.G, color.B);
+                    _activity.Window.SetStatusBarColor(androidColor);
+
+                    if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
+                    {
+                        // As we can only change the navigation bar's foreground api 26 and newer, we only change the background color if running on those versions
+                        _activity.Window.SetNavigationBarColor(androidColor);
+                    }
+                }
+            }
+        }
+
         internal void ApplyStatusBarState()
         {
             IsSystemBarVisible = _systemUiVisibility;
             SystemBarTheme = _statusBarTheme;
+            SystemBarColor = _systemBarColor;
         }
 
         private class InsetsAnimationCallback : WindowInsetsAnimationCompat.Callback

+ 3 - 0
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@@ -9,6 +9,7 @@ using Android.Runtime;
 using Android.Text;
 using Android.Views;
 using Android.Views.InputMethods;
+using AndroidX.AppCompat.App;
 using Avalonia.Android.Platform.Specific;
 using Avalonia.Android.Platform.Specific.Helpers;
 using Avalonia.Android.Platform.Storage;
@@ -286,6 +287,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
                     _ => null,
                 };
             }
+
+            AppCompatDelegate.DefaultNightMode = themeVariant == PlatformThemeVariant.Light ? AppCompatDelegate.ModeNightNo : AppCompatDelegate.ModeNightYes;
         }
 
         public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => new AcrylicPlatformCompensationLevels(1, 1, 1);

+ 7 - 1
src/Avalonia.Controls/Platform/IInsetsManager.cs

@@ -1,4 +1,5 @@
 using System;
+using Avalonia.Media;
 using Avalonia.Metadata;
 
 #nullable enable
@@ -22,7 +23,12 @@ namespace Avalonia.Controls.Platform
         /// Gets the current safe area padding.
         /// </summary>
         Thickness SafeAreaPadding { get; }
-        
+
+        /// <summary>
+        /// Gets or sets the color of the platform's system bars
+        /// </summary>
+        Color? SystemBarColor { get; set; }
+
         /// <summary>
         /// Occurs when safe area for the current window changes.
         /// </summary>

+ 45 - 1
src/Avalonia.Controls/TopLevel.cs

@@ -87,7 +87,15 @@ namespace Avalonia.Controls
         /// <inheritdoc cref="ThemeVariantScope.RequestedThemeVariantProperty" />
         public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
             ThemeVariantScope.RequestedThemeVariantProperty.AddOwner<Application>();
-        
+
+        /// <summary>
+        /// Defines the SystemBarColor attached property.
+        /// </summary>
+        public static readonly AttachedProperty<SolidColorBrush?> SystemBarColorProperty =
+            AvaloniaProperty.RegisterAttached<TopLevel, Control, SolidColorBrush?>(
+                "SystemBarColor",
+                inherits: true);
+
         /// <summary>
         /// Defines the <see cref="BackRequested"/> event.
         /// </summary>
@@ -124,6 +132,22 @@ namespace Avalonia.Controls
         {
             KeyboardNavigation.TabNavigationProperty.OverrideDefaultValue<TopLevel>(KeyboardNavigationMode.Cycle);
             AffectsMeasure<TopLevel>(ClientSizeProperty);
+
+            SystemBarColorProperty.Changed.AddClassHandler<Control>((view, e) =>
+            {
+                if (e.NewValue is SolidColorBrush colorBrush)
+                {
+                    if (view.Parent is TopLevel tl && tl.InsetsManager is { } insetsManager)
+                    {
+                        insetsManager.SystemBarColor = colorBrush.Color;
+                    }
+
+                    if (view is TopLevel topLevel && topLevel.InsetsManager is { } insets)
+                    {
+                        insets.SystemBarColor = colorBrush.Color;
+                    }
+                }
+            });
         }
 
         /// <summary>
@@ -379,6 +403,26 @@ namespace Avalonia.Controls
             set { SetValue(AccessText.ShowAccessKeyProperty, value); }
         }
 
+        /// <summary>
+        /// Helper for setting the color of the platform's system bars
+        /// </summary>
+        /// <param name="control">The main view attached to the toplevel, or the toplevel</param>
+        /// <param name="color">The color to set</param>
+        public static void SetSystemBarColor(Control control, SolidColorBrush? color)
+        {
+            control.SetValue(SystemBarColorProperty, color);
+        }
+
+        /// <summary>
+        /// Helper for getting the color of the platform's system bars
+        /// </summary>
+        /// <param name="control">The main view attached to the toplevel, or the toplevel</param>
+        /// <returns>The current color of the platform's system bars</returns>
+        public static SolidColorBrush? GetSystemBarColor(Control control)
+        {
+            return control.GetValue(SystemBarColorProperty);
+        }
+
         /// <inheritdoc/>
         double ILayoutRoot.LayoutScaling => PlatformImpl?.RenderScaling ?? 1;
 

+ 1 - 0
src/Avalonia.Themes.Fluent/Controls/EmbeddableControlRoot.xaml

@@ -3,6 +3,7 @@
   <ControlTheme x:Key="{x:Type EmbeddableControlRoot}" TargetType="EmbeddableControlRoot">
     <Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
     <Setter Property="Background" Value="{DynamicResource SystemControlBackgroundAltHighBrush}"/>
+    <Setter Property="TopLevel.SystemBarColor" Value="{DynamicResource SystemControlBackgroundAltHighBrush}"/>
     <Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}"/>
     <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
     <Setter Property="Template">

+ 1 - 0
src/Avalonia.Themes.Fluent/Controls/Window.xaml

@@ -3,6 +3,7 @@
   <ControlTheme x:Key="{x:Type Window}" TargetType="Window">
     <Setter Property="Background" Value="{DynamicResource SystemControlBackgroundAltHighBrush}"/>
     <Setter Property="TransparencyBackgroundFallback" Value="{DynamicResource SystemControlBackgroundAltHighBrush}" />
+    <Setter Property="TopLevel.SystemBarColor" Value="{DynamicResource SystemControlBackgroundAltHighBrush}"/>
     <Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
     <Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}"/>
     <Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />

+ 3 - 0
src/Browser/Avalonia.Browser/BrowserInsetsManager.cs

@@ -5,6 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using Avalonia.Browser.Interop;
 using Avalonia.Controls.Platform;
+using Avalonia.Media;
 using static Avalonia.Controls.Platform.IInsetsManager;
 
 namespace Avalonia.Browser
@@ -37,6 +38,8 @@ namespace Avalonia.Browser
             }
         }
 
+        public Color? SystemBarColor { get; set; }
+
         public void NotifySafeAreaPaddingChanged()
         {
             SafeAreaChanged?.Invoke(this, new SafeAreaChangedArgs(SafeAreaPadding));

+ 3 - 0
src/iOS/Avalonia.iOS/InsetsManager.cs

@@ -1,5 +1,6 @@
 using System;
 using Avalonia.Controls.Platform;
+using Avalonia.Media;
 using UIKit;
 
 namespace Avalonia.iOS;
@@ -80,4 +81,6 @@ internal class InsetsManager : IInsetsManager
     }
 
     public Thickness SafeAreaPadding => _controller?.SafeAreaPadding ?? default;
+
+    public Color? SystemBarColor { get; set; }
 }