فهرست منبع

Implement SystemAccentColors backed by the actual system values

Max Katz 2 سال پیش
والد
کامیت
a09c182e89

+ 0 - 2
samples/ControlCatalog/App.xaml

@@ -26,8 +26,6 @@
           <Color x:Key="CatalogBaseHighColor">#FFFFFFFF</Color>
         </ResourceDictionary>
       </ResourceDictionary.ThemeDictionaries>
-      <Color x:Key="SystemAccentColor">#FF0078D7</Color>
-      <Color x:Key="SystemAccentColorDark1">#FF005A9E</Color>
 
       <!-- Styles attached dynamically depending on current theme (simple or fluent) -->
       <StyleInclude x:Key="DataGridFluent" Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml" />

+ 0 - 48
samples/ControlCatalog/MainView.xaml.cs

@@ -19,13 +19,9 @@ namespace ControlCatalog
 {
     public class MainView : UserControl
     {
-        private readonly IPlatformSettings _platformSettings;
-
         public MainView()
         {
             AvaloniaXamlLoader.Load(this);
-            _platformSettings = AvaloniaLocator.Current.GetRequiredService<IPlatformSettings>();
-            PlatformSettingsOnColorValuesChanged(_platformSettings, _platformSettings.GetColorValues());
             
             var sideBar = this.Get<TabControl>("Sidebar");
 
@@ -141,50 +137,6 @@ namespace ControlCatalog
                     ViewModel.IsSystemBarVisible = insets.IsSystemBarVisible ?? true;
                 };
             }
-
-            _platformSettings.ColorValuesChanged += PlatformSettingsOnColorValuesChanged;
-            PlatformSettingsOnColorValuesChanged(_platformSettings, _platformSettings.GetColorValues());
-        }
-
-        protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
-        {
-            base.OnDetachedFromLogicalTree(e);
-            
-            _platformSettings.ColorValuesChanged -= PlatformSettingsOnColorValuesChanged;
-        }
-
-        private void PlatformSettingsOnColorValuesChanged(object? sender, PlatformColorValues e)
-        {
-            Application.Current!.Resources["SystemAccentColor"] = e.AccentColor1;
-            Application.Current.Resources["SystemAccentColorDark1"] = ChangeColorLuminosity(e.AccentColor1, -0.3);
-            Application.Current.Resources["SystemAccentColorDark2"] = ChangeColorLuminosity(e.AccentColor1, -0.5);
-            Application.Current.Resources["SystemAccentColorDark3"] = ChangeColorLuminosity(e.AccentColor1, -0.7);
-            Application.Current.Resources["SystemAccentColorLight1"] = ChangeColorLuminosity(e.AccentColor1, 0.3);
-            Application.Current.Resources["SystemAccentColorLight2"] = ChangeColorLuminosity(e.AccentColor1, 0.5);
-            Application.Current.Resources["SystemAccentColorLight3"] = ChangeColorLuminosity(e.AccentColor1, 0.7);
-
-            static Color ChangeColorLuminosity(Color color, double luminosityFactor)
-            {
-                var red = (double)color.R;
-                var green = (double)color.G;
-                var blue = (double)color.B;
-
-                if (luminosityFactor < 0)
-                {
-                    luminosityFactor = 1 + luminosityFactor;
-                    red *= luminosityFactor;
-                    green *= luminosityFactor;
-                    blue *= luminosityFactor;
-                }
-                else if (luminosityFactor >= 0)
-                {
-                    red = (255 - red) * luminosityFactor + red;
-                    green = (255 - green) * luminosityFactor + green;
-                    blue = (255 - blue) * luminosityFactor + blue;
-                }
-
-                return new Color(color.A, (byte)red, (byte)green, (byte)blue);
-            }
         }
     }
 }

+ 0 - 12
src/Avalonia.Themes.Fluent/Accents/AccentColors.xaml

