Adjust theme options for windows

This commit is contained in:
2dust 2025-01-11 11:23:40 +08:00
parent a176613119
commit 40915b5f98
15 changed files with 72 additions and 80 deletions

View file

@ -102,8 +102,6 @@
public double MainGirdHeight1 { get; set; } public double MainGirdHeight1 { get; set; }
public double MainGirdHeight2 { get; set; } public double MainGirdHeight2 { get; set; }
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical; public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
public bool ColorModeDark { get; set; }
public bool FollowSystemTheme { get; set; }
public string? ColorPrimaryName { get; set; } public string? ColorPrimaryName { get; set; }
public string? CurrentTheme { get; set; } public string? CurrentTheme { get; set; }
public string CurrentLanguage { get; set; } public string CurrentLanguage { get; set; }

View file

@ -64,14 +64,6 @@ namespace v2rayN
BitmapSizeOptions.FromEmptyOptions()); 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() public static void RemoveTunDevice()
{ {
try 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 // Make sure the handle is created before the window is shown
IntPtr hWnd = new WindowInteropHelper(window).EnsureHandle(); IntPtr hWnd = new WindowInteropHelper(window).EnsureHandle();
@ -113,6 +117,14 @@ namespace v2rayN
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize); 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 #region Windows API
[Flags] [Flags]

View file

@ -16,23 +16,17 @@ namespace v2rayN.ViewModels
{ {
private readonly PaletteHelper _paletteHelper = new(); private readonly PaletteHelper _paletteHelper = new();
[Reactive]
public bool ColorModeDark { get; set; }
private IObservableCollection<Swatch> _swatches = new ObservableCollectionExtended<Swatch>(); private IObservableCollection<Swatch> _swatches = new ObservableCollectionExtended<Swatch>();
public IObservableCollection<Swatch> Swatches => _swatches; public IObservableCollection<Swatch> Swatches => _swatches;
[Reactive] [Reactive]
public Swatch SelectedSwatch { get; set; } public Swatch SelectedSwatch { get; set; }
[Reactive] [Reactive] public string CurrentTheme { get; set; }
public int CurrentFontSize { get; set; }
[Reactive] [Reactive] public int CurrentFontSize { get; set; }
public bool FollowSystemTheme { get; set; }
[Reactive] [Reactive] public string CurrentLanguage { get; set; }
public string CurrentLanguage { get; set; }
public ThemeSettingViewModel() public ThemeSettingViewModel()
{ {
@ -62,40 +56,27 @@ namespace v2rayN.ViewModels
private void BindingUI() private void BindingUI()
{ {
ColorModeDark = _config.UiItem.ColorModeDark;
FollowSystemTheme = _config.UiItem.FollowSystemTheme;
_swatches.AddRange(new SwatchesProvider().Swatches); _swatches.AddRange(new SwatchesProvider().Swatches);
if (!_config.UiItem.ColorPrimaryName.IsNullOrEmpty()) if (!_config.UiItem.ColorPrimaryName.IsNullOrEmpty())
{ {
SelectedSwatch = _swatches.FirstOrDefault(t => t.Name == _config.UiItem.ColorPrimaryName); SelectedSwatch = _swatches.FirstOrDefault(t => t.Name == _config.UiItem.ColorPrimaryName);
} }
CurrentTheme = _config.UiItem.CurrentTheme;
CurrentFontSize = _config.UiItem.CurrentFontSize; CurrentFontSize = _config.UiItem.CurrentFontSize;
CurrentLanguage = _config.UiItem.CurrentLanguage; CurrentLanguage = _config.UiItem.CurrentLanguage;
this.WhenAnyValue( this.WhenAnyValue(
x => x.ColorModeDark, x => x.CurrentTheme,
y => y == true) y => y != null && !y.IsNullOrEmpty())
.Subscribe(c => .Subscribe(c =>
{ {
if (_config.UiItem.ColorModeDark != ColorModeDark) if (_config.UiItem.CurrentTheme != CurrentTheme)
{ {
_config.UiItem.ColorModeDark = ColorModeDark; _config.UiItem.CurrentTheme = CurrentTheme;
ModifyTheme(); ModifyTheme();
ConfigHandler.SaveConfig(_config); 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);
}
});
this.WhenAnyValue( this.WhenAnyValue(
x => x.SelectedSwatch, x => x.SelectedSwatch,
@ -147,12 +128,18 @@ namespace v2rayN.ViewModels
public void ModifyTheme() 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; var theme = _paletteHelper.GetTheme();
theme.SetBaseTheme(isDarkTheme ? BaseTheme.Dark : BaseTheme.Light); theme.SetBaseTheme(baseTheme);
_paletteHelper.SetTheme(theme); _paletteHelper.SetTheme(theme);
WindowsUtils.SetDarkBorder(Application.Current.MainWindow, isDarkTheme);
WindowsUtils.SetDarkBorder(Application.Current.MainWindow, CurrentTheme);
} }
private void ModifyFontSize() private void ModifyFontSize()
@ -182,7 +169,7 @@ namespace v2rayN.ViewModels
var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle()); var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle());
hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) => 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; const int WM_SETTINGCHANGE = 0x001A;
if (msg == WM_SETTINGCHANGE) if (msg == WM_SETTINGCHANGE)

View file

@ -34,7 +34,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).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<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -210,7 +210,7 @@ namespace v2rayN.Views
}); });
this.Title = $"{profileItem.ConfigType}"; 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<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -50,7 +50,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).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<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -30,7 +30,7 @@ namespace v2rayN.Views
HotkeyHandler.Instance.IsPause = true; HotkeyHandler.Instance.IsPause = true;
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false; 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(); InitData();
} }

View file

@ -177,7 +177,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); 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<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -58,7 +58,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); 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<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -60,7 +60,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); 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<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -52,7 +52,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); 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<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -38,7 +38,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); 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<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -31,7 +31,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).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<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View file

@ -25,29 +25,20 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsColorMode}" />
<ToggleButton
x:Name="togDarkMode"
Grid.Row="0"
Grid.Column="1"
Margin="{StaticResource Margin8}" />
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsFollowSystemTheme}" /> Text="{x:Static resx:ResUI.TbSettingsTheme}" />
<ToggleButton <ComboBox
x:Name="togFollowSystemTheme" x:Name="cmbCurrentTheme"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin8}" /> Width="120"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@ -59,7 +50,7 @@
x:Name="cmbSwatches" x:Name="cmbSwatches"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="100" Width="120"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
DisplayMemberPath="Name" DisplayMemberPath="Name"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
@ -74,7 +65,7 @@
x:Name="cmbCurrentFontSize" x:Name="cmbCurrentFontSize"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="100" Width="120"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
@ -88,7 +79,7 @@
x:Name="cmbCurrentLanguage" x:Name="cmbCurrentLanguage"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="100" Width="120"
Margin="{StaticResource Margin8}" Margin="{StaticResource Margin8}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</Grid> </Grid>

View file

@ -13,6 +13,11 @@ namespace v2rayN.Views
{ {
InitializeComponent(); InitializeComponent();
ViewModel = new ThemeSettingViewModel(); 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++) for (int i = Global.MinFontSize; i <= Global.MinFontSize + 10; i++)
{ {
@ -26,8 +31,7 @@ namespace v2rayN.Views
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CurrentTheme, v => v.cmbCurrentTheme.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FollowSystemTheme, v => v.togFollowSystemTheme.IsChecked).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).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.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables);