Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ResourceProvider upgrade #16928

Merged
merged 6 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions api/Avalonia.Themes.Fluent.nupkg.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0007</DiagnosticId>
<Target>T:Avalonia.Themes.Fluent.ColorPaletteResources</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Themes.Fluent.ColorPaletteResources</Target>
<Left>baseline/netstandard2.0/Avalonia.Themes.Fluent.dll</Left>
<Right>target/netstandard2.0/Avalonia.Themes.Fluent.dll</Right>
</Suppression>
</Suppressions>
2 changes: 1 addition & 1 deletion src/Avalonia.Base/Controls/ResourceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Avalonia.Controls;
/// Base implementation for IResourceProvider interface.
/// Includes Owner property management.
/// </summary>
public abstract class ResourceProvider : IResourceProvider
public abstract class ResourceProvider : AvaloniaObject, IResourceProvider
{
private IResourceHost? _owner;

Expand Down
9 changes: 5 additions & 4 deletions src/Avalonia.Themes.Fluent/ColorPaletteResources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ namespace Avalonia.Themes.Fluent;
/// <remarks>
/// This class can only be used in <see cref="FluentTheme.Palettes"/>.
/// </remarks>
public partial class ColorPaletteResources : AvaloniaObject, IResourceNode
public partial class ColorPaletteResources : ResourceProvider
{
private readonly Dictionary<string, Color> _colors = new(StringComparer.InvariantCulture);

public bool HasResources => _hasAccentColor || _colors.Count > 0;
public override bool HasResources => _hasAccentColor || _colors.Count > 0;

public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
public override bool TryGetResource(object key, ThemeVariant? theme, out object? value)
{
if (key is string strKey)
{
Expand Down Expand Up @@ -86,7 +86,7 @@ private Color GetColor(string key)

return default;
}

private void SetColor(string key, Color value)
{
if (value == default)
Expand All @@ -113,6 +113,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
_accentColorLight1, _accentColorLight2, _accentColorLight3) =
SystemAccentColors.CalculateAccentShades(_accentColor);
}
RaiseResourcesChanged();
}
}
}
119 changes: 97 additions & 22 deletions src/Avalonia.Themes.Fluent/ColorPaletteResourcesCollection.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Styling;

namespace Avalonia.Themes.Fluent;

internal class ColorPaletteResourcesCollection : AvaloniaDictionary<ThemeVariant, ColorPaletteResources>, IResourceProvider
internal sealed class ColorPaletteResourcesCollection : ResourceProvider, IDictionary<ThemeVariant, ColorPaletteResources>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of new boilerplate, because C# can't do multiple inheritance.

