diff --git a/v2rayN/v2rayN/App.xaml b/v2rayN/v2rayN/App.xaml index ddb2a4ba..03af3be5 100644 --- a/v2rayN/v2rayN/App.xaml +++ b/v2rayN/v2rayN/App.xaml @@ -20,6 +20,8 @@ 13 14 11 + + + /// 查找类似 Follow System Theme 的本地化字符串。 + /// + public static string TbSettingsFollowSystemTheme { + get { + return ResourceManager.GetString("TbSettingsFollowSystemTheme", resourceCulture); + } + } + /// /// 查找类似 FontSize 的本地化字符串。 /// diff --git a/v2rayN/v2rayN/Resx/ResUI.resx b/v2rayN/v2rayN/Resx/ResUI.resx index 1625e449..5b513251 100644 --- a/v2rayN/v2rayN/Resx/ResUI.resx +++ b/v2rayN/v2rayN/Resx/ResUI.resx @@ -505,6 +505,9 @@ Dark Mode + + Follow System Theme + Language(Restart) diff --git a/v2rayN/v2rayN/Resx/ResUI.ru.resx b/v2rayN/v2rayN/Resx/ResUI.ru.resx index 99be3632..30e796ab 100644 --- a/v2rayN/v2rayN/Resx/ResUI.ru.resx +++ b/v2rayN/v2rayN/Resx/ResUI.ru.resx @@ -505,6 +505,9 @@ Тёмный режим + + следить за системной темой + Язык (требуется перезапуск) diff --git a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx index 0363c124..8de8f034 100644 --- a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx @@ -505,6 +505,9 @@ 暗黑模式 + + 是否跟随系统主题 + 语言(重启) diff --git a/v2rayN/v2rayN/Tool/Utils.cs b/v2rayN/v2rayN/Tool/Utils.cs index e440c3ff..d65bebae 100644 --- a/v2rayN/v2rayN/Tool/Utils.cs +++ b/v2rayN/v2rayN/Tool/Utils.cs @@ -1047,6 +1047,13 @@ namespace v2rayN DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize); } + public static bool IsLightTheme() + { + using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); + var value = key?.GetValue("AppsUseLightTheme"); + return value is int i && i > 0; + } + #endregion 杂项 #region TempPath diff --git a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs index 7a250e96..83fe9a7d 100644 --- a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs @@ -12,8 +12,10 @@ using System.Drawing; using System.IO; using System.Reactive; using System.Reactive.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Windows; +using System.Windows.Interop; using System.Windows.Media; using v2rayN.Base; using v2rayN.Handler; @@ -237,6 +239,9 @@ namespace v2rayN.ViewModels [Reactive] public int CurrentFontSize { get; set; } + [Reactive] + public bool FollowSystemTheme { get; set; } + [Reactive] public string CurrentLanguage { get; set; } @@ -244,7 +249,7 @@ namespace v2rayN.ViewModels #region Init - public MainWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue, Action updateView) + public MainWindowViewModel(ISnackbarMessageQueue snackbarMessageQueue, Action updateView,HwndSource hwndSource) { _updateView = updateView; ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false); @@ -309,7 +314,7 @@ namespace v2rayN.ViewModels y => y == true) .Subscribe(c => DoEnableTun(c)); - BindingUI(); + BindingUI(hwndSource); RestoreUI(); AutoHideStartup(); @@ -1665,9 +1670,10 @@ namespace v2rayN.ViewModels { } - private void BindingUI() + private void BindingUI(HwndSource hwndSource) { ColorModeDark = _config.uiItem.colorModeDark; + FollowSystemTheme = _config.uiItem.followSystemTheme; _swatches.AddRange(new SwatchesProvider().Swatches); if (!_config.uiItem.colorPrimaryName.IsNullOrEmpty()) { @@ -1690,6 +1696,57 @@ namespace v2rayN.ViewModels } }); + this.WhenAnyValue(x => x.FollowSystemTheme, + y => y == true) + .Subscribe(c => + { + if (_config.uiItem.followSystemTheme != FollowSystemTheme) + { + _config.uiItem.followSystemTheme = FollowSystemTheme; + if (FollowSystemTheme) + { + hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) => + { + const int WM_SETTINGCHANGE = 0x001A; + if (msg == WM_SETTINGCHANGE) + { + if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet") + { + var isLightTheme = Utils.IsLightTheme(); + ColorModeDark = !isLightTheme; + } + } + + return IntPtr.Zero; + + }); + + var isLightTheme = Utils.IsLightTheme(); + ColorModeDark = !isLightTheme; + } + else + { + hwndSource.RemoveHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) => + { + const int WM_SETTINGCHANGE = 0x001A; + if (msg == WM_SETTINGCHANGE) + { + if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet") + { + var isLightTheme = Utils.IsLightTheme(); + ColorModeDark = !isLightTheme; + } + } + + return IntPtr.Zero; + + }); + } + + ConfigHandler.SaveConfig(ref _config); + } + }); + this.WhenAnyValue( x => x.SelectedSwatch, y => y != null && !y.Name.IsNullOrEmpty()) diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml index b994f28f..9aefc90e 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml +++ b/v2rayN/v2rayN/Views/MainWindow.xaml @@ -301,6 +301,7 @@ + @@ -319,17 +320,30 @@ x:Name="togDarkMode" Grid.Row="0" Grid.Column="1" + Margin="8" + IsEnabled="{Binding ElementName=followSystemTheme, Path=IsChecked, Converter={StaticResource InverseBooleanConverter}}"/> + + + + Header="{x:Static resx:ResUI.menuSpeedServer}"/> ViewModel, typeof(MainWindowViewModel)); for (int i = Global.MinFontSize; i <= Global.MinFontSize + 8; i++) @@ -183,6 +187,7 @@ namespace v2rayN.Views //UI this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.FollowSystemTheme, v => v.followSystemTheme.IsChecked).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);