feat: Theme toggler

This commit is contained in:
rabbitism
2024-02-06 19:57:11 +08:00
committed by rabbitism
parent 84ad981297
commit 5f35f574a9
11 changed files with 182 additions and 5 deletions

View File

@@ -0,0 +1,65 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.LogicalTree;
using Avalonia.Styling;
namespace Ursa.Controls;
public abstract class ThemeSelectorBase: TemplatedControl
{
private Application? _application;
private ThemeVariantScope? _scope;
public static readonly StyledProperty<ThemeVariant?> SelectedThemeProperty = AvaloniaProperty.Register<ThemeSelectorBase, ThemeVariant?>(
nameof(SelectedTheme));
public ThemeVariant? SelectedTheme
{
get => GetValue(SelectedThemeProperty);
set => SetValue(SelectedThemeProperty, value);
}
public static readonly StyledProperty<ThemeVariantScope?> TargetScopeProperty =
AvaloniaProperty.Register<ThemeSelectorBase, ThemeVariantScope?>(
nameof(TargetScope));
public ThemeVariantScope? TargetScope
{
get => GetValue(TargetScopeProperty);
set => SetValue(TargetScopeProperty, value);
}
static ThemeSelectorBase()
{
SelectedThemeProperty.Changed.AddClassHandler<ThemeSelectorBase, ThemeVariant?>((s, e) => s.OnSelectedThemeChanged(e));
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
_application = Application.Current;
_scope = this.GetLogicalAncestors().FirstOrDefault(a => a is ThemeVariantScope) as ThemeVariantScope;
}
protected virtual void OnSelectedThemeChanged(AvaloniaPropertyChangedEventArgs<ThemeVariant?> args)
{
ThemeVariant? newTheme = args.NewValue.Value;
if (newTheme is null) return;
if (TargetScope is not null)
{
TargetScope.RequestedThemeVariant = newTheme;
return;
}
if (_scope is not null)
{
_scope.RequestedThemeVariant = newTheme;
return;
}
if (_application is not null)
{
_application.RequestedThemeVariant = newTheme;
return;
}
}
}

View File

@@ -0,0 +1,45 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Styling;
using Ursa.Common;
namespace Ursa.Controls;
[TemplatePart(PART_ThemeToggleButton, typeof(ToggleButton))]
public class ThemeToggleButton: ThemeSelectorBase
{
public const string PART_ThemeToggleButton = "PART_ThemeToggleButton";
/// <summary>
/// This button IsChecked=true means ThemeVariant.Light, IsChecked=false means ThemeVariant.Dark.
/// </summary>
private ToggleButton? _button;
private ThemeVariant? _currentTheme;
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
_currentTheme = this.ActualThemeVariant;
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
EventHelper.UnregisterEvent(ToggleButton.IsCheckedChangedEvent, OnButtonCheckedChanged, _button);
_button = e.NameScope.Get<ToggleButton>(PART_ThemeToggleButton);
EventHelper.RegisterEvent(ToggleButton.IsCheckedChangedEvent, OnButtonCheckedChanged, _button);
PropertyHelper.SetValue(ToggleButton.IsCheckedProperty, _currentTheme == ThemeVariant.Light, _button);
}
private void OnButtonCheckedChanged(object sender, RoutedEventArgs e)
{
var newTheme = (sender as ToggleButton)!.IsChecked;
if (newTheme is null) return;
SelectedTheme = newTheme.Value ? ThemeVariant.Light : ThemeVariant.Dark;
}
}