{
public ColorPaletteResourcesCollection() : base(2)
private readonly AvaloniaDictionary<ThemeVariant, ColorPaletteResources> _inner;

public ColorPaletteResourcesCollection()
{
this.ForEachItem(
_inner = new AvaloniaDictionary<ThemeVariant, ColorPaletteResources>(2);
_inner.ForEachItem(
(key, x) =>
{
if (Owner is not null)
{
x.PropertyChanged += Palette_PropertyChanged;
((IResourceProvider)x).AddOwner(Owner);
}

if (key != ThemeVariant.Dark && key != ThemeVariant.Light)
Expand All @@ -27,21 +33,21 @@ public ColorPaletteResourcesCollection() : base(2)
{
if (Owner is not null)
{
x.PropertyChanged -= Palette_PropertyChanged;
((IResourceProvider)x).RemoveOwner(Owner);
}
},
() => throw new NotSupportedException("Dictionary reset not supported"));
}

public bool HasResources => Count > 0;
public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
public override bool HasResources => _inner.Count > 0;
public override bool TryGetResource(object key, ThemeVariant? theme, out object? value)
{
if (theme == null || theme == ThemeVariant.Default)
{
theme = ThemeVariant.Light;
}

if (base.TryGetValue(theme, out var themePaletteResources)
if (_inner.TryGetValue(theme, out var themePaletteResources)
&& themePaletteResources.TryGetResource(key, theme, out value))
{
return true;
Expand All @@ -51,25 +57,94 @@ public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
return false;
}

public IResourceHost? Owner { get; private set; }
public event EventHandler? OwnerChanged;
public void AddOwner(IResourceHost owner)
protected override void OnAddOwner(IResourceHost owner)
{
Owner = owner;
OwnerChanged?.Invoke(this, EventArgs.Empty);
base.OnAddOwner(owner);
foreach (var palette in _inner.Values)
{
((IResourceProvider)palette).AddOwner(owner);
}
}

public void RemoveOwner(IResourceHost owner)
protected override void OnRemoveOwner(IResourceHost owner)
{
Owner = null;
OwnerChanged?.Invoke(this, EventArgs.Empty);
}

private void Palette_PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == ColorPaletteResources.AccentProperty)
base.OnRemoveOwner(owner);
foreach (var palette in _inner.Values)
{
Owner?.NotifyHostedResourcesChanged(ResourcesChangedEventArgs.Empty);
((IResourceProvider)palette).RemoveOwner(owner);
}
}

IEnumerator<KeyValuePair<ThemeVariant, ColorPaletteResources>> IEnumerable<KeyValuePair<ThemeVariant, ColorPaletteResources>>.GetEnumerator()
{
return _inner.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_inner).GetEnumerator();
}

void ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Add(KeyValuePair<ThemeVariant, ColorPaletteResources> item)
{
((ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>)_inner).Add(item);
}

void ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Clear()
{
_inner.Clear();
}

bool ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Contains(KeyValuePair<ThemeVariant, ColorPaletteResources> item)
{
return ((ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>)_inner).Contains(item);
}

void ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.CopyTo(KeyValuePair<ThemeVariant, ColorPaletteResources>[] array, int arrayIndex)
{
_inner.CopyTo(array, arrayIndex);
}

bool ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Remove(KeyValuePair<ThemeVariant, ColorPaletteResources> item)
{
return ((ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>)_inner).Remove(item);
}

int ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.Count => _inner.Count;

bool ICollection<KeyValuePair<ThemeVariant, ColorPaletteResources>>.IsReadOnly => _inner.IsReadOnly;

void IDictionary<ThemeVariant, ColorPaletteResources>.Add(ThemeVariant key, ColorPaletteResources value)
{
_inner.Add(key, value);
}

bool IDictionary<ThemeVariant, ColorPaletteResources>.ContainsKey(ThemeVariant key)
{
return _inner.ContainsKey(key);
}

bool IDictionary<ThemeVariant, ColorPaletteResources>.Remove(ThemeVariant key)
{
return _inner.Remove(key);
}

bool IDictionary<ThemeVariant, ColorPaletteResources>.TryGetValue(ThemeVariant key,
#if NET6_0_OR_GREATER
[MaybeNullWhen(false)]
#endif
out ColorPaletteResources value)
{
return _inner.TryGetValue(key, out value);
}

ColorPaletteResources IDictionary<ThemeVariant, ColorPaletteResources>.this[ThemeVariant key]
{
get => _inner[key];
set => _inner[key] = value;
}

ICollection<ThemeVariant> IDictionary<ThemeVariant, ColorPaletteResources>.Keys => _inner.Keys;

ICollection<ColorPaletteResources> IDictionary<ThemeVariant, ColorPaletteResources>.Values => _inner.Values;
}
2 changes: 1 addition & 1 deletion src/Avalonia.Themes.Fluent/FluentTheme.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public DensityStyle DensityStyle
get => _densityStyle;
set => SetAndRaise(DensityStyleProperty, ref _densityStyle, value);
}

public IDictionary<ThemeVariant, ColorPaletteResources> Palettes { get; }

protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -991,18 +991,11 @@ private Style WindowStyle()
}
}

public class TrackingResourceProvider : IResourceProvider
public class TrackingResourceProvider : ResourceProvider
{
public IResourceHost Owner { get; private set; }
public bool HasResources => true;
public override bool HasResources => true;
public List<object> RequestedResources { get; } = new List<object>();

public event EventHandler OwnerChanged { add { } remove { } }

public void AddOwner(IResourceHost owner) => Owner = owner;
public void RemoveOwner(IResourceHost owner) => Owner = null;

public bool TryGetResource(object key, ThemeVariant themeVariant, out object value)
public override bool TryGetResource(object key, ThemeVariant themeVariant, out object value)
{
RequestedResources.Add(key);
value = key;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,25 +127,13 @@ private IDisposable StartWithResources(params (string, string)[] assets)
}

// See https://github.com/AvaloniaUI/Avalonia/issues/11172
public class LocaleCollection : IResourceProvider
public class LocaleCollection : ResourceProvider
{
private readonly Dictionary<object, IResourceProvider> _langs = new();

public override bool HasResources => true;

public IResourceHost? Owner { get; private set; }

public bool HasResources => true;

public event EventHandler? OwnerChanged
{
add { }
remove { }
}

public void AddOwner(IResourceHost owner) => Owner = owner;

public void RemoveOwner(IResourceHost owner) => Owner = null;

public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
public override bool TryGetResource(object key, ThemeVariant? theme, out object? value)
{
if (_langs.TryGetValue("English", out var res))
{
Expand Down
Loading