mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-23 19:49:43 +01:00
Refactor LightSwitch and PowerDisplay integration
Simplify theme change notification logic in `LightSwitchService.cpp` by consolidating redundant checks and improving error handling. Remove the `applyMonitorSettings` setting and associated logic from `LightSwitchSettings`. Introduce `PowerDisplayProfilesHelper` to centralize profile management, ensuring thread safety and simplifying file operations. Update UI in `LightSwitchPage.xaml` to replace `ApplyMonitorSettings` with separate dark and light mode profile settings, adding navigation to PowerDisplay settings. Enhance `LightSwitchViewModel` with nullable annotations, new profile selection properties, and improved property synchronization. Refactor `PowerDisplayViewModel` to use `PowerDisplayProfilesHelper` for profile management. Update localization strings for new UI elements. Perform general code cleanup, including null safety annotations, improved logging, and removal of legacy code.
This commit is contained in:
@@ -197,44 +197,41 @@ DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
SetAppsTheme(false);
|
||||
}
|
||||
|
||||
// Notify PowerDisplay about theme change if monitor settings integration is enabled
|
||||
if (settings.applyMonitorSettings)
|
||||
// Notify PowerDisplay about theme change if any profile is enabled
|
||||
bool shouldNotify = false;
|
||||
|
||||
if (isLightActive && settings.enableLightModeProfile && !settings.lightModeProfile.empty())
|
||||
{
|
||||
bool shouldNotify = false;
|
||||
shouldNotify = true;
|
||||
}
|
||||
else if (!isLightActive && settings.enableDarkModeProfile && !settings.darkModeProfile.empty())
|
||||
{
|
||||
shouldNotify = true;
|
||||
}
|
||||
|
||||
if (isLightActive && settings.enableLightModeProfile && settings.lightModeProfile != L"(None)")
|
||||
if (shouldNotify)
|
||||
{
|
||||
try
|
||||
{
|
||||
shouldNotify = true;
|
||||
}
|
||||
else if (!isLightActive && settings.enableDarkModeProfile && settings.darkModeProfile != L"(None)")
|
||||
{
|
||||
shouldNotify = true;
|
||||
}
|
||||
// Signal PowerDisplay to check LightSwitch settings and apply appropriate profile
|
||||
// PowerDisplay will read LightSwitch settings to determine which profile to apply
|
||||
Logger::info(L"[LightSwitch] Notifying PowerDisplay about theme change (isLight: {})", isLightActive);
|
||||
|
||||
if (shouldNotify)
|
||||
HANDLE hThemeChangedEvent = CreateEventW(nullptr, FALSE, FALSE, L"Local\\PowerToys_LightSwitch_ThemeChanged");
|
||||
if (hThemeChangedEvent)
|
||||
{
|
||||
SetEvent(hThemeChangedEvent);
|
||||
CloseHandle(hThemeChangedEvent);
|
||||
Logger::info(L"[LightSwitch] Theme change event signaled");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::warn(L"[LightSwitch] Failed to create theme change event");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Signal PowerDisplay to check LightSwitch settings and apply appropriate profile
|
||||
// PowerDisplay will read LightSwitch settings to determine which profile to apply
|
||||
Logger::info(L"[LightSwitch] Notifying PowerDisplay about theme change (isLight: {})", isLightActive);
|
||||
|
||||
HANDLE hThemeChangedEvent = CreateEventW(nullptr, FALSE, FALSE, L"Local\\PowerToys_LightSwitch_ThemeChanged");
|
||||
if (hThemeChangedEvent)
|
||||
{
|
||||
SetEvent(hThemeChangedEvent);
|
||||
CloseHandle(hThemeChangedEvent);
|
||||
Logger::info(L"[LightSwitch] Theme change event signaled");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::warn(L"[LightSwitch] Failed to create theme change event");
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error(L"[LightSwitch] Failed to notify PowerDisplay");
|
||||
}
|
||||
Logger::error(L"[LightSwitch] Failed to notify PowerDisplay");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -160,16 +160,6 @@ void LightSwitchSettings::LoadSettings()
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyMonitorSettings
|
||||
if (const auto jsonVal = values.get_bool_value(L"applyMonitorSettings"))
|
||||
{
|
||||
auto val = *jsonVal;
|
||||
if (m_settings.applyMonitorSettings != val)
|
||||
{
|
||||
m_settings.applyMonitorSettings = val;
|
||||
}
|
||||
}
|
||||
|
||||
// EnableDarkModeProfile
|
||||
if (const auto jsonVal = values.get_bool_value(L"enableDarkModeProfile"))
|
||||
{
|
||||
|
||||
@@ -57,11 +57,10 @@ struct LightSwitchConfig
|
||||
bool changeSystem = false;
|
||||
bool changeApps = false;
|
||||
|
||||
bool applyMonitorSettings = false;
|
||||
bool enableDarkModeProfile = false;
|
||||
bool enableLightModeProfile = false;
|
||||
std::wstring darkModeProfile = L"(None)";
|
||||
std::wstring lightModeProfile = L"(None)";
|
||||
std::wstring darkModeProfile = L"";
|
||||
std::wstring lightModeProfile = L"";
|
||||
};
|
||||
|
||||
class LightSwitchSettings
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
public const string DefaultLatitude = "0.0";
|
||||
public const string DefaultLongitude = "0.0";
|
||||
public const string DefaultScheduleMode = "FixedHours";
|
||||
public const bool DefaultApplyMonitorSettings = false;
|
||||
public const bool DefaultEnableDarkModeProfile = false;
|
||||
public const bool DefaultEnableLightModeProfile = false;
|
||||
public const string DefaultDarkModeProfile = "";
|
||||
@@ -36,7 +35,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
SunsetOffset = new IntProperty(DefaultSunsetOffset);
|
||||
ScheduleMode = new StringProperty(DefaultScheduleMode);
|
||||
ToggleThemeHotkey = new KeyboardKeysProperty(DefaultToggleThemeHotkey);
|
||||
ApplyMonitorSettings = new BoolProperty(DefaultApplyMonitorSettings);
|
||||
EnableDarkModeProfile = new BoolProperty(DefaultEnableDarkModeProfile);
|
||||
EnableLightModeProfile = new BoolProperty(DefaultEnableLightModeProfile);
|
||||
DarkModeProfile = new StringProperty(DefaultDarkModeProfile);
|
||||
@@ -73,9 +71,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("toggle-theme-hotkey")]
|
||||
public KeyboardKeysProperty ToggleThemeHotkey { get; set; }
|
||||
|
||||
[JsonPropertyName("applyMonitorSettings")]
|
||||
public BoolProperty ApplyMonitorSettings { get; set; }
|
||||
|
||||
[JsonPropertyName("enableDarkModeProfile")]
|
||||
public BoolProperty EnableDarkModeProfile { get; set; }
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ namespace Settings.UI.Library
|
||||
Latitude = new StringProperty(Properties.Latitude.Value),
|
||||
Longitude = new StringProperty(Properties.Longitude.Value),
|
||||
ToggleThemeHotkey = new KeyboardKeysProperty(Properties.ToggleThemeHotkey.Value),
|
||||
ApplyMonitorSettings = new BoolProperty(Properties.ApplyMonitorSettings.Value),
|
||||
EnableDarkModeProfile = new BoolProperty(Properties.EnableDarkModeProfile.Value),
|
||||
EnableLightModeProfile = new BoolProperty(Properties.EnableLightModeProfile.Value),
|
||||
DarkModeProfile = new StringProperty(Properties.DarkModeProfile.Value),
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// 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.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using ManagedCommon;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for managing PowerDisplay profiles storage and retrieval
|
||||
/// Provides centralized access to profile data for both PowerDisplay and LightSwitch modules
|
||||
/// </summary>
|
||||
public static class PowerDisplayProfilesHelper
|
||||
{
|
||||
private static readonly object _lock = new object();
|
||||
private static readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true };
|
||||
private static string? _cachedProfilesFilePath;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file path where PowerDisplay profiles are stored
|
||||
/// </summary>
|
||||
public static string GetProfilesFilePath()
|
||||
{
|
||||
if (_cachedProfilesFilePath != null)
|
||||
{
|
||||
return _cachedProfilesFilePath;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_cachedProfilesFilePath != null)
|
||||
{
|
||||
return _cachedProfilesFilePath;
|
||||
}
|
||||
|
||||
var settingsPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var powerToysPath = Path.Combine(settingsPath, "Microsoft", "PowerToys", "PowerDisplay");
|
||||
|
||||
if (!Directory.Exists(powerToysPath))
|
||||
{
|
||||
Directory.CreateDirectory(powerToysPath);
|
||||
}
|
||||
|
||||
_cachedProfilesFilePath = Path.Combine(powerToysPath, "profiles.json");
|
||||
return _cachedProfilesFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads PowerDisplay profiles from disk
|
||||
/// </summary>
|
||||
/// <returns>PowerDisplayProfiles object, or a new empty instance if file doesn't exist or load fails</returns>
|
||||
public static PowerDisplayProfiles LoadProfiles()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filePath = GetProfilesFilePath();
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var profiles = JsonSerializer.Deserialize<PowerDisplayProfiles>(json);
|
||||
|
||||
if (profiles != null)
|
||||
{
|
||||
// Clean up any legacy Custom profiles
|
||||
profiles.Profiles.RemoveAll(p => p.Name.Equals(PowerDisplayProfiles.CustomProfileName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
Logger.LogInfo($"[PowerDisplayProfilesHelper] Loaded {profiles.Profiles.Count} profiles from {filePath}");
|
||||
return profiles;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogInfo($"[PowerDisplayProfilesHelper] No profiles file found at {filePath}, returning empty collection");
|
||||
}
|
||||
|
||||
return new PowerDisplayProfiles();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"[PowerDisplayProfilesHelper] Failed to load profiles: {ex.Message}");
|
||||
return new PowerDisplayProfiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves PowerDisplay profiles to disk
|
||||
/// </summary>
|
||||
/// <param name="profiles">The profiles collection to save</param>
|
||||
/// <param name="prettyPrint">Whether to format the JSON with indentation</param>
|
||||
public static void SaveProfiles(PowerDisplayProfiles profiles, bool prettyPrint = true)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (profiles == null)
|
||||
{
|
||||
Logger.LogWarning("[PowerDisplayProfilesHelper] Cannot save null profiles");
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up any Custom profiles before saving
|
||||
profiles.Profiles.RemoveAll(p => p.Name.Equals(PowerDisplayProfiles.CustomProfileName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
profiles.LastUpdated = DateTime.UtcNow;
|
||||
|
||||
var json = prettyPrint
|
||||
? JsonSerializer.Serialize(profiles, _jsonSerializerOptions)
|
||||
: JsonSerializer.Serialize(profiles);
|
||||
|
||||
var filePath = GetProfilesFilePath();
|
||||
|
||||
File.WriteAllText(filePath, json);
|
||||
|
||||
Logger.LogInfo($"[PowerDisplayProfilesHelper] Saved {profiles.Profiles.Count} profiles to {filePath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"[PowerDisplayProfilesHelper] Failed to save profiles: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the profiles file exists
|
||||
/// </summary>
|
||||
public static bool ProfilesFileExists()
|
||||
{
|
||||
try
|
||||
{
|
||||
var filePath = GetProfilesFilePath();
|
||||
return File.Exists(filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"[PowerDisplayProfilesHelper] Error checking if profiles file exists: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,40 +156,43 @@
|
||||
x:Uid="LightSwitch_PowerDisplayDisabledWarningBar"
|
||||
IsOpen="True"
|
||||
Severity="Warning"
|
||||
Visibility="{x:Bind ViewModel.ShowPowerDisplayDisabledWarning, Mode=OneWay}" />
|
||||
Visibility="{x:Bind ViewModel.ShowPowerDisplayDisabledWarning, Mode=OneWay}">
|
||||
<InfoBar.ActionButton>
|
||||
<HyperlinkButton x:Uid="LightSwitch_NavigatePowerDisplaySettings" Click="NavigatePowerDisplaySettings_Click" />
|
||||
</InfoBar.ActionButton>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Uid="LightSwitch_ApplyMonitorSettingsExpander"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="False">
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<CheckBox
|
||||
x:Uid="LightSwitch_EnableMonitorSettings"
|
||||
IsChecked="{x:Bind ViewModel.ApplyMonitorSettings, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="LightSwitch_DarkModeProfileCard" HorizontalContentAlignment="Left">
|
||||
<StackPanel Orientation="Horizontal" Spacing="12">
|
||||
<tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard.Header>
|
||||
<CheckBox
|
||||
x:Uid="LightSwitch_DarkModeProfileCheckbox"
|
||||
IsChecked="{x:Bind ViewModel.EnableDarkModeProfile, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}" />
|
||||
<ComboBox
|
||||
MinWidth="200"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableProfiles, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.DarkModeProfile, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard.Header>
|
||||
<ComboBox
|
||||
MinWidth="200"
|
||||
DisplayMemberPath="Name"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableProfiles, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedDarkModeProfile, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="LightSwitch_LightModeProfileCard" HorizontalContentAlignment="Left">
|
||||
<StackPanel Orientation="Horizontal" Spacing="12">
|
||||
<tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard.Header>
|
||||
<CheckBox
|
||||
x:Uid="LightSwitch_LightModeProfileCheckbox"
|
||||
IsChecked="{x:Bind ViewModel.EnableLightModeProfile, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}" />
|
||||
<ComboBox
|
||||
MinWidth="200"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableProfiles, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.LightModeProfile, Mode=TwoWay}" />
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard.Header>
|
||||
<ComboBox
|
||||
MinWidth="200"
|
||||
DisplayMemberPath="Name"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableProfiles, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedLightModeProfile, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Common.UI;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
@@ -128,7 +129,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
ViewModel.SelectedCity = null;
|
||||
|
||||
// CityAutoSuggestBox.Text = string.Empty;
|
||||
ViewModel.SyncButtonInformation = $"{ViewModel.Latitude}<7D>, {ViewModel.Longitude}<7D>";
|
||||
ViewModel.SyncButtonInformation = $"{ViewModel.Latitude}<7D>, {ViewModel.Longitude}<7D>";
|
||||
|
||||
// ViewModel.CityTimesText = $"Sunrise: {result.SunriseHour}:{result.SunriseMinute:D2}\n" + $"Sunset: {result.SunsetHour}:{result.SunsetMinute:D2}";
|
||||
SyncButton.IsEnabled = true;
|
||||
@@ -153,7 +154,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
}
|
||||
else if (ViewModel.ScheduleMode == "SunriseToSunsetGeo")
|
||||
{
|
||||
ViewModel.SyncButtonInformation = $"{ViewModel.Latitude}<7D>, {ViewModel.Longitude}<7D>";
|
||||
ViewModel.SyncButtonInformation = $"{ViewModel.Latitude}<7D>, {ViewModel.Longitude}<7D>";
|
||||
}
|
||||
|
||||
SunriseModeChartState();
|
||||
@@ -321,5 +322,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
await GetGeoLocation();
|
||||
}
|
||||
|
||||
private void NavigatePowerDisplaySettings_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
ShellPage.Navigate(typeof(PowerDisplayPage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5336,12 +5336,27 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<data name="LightSwitch_EnableMonitorSettings.Content" xml:space="preserve">
|
||||
<value>Enable monitor settings integration</value>
|
||||
</data>
|
||||
<data name="LightSwitch_DarkModeProfileCheckbox.Content" xml:space="preserve">
|
||||
<value>Dark mode profile</value>
|
||||
</data>
|
||||
<data name="LightSwitch_LightModeProfileCheckbox.Content" xml:space="preserve">
|
||||
<value>Light mode profile</value>
|
||||
</data>
|
||||
<data name="LightSwitch_DarkModeProfileCard.Header" xml:space="preserve">
|
||||
<value>Dark mode profile</value>
|
||||
</data>
|
||||
<data name="LightSwitch_DarkModeProfileCard.Description" xml:space="preserve">
|
||||
<value>Profile to apply when switching to dark mode</value>
|
||||
</data>
|
||||
<data name="LightSwitch_LightModeProfileCard.Header" xml:space="preserve">
|
||||
<value>Light mode profile</value>
|
||||
</data>
|
||||
<data name="LightSwitch_LightModeProfileCard.Description" xml:space="preserve">
|
||||
<value>Profile to apply when switching to light mode</value>
|
||||
</data>
|
||||
<data name="LightSwitch_NavigatePowerDisplaySettings.Content" xml:space="preserve">
|
||||
<value>Open PowerDisplay settings</value>
|
||||
</data>
|
||||
<data name="LightSwitch_LocationDialog.Title" xml:space="preserve">
|
||||
<value>Select a location</value>
|
||||
</data>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -30,10 +32,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
public ObservableCollection<SearchLocation> SearchLocations { get; } = new();
|
||||
|
||||
public LightSwitchViewModel(LightSwitchSettings initialSettings = null, Func<string, int> ipcMSGCallBackFunc = null)
|
||||
public LightSwitchViewModel(LightSwitchSettings? initialSettings = null, Func<string, int>? ipcMSGCallBackFunc = null)
|
||||
{
|
||||
_moduleSettings = initialSettings ?? new LightSwitchSettings();
|
||||
SendConfigMSG = ipcMSGCallBackFunc;
|
||||
SendConfigMSG = ipcMSGCallBackFunc ?? (_ => 0);
|
||||
|
||||
ForceLightCommand = new RelayCommand(ForceLightNow);
|
||||
ForceDarkCommand = new RelayCommand(ForceDarkNow);
|
||||
@@ -381,9 +383,9 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private SearchLocation _selectedSearchLocation;
|
||||
private SearchLocation? _selectedSearchLocation;
|
||||
|
||||
public SearchLocation SelectedCity
|
||||
public SearchLocation? SelectedCity
|
||||
{
|
||||
get => _selectedSearchLocation;
|
||||
set
|
||||
@@ -393,7 +395,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
_selectedSearchLocation = value;
|
||||
NotifyPropertyChanged();
|
||||
|
||||
UpdateSunTimes(_selectedSearchLocation.Latitude, _selectedSearchLocation.Longitude, _selectedSearchLocation.City);
|
||||
if (_selectedSearchLocation != null)
|
||||
{
|
||||
UpdateSunTimes(_selectedSearchLocation.Latitude, _selectedSearchLocation.Longitude, _selectedSearchLocation.City);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,7 +447,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
public void NotifyPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
Logger.LogInfo($"Changed the property {propertyName}");
|
||||
OnPropertyChanged(propertyName);
|
||||
@@ -476,21 +481,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowPowerDisplayDisabledWarning => !IsPowerDisplayEnabled && ModuleSettings.Properties.ApplyMonitorSettings.Value;
|
||||
|
||||
public bool ApplyMonitorSettings
|
||||
{
|
||||
get => ModuleSettings.Properties.ApplyMonitorSettings.Value;
|
||||
set
|
||||
{
|
||||
if (ModuleSettings.Properties.ApplyMonitorSettings.Value != value)
|
||||
{
|
||||
ModuleSettings.Properties.ApplyMonitorSettings.Value = value;
|
||||
NotifyPropertyChanged();
|
||||
NotifyPropertyChanged(nameof(ShowPowerDisplayDisabledWarning));
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool ShowPowerDisplayDisabledWarning => !IsPowerDisplayEnabled && (ModuleSettings.Properties.EnableDarkModeProfile.Value || ModuleSettings.Properties.EnableLightModeProfile.Value);
|
||||
|
||||
public bool EnableDarkModeProfile
|
||||
{
|
||||
@@ -501,6 +492,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
{
|
||||
ModuleSettings.Properties.EnableDarkModeProfile.Value = value;
|
||||
NotifyPropertyChanged();
|
||||
NotifyPropertyChanged(nameof(ShowPowerDisplayDisabledWarning));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,10 +506,54 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
{
|
||||
ModuleSettings.Properties.EnableLightModeProfile.Value = value;
|
||||
NotifyPropertyChanged();
|
||||
NotifyPropertyChanged(nameof(ShowPowerDisplayDisabledWarning));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PowerDisplayProfile? SelectedDarkModeProfile
|
||||
{
|
||||
get => _selectedDarkModeProfile;
|
||||
set
|
||||
{
|
||||
if (_selectedDarkModeProfile != value)
|
||||
{
|
||||
_selectedDarkModeProfile = value;
|
||||
|
||||
// Sync with the string property stored in settings
|
||||
var newProfileName = value?.Name ?? string.Empty;
|
||||
if (ModuleSettings.Properties.DarkModeProfile.Value != newProfileName)
|
||||
{
|
||||
ModuleSettings.Properties.DarkModeProfile.Value = newProfileName;
|
||||
}
|
||||
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PowerDisplayProfile? SelectedLightModeProfile
|
||||
{
|
||||
get => _selectedLightModeProfile;
|
||||
set
|
||||
{
|
||||
if (_selectedLightModeProfile != value)
|
||||
{
|
||||
_selectedLightModeProfile = value;
|
||||
|
||||
// Sync with the string property stored in settings
|
||||
var newProfileName = value?.Name ?? string.Empty;
|
||||
if (ModuleSettings.Properties.LightModeProfile.Value != newProfileName)
|
||||
{
|
||||
ModuleSettings.Properties.LightModeProfile.Value = newProfileName;
|
||||
}
|
||||
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy string properties for backwards compatibility with settings persistence
|
||||
public string DarkModeProfile
|
||||
{
|
||||
get => ModuleSettings.Properties.DarkModeProfile.Value;
|
||||
@@ -526,6 +562,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
if (ModuleSettings.Properties.DarkModeProfile.Value != value)
|
||||
{
|
||||
ModuleSettings.Properties.DarkModeProfile.Value = value;
|
||||
|
||||
// Sync with the object property
|
||||
UpdateSelectedProfileFromName(value, isDarkMode: true);
|
||||
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
@@ -539,6 +579,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
if (ModuleSettings.Properties.LightModeProfile.Value != value)
|
||||
{
|
||||
ModuleSettings.Properties.LightModeProfile.Value = value;
|
||||
|
||||
// Sync with the object property
|
||||
UpdateSelectedProfileFromName(value, isDarkMode: false);
|
||||
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
@@ -548,43 +592,62 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
var settingsPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var powerToysPath = Path.Combine(settingsPath, "Microsoft", "PowerToys", "PowerDisplay");
|
||||
_profilesFilePath = Path.Combine(powerToysPath, "profiles.json");
|
||||
var profilesData = PowerDisplayProfilesHelper.LoadProfiles();
|
||||
|
||||
if (File.Exists(_profilesFilePath))
|
||||
AvailableProfiles.Clear();
|
||||
|
||||
foreach (var profile in profilesData.Profiles)
|
||||
{
|
||||
var json = File.ReadAllText(_profilesFilePath);
|
||||
var profilesData = JsonSerializer.Deserialize<PowerDisplayProfiles>(json);
|
||||
|
||||
if (profilesData != null)
|
||||
{
|
||||
AvailableProfiles.Clear();
|
||||
|
||||
// Add empty option
|
||||
AvailableProfiles.Add(new PowerDisplayProfile("(None)", new List<ProfileMonitorSetting>()));
|
||||
|
||||
foreach (var profile in profilesData.Profiles)
|
||||
{
|
||||
AvailableProfiles.Add(profile);
|
||||
}
|
||||
|
||||
Logger.LogInfo($"Loaded {profilesData.Profiles.Count} PowerDisplay profiles");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add empty option
|
||||
AvailableProfiles.Clear();
|
||||
AvailableProfiles.Add(new PowerDisplayProfile("(None)", new List<ProfileMonitorSetting>()));
|
||||
Logger.LogInfo("No PowerDisplay profiles file found");
|
||||
AvailableProfiles.Add(profile);
|
||||
}
|
||||
|
||||
Logger.LogInfo($"Loaded {profilesData.Profiles.Count} PowerDisplay profiles");
|
||||
|
||||
// Sync selected profiles from settings
|
||||
UpdateSelectedProfileFromName(ModuleSettings.Properties.DarkModeProfile.Value, isDarkMode: true);
|
||||
UpdateSelectedProfileFromName(ModuleSettings.Properties.LightModeProfile.Value, isDarkMode: false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Failed to load PowerDisplay profiles: {ex.Message}");
|
||||
AvailableProfiles.Clear();
|
||||
AvailableProfiles.Add(new PowerDisplayProfile("(None)", new List<ProfileMonitorSetting>()));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to sync the selected profile object from the profile name stored in settings
|
||||
/// </summary>
|
||||
private void UpdateSelectedProfileFromName(string profileName, bool isDarkMode)
|
||||
{
|
||||
PowerDisplayProfile? matchingProfile = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(profileName))
|
||||
{
|
||||
matchingProfile = AvailableProfiles.FirstOrDefault(p =>
|
||||
p.Name.Equals(profileName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
// If not found or empty, default to first available profile
|
||||
if (matchingProfile == null && AvailableProfiles.Count > 0)
|
||||
{
|
||||
matchingProfile = AvailableProfiles[0];
|
||||
}
|
||||
|
||||
if (isDarkMode)
|
||||
{
|
||||
if (_selectedDarkModeProfile != matchingProfile)
|
||||
{
|
||||
_selectedDarkModeProfile = matchingProfile;
|
||||
NotifyPropertyChanged(nameof(SelectedDarkModeProfile));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_selectedLightModeProfile != matchingProfile)
|
||||
{
|
||||
_selectedLightModeProfile = matchingProfile;
|
||||
NotifyPropertyChanged(nameof(SelectedLightModeProfile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,7 +689,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
OnPropertyChanged(nameof(Latitude));
|
||||
OnPropertyChanged(nameof(Longitude));
|
||||
OnPropertyChanged(nameof(ScheduleMode));
|
||||
OnPropertyChanged(nameof(ApplyMonitorSettings));
|
||||
OnPropertyChanged(nameof(EnableDarkModeProfile));
|
||||
OnPropertyChanged(nameof(EnableLightModeProfile));
|
||||
OnPropertyChanged(nameof(DarkModeProfile));
|
||||
@@ -692,7 +754,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
// PowerDisplay integration
|
||||
private ObservableCollection<PowerDisplayProfile> _availableProfiles = new ObservableCollection<PowerDisplayProfile>();
|
||||
private bool _isPowerDisplayEnabled;
|
||||
private string _profilesFilePath = string.Empty;
|
||||
private PowerDisplayProfile? _selectedDarkModeProfile;
|
||||
private PowerDisplayProfile? _selectedLightModeProfile;
|
||||
|
||||
public ICommand ForceLightCommand { get; }
|
||||
|
||||
|
||||
@@ -476,7 +476,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
// Profile-related fields
|
||||
private ObservableCollection<PowerDisplayProfile> _profiles = new ObservableCollection<PowerDisplayProfile>();
|
||||
private string _profilesFilePath = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Collection of available profiles (for button display)
|
||||
@@ -520,11 +519,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
var settingsPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var powerToysPath = Path.Combine(settingsPath, "Microsoft", "PowerToys", "PowerDisplay");
|
||||
_profilesFilePath = Path.Combine(powerToysPath, "profiles.json");
|
||||
|
||||
var profilesData = LoadProfilesFromDisk();
|
||||
var profilesData = PowerDisplayProfilesHelper.LoadProfiles();
|
||||
|
||||
// Load profile objects (no Custom - it's not a profile anymore)
|
||||
Profiles.Clear();
|
||||
@@ -547,14 +542,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
/// </summary>
|
||||
private PowerDisplayProfiles LoadProfilesFromDisk()
|
||||
{
|
||||
if (File.Exists(_profilesFilePath))
|
||||
{
|
||||
var json = File.ReadAllText(_profilesFilePath);
|
||||
var profiles = JsonSerializer.Deserialize<PowerDisplayProfiles>(json);
|
||||
return profiles ?? new PowerDisplayProfiles();
|
||||
}
|
||||
|
||||
return new PowerDisplayProfiles();
|
||||
return PowerDisplayProfilesHelper.LoadProfiles();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -562,17 +550,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
/// </summary>
|
||||
private void SaveProfilesToDisk(PowerDisplayProfiles profiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
profiles.LastUpdated = DateTime.UtcNow;
|
||||
var json = JsonSerializer.Serialize(profiles, _jsonSerializerOptions);
|
||||
File.WriteAllText(_profilesFilePath, json);
|
||||
Logger.LogInfo($"Saved profiles to disk: {_profilesFilePath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Failed to save profiles: {ex.Message}");
|
||||
}
|
||||
PowerDisplayProfilesHelper.SaveProfiles(profiles, prettyPrint: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user