diff --git a/LightBulb.Core.Tests/LightBulb.Core.Tests.csproj b/LightBulb.Core.Tests/LightBulb.Core.Tests.csproj index b829b6d..ba4c9c8 100644 --- a/LightBulb.Core.Tests/LightBulb.Core.Tests.csproj +++ b/LightBulb.Core.Tests/LightBulb.Core.Tests.csproj @@ -11,12 +11,12 @@ - + - - + + diff --git a/LightBulb.Core/LightBulb.Core.csproj b/LightBulb.Core/LightBulb.Core.csproj index 9cb25d0..35a9f20 100644 --- a/LightBulb.Core/LightBulb.Core.csproj +++ b/LightBulb.Core/LightBulb.Core.csproj @@ -1,7 +1,7 @@ - + diff --git a/LightBulb.PlatformInterop/LightBulb.PlatformInterop.csproj b/LightBulb.PlatformInterop/LightBulb.PlatformInterop.csproj index 5e9e81f..a37e6f7 100644 --- a/LightBulb.PlatformInterop/LightBulb.PlatformInterop.csproj +++ b/LightBulb.PlatformInterop/LightBulb.PlatformInterop.csproj @@ -1,7 +1,7 @@  - + \ No newline at end of file diff --git a/LightBulb/App.axaml b/LightBulb/App.axaml index 13df945..820c0ee 100644 --- a/LightBulb/App.axaml +++ b/LightBulb/App.axaml @@ -4,29 +4,42 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:dialogHostAvalonia="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia" xmlns:framework="clr-namespace:LightBulb.Framework" - xmlns:sys="using:System" xmlns:materialAssists="clr-namespace:Material.Styles.Assists;assembly=Material.Styles" - xmlns:materialControls="clr-namespace:Material.Styles.Controls;assembly=Material.Styles" xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" - xmlns:materialStyles="clr-namespace:Material.Styles.Themes;assembly=Material.Styles"> + xmlns:materialStyles="clr-namespace:Material.Styles.Themes;assembly=Material.Styles" + ActualThemeVariantChanged="Application_OnActualThemeVariantChanged"> - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - @@ -150,6 +120,15 @@ + + + + + + + + + + - - - - - false - - - - - true - - diff --git a/LightBulb/App.axaml.cs b/LightBulb/App.axaml.cs index 10f1f12..4adbe50 100644 --- a/LightBulb/App.axaml.cs +++ b/LightBulb/App.axaml.cs @@ -8,7 +8,6 @@ using Avalonia.Platform; using Avalonia.Threading; using LightBulb.Framework; -using LightBulb.Models; using LightBulb.Services; using LightBulb.Utils; using LightBulb.Utils.Extensions; @@ -27,8 +26,8 @@ public class App : Application, IDisposable private readonly DisposableCollector _eventRoot = new(); private readonly ServiceProvider _services; - private readonly MainViewModel _mainViewModel; private readonly SettingsService _settingsService; + private readonly MainViewModel _mainViewModel; public App() { @@ -58,30 +57,29 @@ public App() services.AddTransient(); _services = services.BuildServiceProvider(true); - _mainViewModel = _services.GetRequiredService().CreateMainViewModel(); _settingsService = _services.GetRequiredService(); + _mainViewModel = _services.GetRequiredService().CreateMainViewModel(); - // Load settings - _settingsService.Load(); - - _settingsService.WatchProperty( - o => o.Theme, - () => - { - if (PlatformSettings is IPlatformSettings settings) + // Re-initialize the theme when the user changes it + _eventRoot.Add( + _settingsService.WatchProperty( + o => o.Theme, + () => { - SetupTheme(settings.GetColorValues()); - } - }, - false + RequestedThemeVariant = _settingsService.Theme switch + { + ThemeVariant.Light => Avalonia.Styling.ThemeVariant.Light, + ThemeVariant.Dark => Avalonia.Styling.ThemeVariant.Dark, + _ => Avalonia.Styling.ThemeVariant.Default + }; + + InitializeTheme(); + }, + false + ) ); - } - public override void Initialize() - { - AvaloniaXamlLoader.Load(this); - - // Tray icon does not support binding so we use this hack to update its tooltip + // Tray icon does not support binding so we use this hack to synchronize its tooltip _eventRoot.Add( _mainViewModel.Dashboard.WatchProperties( [o => o.IsActive, o => o.CurrentConfiguration], @@ -102,59 +100,52 @@ public override void Initialize() if (TrayIcon.GetIcons(this)?.FirstOrDefault() is { } trayIcon) trayIcon.ToolTipText = tooltip; }); - } + }, + false ) ); } - public override void OnFrameworkInitializationCompleted() + public override void Initialize() { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) - desktopLifetime.MainWindow = new MainView { DataContext = _mainViewModel }; - - base.OnFrameworkInitializationCompleted(); + base.Initialize(); - if (PlatformSettings is IPlatformSettings settings) - { - settings.ColorValuesChanged += PlatformSettings_ColorValuesChanged; - SetupTheme(settings.GetColorValues()); - } + AvaloniaXamlLoader.Load(this); } - private void PlatformSettings_ColorValuesChanged(object? sender, PlatformColorValues colors) + private void InitializeTheme() { - SetupTheme(colors); + var actualTheme = RequestedThemeVariant?.Key switch + { + "Light" => PlatformThemeVariant.Light, + "Dark" => PlatformThemeVariant.Dark, + _ => PlatformSettings?.GetColorValues().ThemeVariant ?? PlatformThemeVariant.Light + }; + + this.LocateMaterialTheme().CurrentTheme = + actualTheme == PlatformThemeVariant.Light + ? Theme.Create(Theme.Light, Color.Parse("#343838"), Color.Parse("#F9A825")) + : Theme.Create(Theme.Dark, Color.Parse("#E8E8E8"), Color.Parse("#F9A825")); } - private void SetupTheme(PlatformColorValues colors) + public override void OnFrameworkInitializationCompleted() { - var themeMode = _settingsService.Theme; - if (themeMode == ThemeMode.System) - { - themeMode = - colors.ThemeVariant == PlatformThemeVariant.Dark ? ThemeMode.Dark : ThemeMode.Light; - } + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) + desktopLifetime.MainWindow = new MainView { DataContext = _mainViewModel }; - if (themeMode == ThemeMode.Dark) - { - RequestedThemeVariant = Avalonia.Styling.ThemeVariant.Dark; - this.LocateMaterialTheme().CurrentTheme = Theme.Create( - Theme.Dark, - Color.Parse("#202222"), - Color.Parse("#F9A825") - ); - } - else - { - RequestedThemeVariant = Avalonia.Styling.ThemeVariant.Light; - this.LocateMaterialTheme().CurrentTheme = Theme.Create( - Theme.Light, - Color.Parse("#343838"), - Color.Parse("#F9A825") - ); - } + base.OnFrameworkInitializationCompleted(); + + // Set up custom theme colors + InitializeTheme(); + + // Load settings + _settingsService.Load(); } + private void Application_OnActualThemeVariantChanged(object? sender, EventArgs args) => + // Re-initialize the theme when the system theme changes + InitializeTheme(); + private void TrayIcon_OnClicked(object? sender, EventArgs args) => this.TryFocusMainWindow(); private void ShowSettingsMenuItem_OnClick(object? sender, EventArgs args) diff --git a/LightBulb/Framework/ThemeVariant.cs b/LightBulb/Framework/ThemeVariant.cs new file mode 100644 index 0000000..4a062ad --- /dev/null +++ b/LightBulb/Framework/ThemeVariant.cs @@ -0,0 +1,8 @@ +namespace LightBulb.Framework; + +public enum ThemeVariant +{ + System, + Light, + Dark +} diff --git a/LightBulb/LightBulb.csproj b/LightBulb/LightBulb.csproj index c13291a..00c8e75 100644 --- a/LightBulb/LightBulb.csproj +++ b/LightBulb/LightBulb.csproj @@ -19,14 +19,14 @@ - + - + - - + + diff --git a/LightBulb/Models/ThemeMode.cs b/LightBulb/Models/ThemeMode.cs deleted file mode 100644 index 82d71c5..0000000 --- a/LightBulb/Models/ThemeMode.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace LightBulb.Models; - -/// -/// Describes the application's theme mode. -/// -public enum ThemeMode -{ - /// - /// Use the light theme - /// - Light, - - /// - /// Use the dark theme - /// - Dark, - - /// - /// Use whichever theme is specified by system settings - /// - System -} diff --git a/LightBulb/Services/SettingsService.cs b/LightBulb/Services/SettingsService.cs index c99f795..e85a80b 100644 --- a/LightBulb/Services/SettingsService.cs +++ b/LightBulb/Services/SettingsService.cs @@ -5,6 +5,7 @@ using Cogwheel; using CommunityToolkit.Mvvm.ComponentModel; using LightBulb.Core; +using LightBulb.Framework; using LightBulb.Models; using LightBulb.PlatformInterop; using LightBulb.Utils; @@ -85,11 +86,11 @@ public partial class SettingsService() : SettingsBase(GetFilePath()) // Advanced [ObservableProperty] - [property: JsonIgnore] // comes from registry - private bool _isAutoStartEnabled; + private ThemeVariant _theme; [ObservableProperty] - private ThemeMode _theme = ThemeMode.System; + [property: JsonIgnore] // comes from registry + private bool _isAutoStartEnabled; [ObservableProperty] private bool _isAutoUpdateEnabled = true; diff --git a/LightBulb/ViewModels/Components/Settings/AdvancedSettingsTabViewModel.cs b/LightBulb/ViewModels/Components/Settings/AdvancedSettingsTabViewModel.cs index 059306f..7cb85f9 100644 --- a/LightBulb/ViewModels/Components/Settings/AdvancedSettingsTabViewModel.cs +++ b/LightBulb/ViewModels/Components/Settings/AdvancedSettingsTabViewModel.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using LightBulb.Models; +using LightBulb.Framework; using LightBulb.Services; namespace LightBulb.ViewModels.Components.Settings; @@ -8,20 +8,20 @@ namespace LightBulb.ViewModels.Components.Settings; public class AdvancedSettingsTabViewModel(SettingsService settingsService) : SettingsTabViewModelBase(settingsService, 2, "Advanced") { - public bool IsAutoStartEnabled - { - get => SettingsService.IsAutoStartEnabled; - set => SettingsService.IsAutoStartEnabled = value; - } - - public IReadOnlyList ThemeArray { get; } = Enum.GetValues(); + public IReadOnlyList AvailableThemes { get; } = Enum.GetValues(); - public ThemeMode Theme + public ThemeVariant Theme { get => SettingsService.Theme; set => SettingsService.Theme = value; } + public bool IsAutoStartEnabled + { + get => SettingsService.IsAutoStartEnabled; + set => SettingsService.IsAutoStartEnabled = value; + } + public bool IsAutoUpdateEnabled { get => SettingsService.IsAutoUpdateEnabled; diff --git a/LightBulb/Views/Components/DashboardView.axaml b/LightBulb/Views/Components/DashboardView.axaml index ad06e36..349bab7 100644 --- a/LightBulb/Views/Components/DashboardView.axaml +++ b/LightBulb/Views/Components/DashboardView.axaml @@ -12,39 +12,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + ItemsSource="{Binding AvailableThemes}" + SelectedItem="{Binding Theme}" /> - - - - - - - - - - - + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + \ No newline at end of file diff --git a/LightBulb/Views/Components/Settings/ApplicationWhitelistSettingsTabView.axaml b/LightBulb/Views/Components/Settings/ApplicationWhitelistSettingsTabView.axaml index 22a0d90..a97a14b 100644 --- a/LightBulb/Views/Components/Settings/ApplicationWhitelistSettingsTabView.axaml +++ b/LightBulb/Views/Components/Settings/ApplicationWhitelistSettingsTabView.axaml @@ -42,8 +42,7 @@ HorizontalAlignment="Right" VerticalAlignment="Center" IsChecked="{Binding IsApplicationWhitelistEnabled}" - ToolTip.Tip="Pause LightBulb when one of the selected applications is in the foreground" - Classes.accent="{DynamicResource UseAccentControls}" /> + ToolTip.Tip="Pause LightBulb when one of the selected applications is in the foreground" /> @@ -70,8 +69,7 @@ + IsHitTestVisible="False" /> diff --git a/LightBulb/Views/Components/Settings/GeneralSettingsTabView.axaml b/LightBulb/Views/Components/Settings/GeneralSettingsTabView.axaml index d1db410..621f466 100644 --- a/LightBulb/Views/Components/Settings/GeneralSettingsTabView.axaml +++ b/LightBulb/Views/Components/Settings/GeneralSettingsTabView.axaml @@ -17,8 +17,7 @@ MinWidth="24" HorizontalAlignment="Right" DockPanel.Dock="Right" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}"> + Theme="{DynamicResource CompactTextBox}"> @@ -32,8 +31,7 @@ Minimum="2500" SmallChange="100" TickFrequency="20" - Value="{Binding DayTemperature}" - Classes.accent="{DynamicResource UseAccentControls}" /> + Value="{Binding DayTemperature}" /> @@ -42,8 +40,7 @@ MinWidth="24" HorizontalAlignment="Right" DockPanel.Dock="Right" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}"> + Theme="{DynamicResource CompactTextBox}"> @@ -57,8 +54,7 @@ Minimum="2500" SmallChange="100" TickFrequency="20" - Value="{Binding NightTemperature}" - Classes.accent="{DynamicResource UseAccentControls}" /> + Value="{Binding NightTemperature}" /> @@ -80,8 +76,7 @@ MinWidth="24" HorizontalAlignment="Right" DockPanel.Dock="Right" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}"> + Theme="{DynamicResource CompactTextBox}"> @@ -95,8 +90,7 @@ Minimum="0.1" SmallChange="0.01" TickFrequency="0.01" - Value="{Binding DayBrightness}" - Classes.accent="{DynamicResource UseAccentControls}" /> + Value="{Binding DayBrightness}" /> @@ -118,8 +112,7 @@ MinWidth="24" HorizontalAlignment="Right" DockPanel.Dock="Right" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}"> + Theme="{DynamicResource CompactTextBox}"> @@ -133,8 +126,7 @@ Minimum="0.1" SmallChange="0.01" TickFrequency="0.01" - Value="{Binding NightBrightness}" - Classes.accent="{DynamicResource UseAccentControls}" /> + Value="{Binding NightBrightness}" /> @@ -143,8 +135,7 @@ MinWidth="48" HorizontalAlignment="Right" DockPanel.Dock="Right" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}"> + Theme="{DynamicResource CompactTextBox}"> @@ -156,8 +147,7 @@ Maximum="3" Minimum="0" SmallChange="0.08" - Value="{Binding ConfigurationTransitionDuration, Converter={x:Static converters:TimeSpanToHoursDoubleConverter.Instance}}" - Classes.accent="{DynamicResource UseAccentControls}" /> + Value="{Binding ConfigurationTransitionDuration, Converter={x:Static converters:TimeSpanToHoursDoubleConverter.Instance}}" /> @@ -166,8 +156,7 @@ MinWidth="24" HorizontalAlignment="Right" DockPanel.Dock="Right" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}"> + Theme="{DynamicResource CompactTextBox}"> @@ -179,7 +168,6 @@ Maximum="1" Minimum="0" SmallChange="0.01" - Value="{Binding ConfigurationTransitionOffset}" - Classes.accent="{DynamicResource UseAccentControls}" /> + Value="{Binding ConfigurationTransitionOffset}" /> \ No newline at end of file diff --git a/LightBulb/Views/Components/Settings/LocationSettingsTabView.axaml b/LightBulb/Views/Components/Settings/LocationSettingsTabView.axaml index 86edeb4..7a55f83 100644 --- a/LightBulb/Views/Components/Settings/LocationSettingsTabView.axaml +++ b/LightBulb/Views/Components/Settings/LocationSettingsTabView.axaml @@ -18,15 +18,13 @@ Content="Manual" DockPanel.Dock="Left" IsChecked="{Binding IsManualSunriseSunsetEnabled}" - ToolTip.Tip="Configure sunrise and sunset manually" - Classes.accent="{DynamicResource UseAccentControls}" /> + ToolTip.Tip="Configure sunrise and sunset manually" /> + ToolTip.Tip="Configure your location and use it to automatically calculate the sunrise and sunset times" /> @@ -41,8 +39,7 @@ MinWidth="24" HorizontalAlignment="Right" DockPanel.Dock="Right" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}"> + Theme="{DynamicResource CompactTextBox}"> @@ -54,8 +51,7 @@ Maximum="23.99999" Minimum="0" SmallChange="0.25" - Value="{Binding ManualSunrise, Converter={x:Static converters:TimeOnlyToHoursDoubleConverter.Instance}}" - Classes.accent="{DynamicResource UseAccentControls}" /> + Value="{Binding ManualSunrise, Converter={x:Static converters:TimeOnlyToHoursDoubleConverter.Instance}}" /> @@ -64,8 +60,7 @@ MinWidth="24" HorizontalAlignment="Right" DockPanel.Dock="Right" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}"> + Theme="{DynamicResource CompactTextBox}"> @@ -77,8 +72,7 @@ Maximum="23.99999" Minimum="0" SmallChange="0.25" - Value="{Binding ManualSunset, Converter={x:Static converters:TimeOnlyToHoursDoubleConverter.Instance}}" - Classes.accent="{DynamicResource UseAccentControls}" /> + Value="{Binding ManualSunset, Converter={x:Static converters:TimeOnlyToHoursDoubleConverter.Instance}}" /> @@ -110,8 +104,7 @@ VerticalAlignment="Center" IsEnabled="{Binding !IsBusy}" Text="{Binding LocationQuery}" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}"> + Theme="{DynamicResource CompactTextBox}"> diff --git a/LightBulb/Views/Controls/HotKeyTextBox.axaml b/LightBulb/Views/Controls/HotKeyTextBox.axaml index 2c81dd7..7777ecf 100644 --- a/LightBulb/Views/Controls/HotKeyTextBox.axaml +++ b/LightBulb/Views/Controls/HotKeyTextBox.axaml @@ -8,6 +8,5 @@ IsUndoEnabled="False" Text="{Binding $parent[UserControl].HotKey, Mode=OneWay}" TextAlignment="Center" - Theme="{DynamicResource CompactTextBox}" - Classes.accent="{DynamicResource UseAccentControls}" /> + Theme="{DynamicResource CompactTextBox}" /> diff --git a/LightBulb/Views/Dialogs/SettingsView.axaml b/LightBulb/Views/Dialogs/SettingsView.axaml index 9412346..05facd5 100644 --- a/LightBulb/Views/Dialogs/SettingsView.axaml +++ b/LightBulb/Views/Dialogs/SettingsView.axaml @@ -16,8 +16,8 @@ - + Background="{DynamicResource MaterialDarkBackgroundBrush}"> + @@ -45,11 +45,13 @@ - + diff --git a/LightBulb/Views/MainView.axaml b/LightBulb/Views/MainView.axaml index 0d8b759..c137fd9 100644 --- a/LightBulb/Views/MainView.axaml +++ b/LightBulb/Views/MainView.axaml @@ -21,7 +21,10 @@ - + - + ToolTip.Tip="Toggle LightBulb on/off"> @@ -68,7 +71,7 @@ Margin="8,1,0,0" VerticalAlignment="Center" FontSize="16" - Foreground="{DynamicResource MaterialPrimaryMidForegroundBrush}"> + Foreground="{DynamicResource MaterialDarkForegroundBrush}">