@@ -1,12 +0,0 @@
-<ResourceDictionary xmlns="https://github.com/avaloniaui"
-                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
-    <!-- Accent Colours -->
-    <!-- TODO pull accents from system... algorithm to generate shades -->
-    <Color x:Key="SystemAccentColor">#FF0078D7</Color>
-    <Color x:Key="SystemAccentColorDark1">#FF005A9E</Color>
-    <Color x:Key="SystemAccentColorDark2">#FF004275</Color>
-    <Color x:Key="SystemAccentColorDark3">#FF002642</Color>
-    <Color x:Key="SystemAccentColorLight1">#FF429CE3</Color>
-    <Color x:Key="SystemAccentColorLight2">#FF76B9ED</Color>
-    <Color x:Key="SystemAccentColorLight3">#FFA6D8FF</Color>
-</ResourceDictionary>

+ 163 - 0
src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs

@@ -0,0 +1,163 @@
+using System;
+using Avalonia.Controls;
+using Avalonia.Media;
+using Avalonia.Platform;
+using Avalonia.Styling;
+
+namespace Avalonia.Themes.Fluent.Accents;
+
+internal class SystemAccentColors : IResourceProvider
+{
+    public const string AccentKey = "SystemAccentColor";
+    public const string AccentDark1Key = "SystemAccentColorDark1";
+    public const string AccentDark2Key = "SystemAccentColorDark2";
+    public const string AccentDark3Key = "SystemAccentColorDark3";
+    public const string AccentLight1Key = "SystemAccentColorLight1";
+    public const string AccentLight2Key = "SystemAccentColorLight2";
+    public const string AccentLight3Key = "SystemAccentColorLight3";
+    
+    private static readonly Color s_defaultSystemAccentColor = Color.FromRgb(0, 120, 215); 
+    private readonly IPlatformSettings? _platformSettings;
+    private bool _invalidateColors = true;
+    private Color _systemAccentColor;
+    private Color _systemAccentColorDark1, _systemAccentColorDark2, _systemAccentColorDark3;
+    private Color _systemAccentColorLight1, _systemAccentColorLight2, _systemAccentColorLight3;
+
+    public SystemAccentColors()
+    {
+        _platformSettings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
+    }
+    
+    public bool HasResources => true;
+    public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
+    {
+        if (key is string strKey)
+        {
+            if (strKey.Equals(AccentKey, StringComparison.InvariantCulture))
+            {
+                EnsureColors();
+                value = _systemAccentColor;
+                return true;
+            }
+
+            if (strKey.Equals(AccentDark1Key, StringComparison.InvariantCulture))
+            {
+                EnsureColors();
+                value = _systemAccentColorDark1;
+                return true;
+            }
+
+            if (strKey.Equals(AccentDark2Key, StringComparison.InvariantCulture))
+            {
+                EnsureColors();
+                value = _systemAccentColorDark2;
+                return true;
+            }
+
+            if (strKey.Equals(AccentDark3Key, StringComparison.InvariantCulture))
+            {
+                EnsureColors();
+                value = _systemAccentColorDark3;
+                return true;
+            }
+
+            if (strKey.Equals(AccentLight1Key, StringComparison.InvariantCulture))
+            {
+                EnsureColors();
+                value = _systemAccentColorLight1;
+                return true;
+            }
+
+            if (strKey.Equals(AccentLight2Key, StringComparison.InvariantCulture))
+            {
+                EnsureColors();
+                value = _systemAccentColorLight2;
+                return true;
+            }
+
+            if (strKey.Equals(AccentLight3Key, StringComparison.InvariantCulture))
+            {
+                EnsureColors();
+                value = _systemAccentColorLight3;
+                return true;
+            }
+        }
+
+        value = null;
+        return false;
+    }
+
+    public IResourceHost? Owner { get; private set; }
+    public event EventHandler? OwnerChanged;
+    public void AddOwner(IResourceHost owner)
+    {
+        if (Owner != owner)
+        {
+            Owner = owner;
+            OwnerChanged?.Invoke(this, EventArgs.Empty);
+
+            if (_platformSettings is not null)
+            {
+                _platformSettings.ColorValuesChanged += PlatformSettingsOnColorValuesChanged;
+            }
+        }
+    }
+
+    public void RemoveOwner(IResourceHost owner)
+    {
+        if (Owner == owner)
+        {
+            Owner = null;
+            OwnerChanged?.Invoke(this, EventArgs.Empty);
+            
+            if (_platformSettings is not null)
+            {
+                _platformSettings.ColorValuesChanged -= PlatformSettingsOnColorValuesChanged;
+            }
+        }
+    }
+
+    private void EnsureColors()
+    {
+        if (_invalidateColors)
+        {
+            _invalidateColors = false;
+            
+            _systemAccentColor = _platformSettings?.GetColorValues().AccentColor1 ?? s_defaultSystemAccentColor;
+            (_systemAccentColorDark1,_systemAccentColorDark2, _systemAccentColorDark3,
+                    _systemAccentColorLight1, _systemAccentColorLight2, _systemAccentColorLight3) = CalculateAccentShades(_systemAccentColor);
+        }
+    }
+
+    public static (Color d1, Color d2, Color d3, Color l1, Color l2, Color l3) CalculateAccentShades(Color accentColor)
+    {
+        // dark1step = (hslAccent.L - SystemAccentColorDark1.L) * 255
+        const double dark1step = 28.5 / 255d;
+        const double dark2step = 49 / 255d;
+        const double dark3step = 74.5 / 255d;
+        // light1step = (SystemAccentColorLight1.L - hslAccent.L) * 255
+        const double light1step = 39 / 255d;
+        const double light2step = 70 / 255d;
+        const double light3step = 103 / 255d;
+        
+        var hslAccent = accentColor.ToHsl();
+
+        return (
+            // Darker shades
+            new HslColor(hslAccent.A, hslAccent.H, hslAccent.S, hslAccent.L - dark1step).ToRgb(),
+            new HslColor(hslAccent.A, hslAccent.H, hslAccent.S, hslAccent.L - dark2step).ToRgb(),
+            new HslColor(hslAccent.A, hslAccent.H, hslAccent.S, hslAccent.L - dark3step).ToRgb(),
+
+            // Lighter shades
+            new HslColor(hslAccent.A, hslAccent.H, hslAccent.S, hslAccent.L + light1step).ToRgb(),
+            new HslColor(hslAccent.A, hslAccent.H, hslAccent.S, hslAccent.L + light2step).ToRgb(),
+            new HslColor(hslAccent.A, hslAccent.H, hslAccent.S, hslAccent.L + light3step).ToRgb()
+        );
+    }
+    
+    private void PlatformSettingsOnColorValuesChanged(object? sender, PlatformColorValues e)
+    {
+        _invalidateColors = true;
+        Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
+    }
+}

