diff --git a/v2rayN/ServiceLib/Models/ConfigItems.cs b/v2rayN/ServiceLib/Models/ConfigItems.cs index 41d34606..ed306fe1 100644 --- a/v2rayN/ServiceLib/Models/ConfigItems.cs +++ b/v2rayN/ServiceLib/Models/ConfigItems.cs @@ -102,8 +102,6 @@ public double MainGirdHeight1 { get; set; } public double MainGirdHeight2 { get; set; } public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical; - public bool ColorModeDark { get; set; } - public bool FollowSystemTheme { get; set; } public string? ColorPrimaryName { get; set; } public string? CurrentTheme { get; set; } public string CurrentLanguage { get; set; } diff --git a/v2rayN/v2rayN/Common/WindowsUtils.cs b/v2rayN/v2rayN/Common/WindowsUtils.cs index 02ec9abb..6a0792d8 100644 --- a/v2rayN/v2rayN/Common/WindowsUtils.cs +++ b/v2rayN/v2rayN/Common/WindowsUtils.cs @@ -64,14 +64,6 @@ namespace v2rayN BitmapSizeOptions.FromEmptyOptions()); } - public static bool IsDarkTheme() - { - using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); - var obj = key?.GetValue("AppsUseLightTheme"); - int.TryParse(obj?.ToString(), out var value); - return value == 0; - } - public static void RemoveTunDevice() { try @@ -103,7 +95,19 @@ namespace v2rayN } } - public static void SetDarkBorder(Window window, bool dark) + public static void SetDarkBorder(Window window, string? theme) + { + var isDark = theme switch + { + nameof(ETheme.Dark) => true, + nameof(ETheme.Light) => false, + _ => IsDarkTheme(), + }; + + SetDarkBorder(window, isDark); + } + + private static void SetDarkBorder(Window window, bool dark) { // Make sure the handle is created before the window is shown IntPtr hWnd = new WindowInteropHelper(window).EnsureHandle(); @@ -113,6 +117,14 @@ namespace v2rayN DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize); } + private static bool IsDarkTheme() + { + using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); + var obj = key?.GetValue("AppsUseLightTheme"); + int.TryParse(obj?.ToString(), out var value); + return value == 0; + } + #region Windows API [Flags] diff --git a/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs index 22eb78ed..35654d3d 100644 --- a/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs @@ -16,23 +16,17 @@ namespace v2rayN.ViewModels { private readonly PaletteHelper _paletteHelper = new(); - [Reactive] - public bool ColorModeDark { get; set; } - private IObservableCollection _swatches = new ObservableCollectionExtended(); public IObservableCollection Swatches => _swatches; [Reactive] public Swatch SelectedSwatch { get; set; } - [Reactive] - public int CurrentFontSize { get; set; } + [Reactive] public string CurrentTheme { get; set; } - [Reactive] - public bool FollowSystemTheme { get; set; } + [Reactive] public int CurrentFontSize { get; set; } - [Reactive] - public string CurrentLanguage { get; set; } + [Reactive] public string CurrentLanguage { get; set; } public ThemeSettingViewModel() { @@ -62,40 +56,27 @@ namespace v2rayN.ViewModels private void BindingUI() { - ColorModeDark = _config.UiItem.ColorModeDark; - FollowSystemTheme = _config.UiItem.FollowSystemTheme; _swatches.AddRange(new SwatchesProvider().Swatches); if (!_config.UiItem.ColorPrimaryName.IsNullOrEmpty()) { SelectedSwatch = _swatches.FirstOrDefault(t => t.Name == _config.UiItem.ColorPrimaryName); } + CurrentTheme = _config.UiItem.CurrentTheme; CurrentFontSize = _config.UiItem.CurrentFontSize; CurrentLanguage = _config.UiItem.CurrentLanguage; this.WhenAnyValue( - x => x.ColorModeDark, - y => y == true) - .Subscribe(c => - { - if (_config.UiItem.ColorModeDark != ColorModeDark) - { - _config.UiItem.ColorModeDark = ColorModeDark; - ModifyTheme(); - ConfigHandler.SaveConfig(_config); - } - }); - - this.WhenAnyValue(x => x.FollowSystemTheme, - y => y == true) - .Subscribe(c => - { - if (_config.UiItem.FollowSystemTheme != FollowSystemTheme) - { - _config.UiItem.FollowSystemTheme = FollowSystemTheme; - ModifyTheme(); - ConfigHandler.SaveConfig(_config); - } - }); + x => x.CurrentTheme, + y => y != null && !y.IsNullOrEmpty()) + .Subscribe(c => + { + if (_config.UiItem.CurrentTheme != CurrentTheme) + { + _config.UiItem.CurrentTheme = CurrentTheme; + ModifyTheme(); + ConfigHandler.SaveConfig(_config); + } + }); this.WhenAnyValue( x => x.SelectedSwatch, @@ -147,12 +128,18 @@ namespace v2rayN.ViewModels public void ModifyTheme() { - var theme = _paletteHelper.GetTheme(); + var baseTheme = CurrentTheme switch + { + nameof(ETheme.Dark) => BaseTheme.Dark, + nameof(ETheme.Light) => BaseTheme.Light, + _ => BaseTheme.Inherit, + }; - var isDarkTheme = FollowSystemTheme ? WindowsUtils.IsDarkTheme() : ColorModeDark; - theme.SetBaseTheme(isDarkTheme ? BaseTheme.Dark : BaseTheme.Light); + var theme = _paletteHelper.GetTheme(); + theme.SetBaseTheme(baseTheme); _paletteHelper.SetTheme(theme); - WindowsUtils.SetDarkBorder(Application.Current.MainWindow, isDarkTheme); + + WindowsUtils.SetDarkBorder(Application.Current.MainWindow, CurrentTheme); } private void ModifyFontSize() @@ -182,7 +169,7 @@ namespace v2rayN.ViewModels var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle()); hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) => { - if (config.UiItem.FollowSystemTheme) + if (config.UiItem.CurrentTheme == nameof(ETheme.FollowSystem)) { const int WM_SETTINGCHANGE = 0x001A; if (msg == WM_SETTINGCHANGE) diff --git a/v2rayN/v2rayN/Views/AddServer2Window.xaml.cs b/v2rayN/v2rayN/Views/AddServer2Window.xaml.cs index b71c145e..efefab6e 100644 --- a/v2rayN/v2rayN/Views/AddServer2Window.xaml.cs +++ b/v2rayN/v2rayN/Views/AddServer2Window.xaml.cs @@ -34,7 +34,7 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables); }); - WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); } private async Task UpdateViewHandler(EViewAction action, object? obj) diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs b/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs index 11c68424..0d147e10 100644 --- a/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml.cs @@ -210,7 +210,7 @@ namespace v2rayN.Views }); this.Title = $"{profileItem.ConfigType}"; - WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); } private async Task UpdateViewHandler(EViewAction action, object? obj) diff --git a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs index 56a8242d..06955269 100644 --- a/v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/DNSSettingWindow.xaml.cs @@ -50,7 +50,7 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables); }); - WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); } private async Task UpdateViewHandler(EViewAction action, object? obj) diff --git a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs index 185a54d0..6a020a90 100644 --- a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs @@ -30,7 +30,7 @@ namespace v2rayN.Views HotkeyHandler.Instance.IsPause = true; this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false; - WindowsUtils.SetDarkBorder(this, _config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : _config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, _config.UiItem.CurrentTheme); InitData(); } diff --git a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs index d1c859d5..2e52d20a 100644 --- a/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/OptionSettingWindow.xaml.cs @@ -177,7 +177,7 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); }); - WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); } private async Task UpdateViewHandler(EViewAction action, object? obj) diff --git a/v2rayN/v2rayN/Views/RoutingRuleDetailsWindow.xaml.cs b/v2rayN/v2rayN/Views/RoutingRuleDetailsWindow.xaml.cs index 5b6cca4c..b49add72 100644 --- a/v2rayN/v2rayN/Views/RoutingRuleDetailsWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/RoutingRuleDetailsWindow.xaml.cs @@ -58,7 +58,7 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); }); - WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); } private async Task UpdateViewHandler(EViewAction action, object? obj) diff --git a/v2rayN/v2rayN/Views/RoutingRuleSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/RoutingRuleSettingWindow.xaml.cs index 4340b2f3..3f66daaf 100644 --- a/v2rayN/v2rayN/Views/RoutingRuleSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/RoutingRuleSettingWindow.xaml.cs @@ -60,7 +60,7 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); }); - WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); } private async Task UpdateViewHandler(EViewAction action, object? obj) diff --git a/v2rayN/v2rayN/Views/RoutingSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/RoutingSettingWindow.xaml.cs index 39086ec4..74ae14ec 100644 --- a/v2rayN/v2rayN/Views/RoutingSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/RoutingSettingWindow.xaml.cs @@ -52,7 +52,7 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); }); - WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); } private async Task UpdateViewHandler(EViewAction action, object? obj) diff --git a/v2rayN/v2rayN/Views/SubEditWindow.xaml.cs b/v2rayN/v2rayN/Views/SubEditWindow.xaml.cs index 02619d27..2bf457fe 100644 --- a/v2rayN/v2rayN/Views/SubEditWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/SubEditWindow.xaml.cs @@ -38,7 +38,7 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); }); - WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); } private async Task UpdateViewHandler(EViewAction action, object? obj) diff --git a/v2rayN/v2rayN/Views/SubSettingWindow.xaml.cs b/v2rayN/v2rayN/Views/SubSettingWindow.xaml.cs index 96eaf2f8..a326354f 100644 --- a/v2rayN/v2rayN/Views/SubSettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/SubSettingWindow.xaml.cs @@ -31,7 +31,7 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables); }); - WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); + WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme); } private async Task UpdateViewHandler(EViewAction action, object? obj) diff --git a/v2rayN/v2rayN/Views/ThemeSettingView.xaml b/v2rayN/v2rayN/Views/ThemeSettingView.xaml index 059c3414..d51479ef 100644 --- a/v2rayN/v2rayN/Views/ThemeSettingView.xaml +++ b/v2rayN/v2rayN/Views/ThemeSettingView.xaml @@ -25,29 +25,20 @@ - - - + + Width="120" + Margin="{StaticResource Margin8}" + Style="{StaticResource DefComboBox}" /> @@ -74,7 +65,7 @@ x:Name="cmbCurrentFontSize" Grid.Row="3" Grid.Column="1" - Width="100" + Width="120" Margin="{StaticResource Margin8}" Style="{StaticResource DefComboBox}" /> @@ -88,7 +79,7 @@ x:Name="cmbCurrentLanguage" Grid.Row="4" Grid.Column="1" - Width="100" + Width="120" Margin="{StaticResource Margin8}" Style="{StaticResource DefComboBox}" /> diff --git a/v2rayN/v2rayN/Views/ThemeSettingView.xaml.cs b/v2rayN/v2rayN/Views/ThemeSettingView.xaml.cs index 179cb843..2cc80f3b 100644 --- a/v2rayN/v2rayN/Views/ThemeSettingView.xaml.cs +++ b/v2rayN/v2rayN/Views/ThemeSettingView.xaml.cs @@ -13,6 +13,11 @@ namespace v2rayN.Views { InitializeComponent(); ViewModel = new ThemeSettingViewModel(); + foreach (ETheme it in Enum.GetValues(typeof(ETheme))) + { + if ((int)it > 2) continue; + cmbCurrentTheme.Items.Add(it.ToString()); + } for (int i = Global.MinFontSize; i <= Global.MinFontSize + 10; i++) { @@ -26,8 +31,7 @@ namespace v2rayN.Views this.WhenActivated(disposables => { - this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.FollowSystemTheme, v => v.togFollowSystemTheme.IsChecked).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.CurrentTheme, v => v.cmbCurrentTheme.SelectedValue).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables);