[Settings]Theme override fix and cleanup (#32362)

* theme override fix and cleanup

* test fix
This commit is contained in:
Davide Giacometti
2024-04-17 16:39:19 +02:00
committed by GitHub
parent fba5f6f002
commit b14aa8276d
9 changed files with 89 additions and 129 deletions

View File

@@ -53,7 +53,6 @@ namespace ViewModelTests
runAsUserText: "GeneralSettings_RunningAsUserText",
isElevated: false,
isAdmin: false,
updateTheme: UpdateUIThemeMethod,
ipcMSGCallBackFunc: sendMockIPCConfigMSG,
ipcMSGRestartAsAdminMSGCallBackFunc: sendRestartAdminIPCMessage,
ipcMSGCheckForUpdatesCallBackFunc: sendCheckForUpdatesIPCMessage,
@@ -83,7 +82,6 @@ namespace ViewModelTests
"GeneralSettings_RunningAsUserText",
false,
false,
UpdateUIThemeMethod,
sendMockIPCConfigMSG,
sendRestartAdminIPCMessage,
sendCheckForUpdatesIPCMessage,
@@ -120,7 +118,6 @@ namespace ViewModelTests
"GeneralSettings_RunningAsUserText",
false,
false,
UpdateUIThemeMethod,
sendMockIPCConfigMSG,
sendRestartAdminIPCMessage,
sendCheckForUpdatesIPCMessage,
@@ -152,7 +149,6 @@ namespace ViewModelTests
"GeneralSettings_RunningAsUserText",
false,
false,
UpdateUIThemeMethod,
sendMockIPCConfigMSG,
sendRestartAdminIPCMessage,
sendCheckForUpdatesIPCMessage,
@@ -186,7 +182,6 @@ namespace ViewModelTests
"GeneralSettings_RunningAsUserText",
false,
false,
UpdateUIThemeMethod,
sendMockIPCConfigMSG,
sendRestartAdminIPCMessage,
sendCheckForUpdatesIPCMessage,
@@ -217,7 +212,6 @@ namespace ViewModelTests
"GeneralSettings_RunningAsUserText",
false,
false,
UpdateUIThemeMethod,
sendMockIPCConfigMSG,
sendRestartAdminIPCMessage,
sendCheckForUpdatesIPCMessage,
@@ -243,10 +237,5 @@ namespace ViewModelTests
Assert.IsTrue(modules.PowerLauncher);
Assert.IsTrue(modules.ColorPicker);
}
public static int UpdateUIThemeMethod(string themeName)
{
return 0;
}
}
}

View File

@@ -6,10 +6,11 @@ using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.Json;
using Microsoft.UI.Xaml;
namespace Microsoft.PowerToys.Settings.UI.Helpers
{
internal sealed class Utils
internal sealed class WindowHelper
{
private static string _placementPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Microsoft\PowerToys\settings-placement.json");
@@ -45,5 +46,13 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
{
}
}
public static void SetTheme(Window window, ElementTheme theme)
{
if (window.Content is FrameworkElement rootElement)
{
rootElement.RequestedTheme = theme;
}
}
}
}

View File

@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
using Microsoft.UI.Xaml;
namespace Microsoft.PowerToys.Settings.UI.Services
{
public class ThemeService
{
private readonly ISettingsRepository<GeneralSettings> _generalSettingsRepository;
public event EventHandler<ElementTheme> ThemeChanged;
public ElementTheme Theme { get; private set; } = ElementTheme.Default;
public ThemeService(ISettingsRepository<GeneralSettings> generalSettingsRepository)
{
_generalSettingsRepository = generalSettingsRepository;
Theme = GetTheme();
}
public void ApplyTheme()
{
Theme = GetTheme();
ThemeChanged?.Invoke(null, Theme);
}
private ElementTheme GetTheme()
{
switch (_generalSettingsRepository.SettingsConfig.Theme.ToUpperInvariant())
{
case "LIGHT":
return ElementTheme.Light;
case "DARK":
return ElementTheme.Dark;
case "SYSTEM":
return ElementTheme.Default;
default:
ManagedCommon.Logger.LogError($"Unexpected theme name: {_generalSettingsRepository.SettingsConfig.Theme}");
return ElementTheme.Default;
}
}
}
}

View File