+ 1 - 1
src/Avalonia.Themes.Fluent/FluentTheme.xaml

@@ -4,9 +4,9 @@
   <Styles.Resources>
     <ResourceDictionary>
       <ResourceDictionary.MergedDictionaries>
-        <MergeResourceInclude Source="/Accents/AccentColors.xaml" />
         <MergeResourceInclude Source="/Accents/Base.xaml" />
         <MergeResourceInclude Source="/Accents/FluentControlResources.xaml" />
+        <ResourceInclude Source="/Accents/BaseColorsPalette.xaml" />
       </ResourceDictionary.MergedDictionaries>
       
       <!-- These are not part of MergedDictionaries so we can add or remove them easier -->

+ 0 - 12
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs

@@ -24,7 +24,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
 
         var mergeResourceIncludeType = context.GetAvaloniaTypes().MergeResourceInclude;
         var mergeSourceNodes = new List<XamlPropertyAssignmentNode>();
-        var hasAnyNonMergedResource = false;
         foreach (var manipulationNode in resourceDictionaryManipulation.Children.ToArray())
         {
             void ProcessXamlPropertyAssignmentNode(XamlManipulationGroupNode parent, XamlPropertyAssignmentNode assignmentNode)
@@ -47,17 +46,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer
                                 valueNode);
                         }
                     }
-                    else
-                    {
-                        hasAnyNonMergedResource = true;
-                    }
-
-                    if (hasAnyNonMergedResource && mergeSourceNodes.Any())
-                    {
-                        throw new XamlDocumentParseException(context.CurrentDocument,
-                            "Mix of MergeResourceInclude and other dictionaries inside of the ResourceDictionary.MergedDictionaries is not allowed",
-                            valueNode);
-                    }
                 }
             }