@@ -5,20 +5,16 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http.Json;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Common.UI;
using interop;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
using Microsoft.PowerToys.Settings.UI.Services;
using Microsoft.PowerToys.Settings.UI.Views;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Xaml;
@@ -73,8 +69,6 @@ namespace Microsoft.PowerToys.Settings.UI
public static Action<string> IPCMessageReceivedCallback { get; set; }
private static bool loggedImmersiveDarkException;
/// <summary>
/// Initializes a new instance of the <see cref="App"/> class.
/// Initializes the singleton application object. This is the first line of authored code
@@ -259,19 +253,6 @@ namespace Microsoft.PowerToys.Settings.UI
ShellPage.OpenFlyoutCallback(p);
}
}
if (SelectedTheme() == ElementTheme.Default)
{
try
{
themeListener = new ThemeListener();
themeListener.ThemeChanged += (_) => HandleThemeChange();
}
catch (Exception ex)
{
Logger.LogError($"HandleThemeChange exception. Please install .NET 4.", ex);
}
}
}
/// <summary>
@@ -311,7 +292,7 @@ namespace Microsoft.PowerToys.Settings.UI
ShowMessageDialog("The application is running in Debug mode.", "DEBUG");
#else
/* If we try to run Settings as a standalone app, it will start PowerToys.exe if not running and open Settings again through it in the Dashboard page. */
SettingsDeepLink.OpenSettings(SettingsDeepLink.SettingsWindow.Dashboard, true);
Common.UI.SettingsDeepLink.OpenSettings(Common.UI.SettingsDeepLink.SettingsWindow.Dashboard, true);
Exit();
#endif
}
@@ -347,92 +328,24 @@ namespace Microsoft.PowerToys.Settings.UI
return ipcmanager;
}
public static ElementTheme SelectedTheme()
{
switch (SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.Theme.ToUpper(CultureInfo.InvariantCulture))
{
case "DARK": return ElementTheme.Dark;
case "LIGHT": return ElementTheme.Light;
default: return ElementTheme.Default;
}
}
public static bool IsDarkTheme()
{
var selectedTheme = SelectedTheme();
return selectedTheme == ElementTheme.Dark || (selectedTheme == ElementTheme.Default && ThemeHelpers.GetAppTheme() == AppTheme.Dark);
}
public static void HandleThemeChange()
{
try
{
bool isDark = IsDarkTheme();
if (settingsWindow != null)
{
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(settingsWindow);
ThemeHelpers.SetImmersiveDarkMode(hWnd, isDark);
}
if (oobeWindow != null)
{
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(oobeWindow);
ThemeHelpers.SetImmersiveDarkMode(hWnd, isDark);
}
if (SelectedTheme() == ElementTheme.Default)
{
themeListener = new ThemeListener();
themeListener.ThemeChanged += (_) => HandleThemeChange();
}
else if (themeListener != null)
{
themeListener.Dispose();
themeListener = null;
}
}
catch (Exception e)
{
if (!loggedImmersiveDarkException)
{
Logger.LogError($"HandleThemeChange exception. Please install .NET 4.", e);
loggedImmersiveDarkException = true;
}
}
return ThemeService.Theme == ElementTheme.Dark || (ThemeService.Theme == ElementTheme.Default && ThemeHelpers.GetAppTheme() == AppTheme.Dark);
}
public static int UpdateUIThemeMethod(string themeName)
{
switch (themeName?.ToUpperInvariant())
{
case "LIGHT":
// OobeShellPage.OobeShellHandler.RequestedTheme = ElementTheme.Light;
ShellPage.ShellHandler.RequestedTheme = ElementTheme.Light;
break;
case "DARK":
// OobeShellPage.OobeShellHandler.RequestedTheme = ElementTheme.Dark;
ShellPage.ShellHandler.RequestedTheme = ElementTheme.Dark;
break;
case "SYSTEM":
// OobeShellPage.OobeShellHandler.RequestedTheme = ElementTheme.Default;
ShellPage.ShellHandler.RequestedTheme = ElementTheme.Default;
break;
default:
Logger.LogError($"Unexpected theme name: {themeName}");
break;
}
HandleThemeChange();
return 0;
}
private static ISettingsUtils settingsUtils = new SettingsUtils();
private static ThemeService themeService = new ThemeService(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils));
public static ThemeService ThemeService => themeService;
private static MainWindow settingsWindow;
private static OobeWindow oobeWindow;
private static FlyoutWindow flyoutWindow;
private static ThemeListener themeListener;
public static void ClearSettingsWindow()
{

View File

@@ -27,6 +27,9 @@ namespace Microsoft.PowerToys.Settings.UI
var bootTime = new System.Diagnostics.Stopwatch();
bootTime.Start();
App.ThemeService.ThemeChanged += OnThemeChanged;
App.ThemeService.ApplyTheme();
ShellPage.SetElevationStatus(App.IsElevated);
ShellPage.SetIsUserAnAdmin(App.IsUserAnAdmin);
@@ -36,7 +39,7 @@ namespace Microsoft.PowerToys.Settings.UI
AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
appWindow.SetIcon("Assets\\Settings\\icon.ico");
var placement = Utils.DeserializePlacementOrDefault(hWnd);
var placement = WindowHelper.DeserializePlacementOrDefault(hWnd);
if (createHidden)
{
placement.ShowCmd = NativeMethods.SW_HIDE;
@@ -202,7 +205,7 @@ namespace Microsoft.PowerToys.Settings.UI
private void Window_Closed(object sender, WindowEventArgs args)
{
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
Utils.SerializePlacement(hWnd);
WindowHelper.SerializePlacement(hWnd);
if (App.GetOobeWindow() == null)
{
@@ -213,6 +216,8 @@ namespace Microsoft.PowerToys.Settings.UI
args.Handled = true;
NativeMethods.ShowWindow(hWnd, NativeMethods.SW_HIDE);
}
App.ThemeService.ThemeChanged -= OnThemeChanged;
}
private void Window_Activated(object sender, WindowActivatedEventArgs args)
@@ -221,11 +226,16 @@ namespace Microsoft.PowerToys.Settings.UI
{
this.Activated -= Window_Activated;
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
var placement = Utils.DeserializePlacementOrDefault(hWnd);
var placement = WindowHelper.DeserializePlacementOrDefault(hWnd);
NativeMethods.SetWindowPlacement(hWnd, ref placement);
}
}
private void OnThemeChanged(object sender, ElementTheme theme)
{
WindowHelper.SetTheme(this, theme);
}
internal void EnsurePageIsSelected()
{
ShellPage.EnsurePageIsSelected();

View File

@@ -4,7 +4,6 @@
using System;
using interop;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
using Microsoft.PowerToys.Settings.UI.OOBE.Views;
@@ -36,6 +35,9 @@ namespace Microsoft.PowerToys.Settings.UI
public OobeWindow(PowerToysModules initialModule)
{
App.ThemeService.ThemeChanged += OnThemeChanged;
App.ThemeService.ApplyTheme();
this.InitializeComponent();
// Set window icon
@@ -133,6 +135,13 @@ namespace Microsoft.PowerToys.Settings.UI
{
mainWindow.CloseHiddenWindow();
}
App.ThemeService.ThemeChanged -= OnThemeChanged;
}
private void OnThemeChanged(object sender, ElementTheme theme)
{
WindowHelper.SetTheme(this, theme);
}
private void Dispose(bool disposing)

View File

@@ -8,11 +8,9 @@ using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.OOBE.Views;
using Microsoft.PowerToys.Settings.UI.ViewModels;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.Storage.Pickers;
namespace Microsoft.PowerToys.Settings.UI.Views
{
@@ -73,7 +71,6 @@ namespace Microsoft.PowerToys.Settings.UI.Views
loader.GetString("GeneralSettings_RunningAsUserText"),
ShellPage.IsElevated,
ShellPage.IsUserAnAdmin,
App.UpdateUIThemeMethod,
ShellPage.SendDefaultIPCMessage,
ShellPage.SendRestartAdminIPCMessage,
ShellPage.SendCheckForUpdatesIPCMessage,

View File

@@ -64,8 +64,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
UpdatingSettings updatingSettingsConfig = UpdatingSettings.LoadSettings();
UpdateAvailable = updatingSettingsConfig != null && (updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToInstall || updatingSettingsConfig.State == UpdatingSettings.UpdatingState.ReadyToDownload);
App.UpdateUIThemeMethod(generalSettingsConfig.Theme);
}
private void AddDashboardListItem(ModuleType moduleType)

View File

@@ -7,7 +7,6 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json;
@@ -48,8 +47,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
public ButtonClickCommand UpdateNowButtonEventHandler { get; set; }
public Func<string, int> UpdateUIThemeCallBack { get; }
public Func<string, int> SendConfigMSG { get; }
public Func<string, int> SendRestartAsAdminConfigMSG { get; }
@@ -68,7 +65,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private SettingsBackupAndRestoreUtils settingsBackupAndRestoreUtils = SettingsBackupAndRestoreUtils.Instance;
public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository, string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> updateTheme, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "", Action dispatcherAction = null, Action hideBackupAndRestoreMessageAreaAction = null, Action<int> doBackupAndRestoreDryRun = null, Func<Task<string>> pickSingleFolderDialog = null, object resourceLoader = null)
public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository, string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "", Action dispatcherAction = null, Action hideBackupAndRestoreMessageAreaAction = null, Action<int> doBackupAndRestoreDryRun = null, Func<Task<string>> pickSingleFolderDialog = null, object resourceLoader = null)
{
CheckForUpdatesEventHandler = new ButtonClickCommand(CheckForUpdatesClick);
RestartElevatedButtonEventHandler = new ButtonClickCommand(RestartElevated);
@@ -97,9 +94,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
SendCheckForUpdatesConfigMSG = ipcMSGCheckForUpdatesCallBackFunc;
SendRestartAsAdminConfigMSG = ipcMSGRestartAsAdminMSGCallBackFunc;
// set the callback function value to update the UI theme.
UpdateUIThemeCallBack = updateTheme;
// Update Settings file folder:
_settingsConfigFileFolder = configFileSubfolder;
@@ -440,14 +434,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_themeIndex = value;
try
{
UpdateUIThemeCallBack(GeneralSettingsConfig.Theme);
}
catch (Exception e)
{
Logger.LogError("Exception encountered when changing Settings theme", e);
}
App.ThemeService.ApplyTheme();
NotifyPropertyChanged();
}