mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-18 01:00:06 +01:00
Compare commits
51 Commits
dev/snickl
...
jay/DarkMo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d403d5a7fb | ||
|
|
289f47c1ea | ||
|
|
6bbfdd9a93 | ||
|
|
47102583af | ||
|
|
52ff8bea34 | ||
|
|
a3441eecc6 | ||
|
|
88cf1ecaec | ||
|
|
a1b09180d8 | ||
|
|
6907f26243 | ||
|
|
911a4e1009 | ||
|
|
44be38e9b6 | ||
|
|
00d15ba780 | ||
|
|
b1b1791489 | ||
|
|
05ae7129aa | ||
|
|
4b015605a1 | ||
|
|
fa29bebec3 | ||
|
|
9816d6fc05 | ||
|
|
323ddfdf55 | ||
|
|
ae6187101f | ||
|
|
be105b5e27 | ||
|
|
8aedc4a61d | ||
|
|
9c82281bb1 | ||
|
|
df74f6e3c7 | ||
|
|
887e552d43 | ||
|
|
df61b2863e | ||
|
|
9f581101a8 | ||
|
|
db41f61010 | ||
|
|
e28e4582c9 | ||
|
|
abc7f3f3fb | ||
|
|
039991bc4a | ||
|
|
a857cc688b | ||
|
|
1be5e5931a | ||
|
|
03fafa747f | ||
|
|
62b4075349 | ||
|
|
cc42876c01 | ||
|
|
2d30fe2ec2 | ||
|
|
247cc47491 | ||
|
|
7de506010e | ||
|
|
736a04f65c | ||
|
|
b66b44cc49 | ||
|
|
f55f465c83 | ||
|
|
30e6215003 | ||
|
|
bdafb0e38a | ||
|
|
50c5d577bc | ||
|
|
a9e838ae1d | ||
|
|
c47ff9cd55 | ||
|
|
104d4fd6a0 | ||
|
|
37242fbb4d | ||
|
|
2c39113914 | ||
|
|
bf07c11640 | ||
|
|
2c6a8bac27 |
@@ -5,11 +5,13 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
|||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner.vcxproj", "{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner.vcxproj", "{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73} = {031AC72E-FA28-4AB7-B690-6F7B9C28AA73}
|
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73} = {031AC72E-FA28-4AB7-B690-6F7B9C28AA73}
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC} = {08E71C67-6A7E-4CA1-B04E-2FB336410BAC}
|
||||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B} = {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}
|
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B} = {0B43679E-EDFA-4DA0-AD30-F4628B308B1B}
|
||||||
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB}
|
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB}
|
||||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
||||||
{217DF501-135C-4E38-BFC8-99D4821032EA} = {217DF501-135C-4E38-BFC8-99D4821032EA}
|
{217DF501-135C-4E38-BFC8-99D4821032EA} = {217DF501-135C-4E38-BFC8-99D4821032EA}
|
||||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} = {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}
|
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34} = {2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166} = {38177D56-6AD1-4ADF-88C9-2843A7932166}
|
||||||
{48804216-2A0E-4168-A6D8-9CD068D14227} = {48804216-2A0E-4168-A6D8-9CD068D14227}
|
{48804216-2A0E-4168-A6D8-9CD068D14227} = {48804216-2A0E-4168-A6D8-9CD068D14227}
|
||||||
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
{51920F1F-C28C-4ADF-8660-4238766796C2} = {51920F1F-C28C-4ADF-8660-4238766796C2}
|
||||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
|
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
|
||||||
@@ -788,6 +790,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.Window
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.UnitTestBase", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.UnitTestsBase\Microsoft.CmdPal.Ext.UnitTestBase.csproj", "{00D8659C-2068-40B6-8B86-759CD6284BBB}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.UnitTestBase", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.UnitTestsBase\Microsoft.CmdPal.Ext.UnitTestBase.csproj", "{00D8659C-2068-40B6-8B86-759CD6284BBB}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LightSwitch", "LightSwitch", "{5B201255-53C8-490B-A34F-01F05D48A477}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightSwitchModuleInterface", "src\modules\LightSwitch\LightSwitchModuleInterface\LightSwitchModuleInterface.vcxproj", "{38177D56-6AD1-4ADF-88C9-2843A7932166}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightModeService", "src\modules\LightSwitch\LightSwitchService\LightSwitchService.vcxproj", "{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|ARM64 = Debug|ARM64
|
Debug|ARM64 = Debug|ARM64
|
||||||
@@ -2850,6 +2858,22 @@ Global
|
|||||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|ARM64.Build.0 = Release|ARM64
|
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|ARM64.Build.0 = Release|ARM64
|
||||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.ActiveCfg = Release|x64
|
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.ActiveCfg = Release|x64
|
||||||
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.Build.0 = Release|x64
|
{00D8659C-2068-40B6-8B86-759CD6284BBB}.Release|x64.Build.0 = Release|x64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|ARM64.Build.0 = Release|ARM64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.Build.0 = Release|x64
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|ARM64.Build.0 = Release|ARM64
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -3161,6 +3185,9 @@ Global
|
|||||||
{E816D7AF-4688-4ECB-97CC-3D8E798F3828} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
{E816D7AF-4688-4ECB-97CC-3D8E798F3828} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||||
{E816D7B0-4688-4ECB-97CC-3D8E798F3829} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
{E816D7B0-4688-4ECB-97CC-3D8E798F3829} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||||
{00D8659C-2068-40B6-8B86-759CD6284BBB} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
{00D8659C-2068-40B6-8B86-759CD6284BBB} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
|
||||||
|
{5B201255-53C8-490B-A34F-01F05D48A477} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166} = {5B201255-53C8-490B-A34F-01F05D48A477}
|
||||||
|
{08E71C67-6A7E-4CA1-B04E-2FB336410BAC} = {5B201255-53C8-490B-A34F-01F05D48A477}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<clear />
|
<clear />
|
||||||
<add key="PowerToysPublicDependencies" value="https://pkgs.dev.azure.com/shine-oss/PowerToys/_packaging/PowerToysPublicDependencies/nuget/v3/index.json" />
|
<add key="PowerToysPublicDependencies" value="https://pkgs.dev.azure.com/shine-oss/PowerToys/_packaging/PowerToysPublicDependencies%40Local/nuget/v3/index.json" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
<packageSourceMapping>
|
<packageSourceMapping>
|
||||||
<packageSource key="PowerToysPublicDependencies">
|
<packageSource key="PowerToysPublicDependencies">
|
||||||
<package pattern="*" />
|
<package pattern="*" />
|
||||||
</packageSource>
|
</packageSource>
|
||||||
</packageSourceMapping>
|
</packageSourceMapping>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -17,6 +17,7 @@ namespace Common.UI
|
|||||||
Awake,
|
Awake,
|
||||||
ColorPicker,
|
ColorPicker,
|
||||||
CmdNotFound,
|
CmdNotFound,
|
||||||
|
LightSwitch,
|
||||||
FancyZones,
|
FancyZones,
|
||||||
FileLocksmith,
|
FileLocksmith,
|
||||||
Run,
|
Run,
|
||||||
@@ -60,6 +61,8 @@ namespace Common.UI
|
|||||||
return "ColorPicker";
|
return "ColorPicker";
|
||||||
case SettingsWindow.CmdNotFound:
|
case SettingsWindow.CmdNotFound:
|
||||||
return "CmdNotFound";
|
return "CmdNotFound";
|
||||||
|
case SettingsWindow.LightSwitch:
|
||||||
|
return "LightSwitch";
|
||||||
case SettingsWindow.FancyZones:
|
case SettingsWindow.FancyZones:
|
||||||
return "FancyZones";
|
return "FancyZones";
|
||||||
case SettingsWindow.FileLocksmith:
|
case SettingsWindow.FileLocksmith:
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
|||||||
{
|
{
|
||||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCropAndLockEnabledValue());
|
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCropAndLockEnabledValue());
|
||||||
}
|
}
|
||||||
|
GpoRuleConfigured GPOWrapper::GetConfiguredLightSwitchEnabledValue()
|
||||||
|
{
|
||||||
|
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredLightSwitchEnabledValue());
|
||||||
|
}
|
||||||
GpoRuleConfigured GPOWrapper::GetConfiguredFancyZonesEnabledValue()
|
GpoRuleConfigured GPOWrapper::GetConfiguredFancyZonesEnabledValue()
|
||||||
{
|
{
|
||||||
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredFancyZonesEnabledValue());
|
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredFancyZonesEnabledValue());
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
|
|||||||
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
|
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
||||||
|
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace PowerToys
|
|||||||
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
|
static GpoRuleConfigured GetConfiguredCmdPalEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
static GpoRuleConfigured GetConfiguredColorPickerEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
static GpoRuleConfigured GetConfiguredCropAndLockEnabledValue();
|
||||||
|
static GpoRuleConfigured GetConfiguredLightSwitchEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
static GpoRuleConfigured GetConfiguredFancyZonesEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
static GpoRuleConfigured GetConfiguredFileLocksmithEnabledValue();
|
||||||
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace ManagedCommon
|
|||||||
ColorPicker,
|
ColorPicker,
|
||||||
CmdPal,
|
CmdPal,
|
||||||
CropAndLock,
|
CropAndLock,
|
||||||
|
LightSwitch,
|
||||||
EnvironmentVariables,
|
EnvironmentVariables,
|
||||||
FancyZones,
|
FancyZones,
|
||||||
FileLocksmith,
|
FileLocksmith,
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ struct LogSettings
|
|||||||
inline const static std::string workspacesSnapshotToolLoggerName = "workspaces-snapshot-tool";
|
inline const static std::string workspacesSnapshotToolLoggerName = "workspaces-snapshot-tool";
|
||||||
inline const static std::wstring workspacesSnapshotToolLogPath = L"workspaces-snapshot-tool-log.log";
|
inline const static std::wstring workspacesSnapshotToolLogPath = L"workspaces-snapshot-tool-log.log";
|
||||||
inline const static std::string zoomItLoggerName = "zoom-it";
|
inline const static std::string zoomItLoggerName = "zoom-it";
|
||||||
|
inline const static std::string lightSwitchLoggerName = "light-switch";
|
||||||
inline const static int retention = 30;
|
inline const static int retention = 30;
|
||||||
std::wstring logLevel;
|
std::wstring logLevel;
|
||||||
LogSettings();
|
LogSettings();
|
||||||
|
|||||||
@@ -257,7 +257,10 @@ inline HANDLE run_elevated(const std::wstring& file, const std::wstring& params,
|
|||||||
exec_info.nShow = SW_HIDE;
|
exec_info.nShow = SW_HIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ShellExecuteExW(&exec_info) ? exec_info.hProcess : nullptr;
|
// failing bc using "runas" with PowerToys.exe already running?
|
||||||
|
BOOL result = ShellExecuteExW(&exec_info);
|
||||||
|
|
||||||
|
return result ? exec_info.hProcess : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run command as non-elevated user, returns true if succeeded, puts the process id into returnPid if returnPid != NULL
|
// Run command as non-elevated user, returns true if succeeded, puts the process id into returnPid if returnPid != NULL
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace powertoys_gpo
|
|||||||
const std::wstring POLICY_CONFIGURE_ENABLED_CMD_NOT_FOUND = L"ConfigureEnabledUtilityCmdNotFound";
|
const std::wstring POLICY_CONFIGURE_ENABLED_CMD_NOT_FOUND = L"ConfigureEnabledUtilityCmdNotFound";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_COLOR_PICKER = L"ConfigureEnabledUtilityColorPicker";
|
const std::wstring POLICY_CONFIGURE_ENABLED_COLOR_PICKER = L"ConfigureEnabledUtilityColorPicker";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK = L"ConfigureEnabledUtilityCropAndLock";
|
const std::wstring POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK = L"ConfigureEnabledUtilityCropAndLock";
|
||||||
|
const std::wstring POLICY_CONFIGURE_ENABLED_LIGHT_SWITCH = L"ConfigureEnabledUtilityLightSwitch";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_FANCYZONES = L"ConfigureEnabledUtilityFancyZones";
|
const std::wstring POLICY_CONFIGURE_ENABLED_FANCYZONES = L"ConfigureEnabledUtilityFancyZones";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_FILE_LOCKSMITH = L"ConfigureEnabledUtilityFileLocksmith";
|
const std::wstring POLICY_CONFIGURE_ENABLED_FILE_LOCKSMITH = L"ConfigureEnabledUtilityFileLocksmith";
|
||||||
const std::wstring POLICY_CONFIGURE_ENABLED_SVG_PREVIEW = L"ConfigureEnabledUtilityFileExplorerSVGPreview";
|
const std::wstring POLICY_CONFIGURE_ENABLED_SVG_PREVIEW = L"ConfigureEnabledUtilityFileExplorerSVGPreview";
|
||||||
@@ -295,6 +296,11 @@ namespace powertoys_gpo
|
|||||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK);
|
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_CROP_AND_LOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline gpo_rule_configured_t getConfiguredLightSwitchEnabledValue()
|
||||||
|
{
|
||||||
|
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_LIGHT_SWITCH);
|
||||||
|
}
|
||||||
|
|
||||||
inline gpo_rule_configured_t getConfiguredFancyZonesEnabledValue()
|
inline gpo_rule_configured_t getConfiguredFancyZonesEnabledValue()
|
||||||
{
|
{
|
||||||
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_FANCYZONES);
|
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_FANCYZONES);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <common/version/version.h>
|
#include <common/version/version.h>
|
||||||
#include <common/SettingsAPI/settings_helpers.h>
|
#include <common/SettingsAPI/settings_helpers.h>
|
||||||
|
#include <common/logger/logger_settings.h>
|
||||||
|
|
||||||
namespace LoggerHelpers
|
namespace LoggerHelpers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -137,6 +137,16 @@
|
|||||||
<decimal value="0" />
|
<decimal value="0" />
|
||||||
</disabledValue>
|
</disabledValue>
|
||||||
</policy>
|
</policy>
|
||||||
|
<policy name="ConfigureEnabledUtilityLightSwitch" class="Both" displayName="$(string.ConfigureEnabledUtilityLightSwitch)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityLightSwitch">
|
||||||
|
<parentCategory ref="PowerToys" />
|
||||||
|
<supportedOn ref="SUPPORTED_POWERTOYS_0_90_0" />
|
||||||
|
<enabledValue>
|
||||||
|
<decimal value="1" />
|
||||||
|
</enabledValue>
|
||||||
|
<disabledValue>
|
||||||
|
<decimal value="0" />
|
||||||
|
</disabledValue>
|
||||||
|
</policy>
|
||||||
<policy name="ConfigureEnabledUtilityEnvironmentVariables" class="Both" displayName="$(string.ConfigureEnabledUtilityEnvironmentVariables)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityEnvironmentVariables">
|
<policy name="ConfigureEnabledUtilityEnvironmentVariables" class="Both" displayName="$(string.ConfigureEnabledUtilityEnvironmentVariables)" explainText="$(string.ConfigureEnabledUtilityDescription)" key="Software\Policies\PowerToys" valueName="ConfigureEnabledUtilityEnvironmentVariables">
|
||||||
<parentCategory ref="PowerToys" />
|
<parentCategory ref="PowerToys" />
|
||||||
<supportedOn ref="SUPPORTED_POWERTOYS_0_75_0" />
|
<supportedOn ref="SUPPORTED_POWERTOYS_0_75_0" />
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ If you don't configure this policy, the user will be able to control the setting
|
|||||||
<string id="ConfigureEnabledUtilityCmdNotFound">Command Not Found: Configure enabled state</string>
|
<string id="ConfigureEnabledUtilityCmdNotFound">Command Not Found: Configure enabled state</string>
|
||||||
<string id="ConfigureEnabledUtilityCmdPal">CmdPal: Configure enabled state</string>
|
<string id="ConfigureEnabledUtilityCmdPal">CmdPal: Configure enabled state</string>
|
||||||
<string id="ConfigureEnabledUtilityCropAndLock">Crop And Lock: Configure enabled state</string>
|
<string id="ConfigureEnabledUtilityCropAndLock">Crop And Lock: Configure enabled state</string>
|
||||||
|
<string id="ConfigureEnabledUtilityLightSwitch">Light Switch: Configure enabled state</string>
|
||||||
<string id="ConfigureEnabledUtilityEnvironmentVariables">Environment Variables: Configure enabled state</string>
|
<string id="ConfigureEnabledUtilityEnvironmentVariables">Environment Variables: Configure enabled state</string>
|
||||||
<string id="ConfigureEnabledUtilityFancyZones">FancyZones: Configure enabled state</string>
|
<string id="ConfigureEnabledUtilityFancyZones">FancyZones: Configure enabled state</string>
|
||||||
<string id="ConfigureEnabledUtilityFileLocksmith">File Locksmith: Configure enabled state</string>
|
<string id="ConfigureEnabledUtilityFileLocksmith">File Locksmith: Configure enabled state</string>
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
1 VERSIONINFO
|
||||||
|
FILEVERSION 0,1,0,0
|
||||||
|
PRODUCTVERSION 0,1,0,0
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x40004L
|
||||||
|
FILETYPE 0x2L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "Company Name"
|
||||||
|
VALUE "FileDescription", "Light Switch Module"
|
||||||
|
VALUE "FileVersion", "0.1.0.0"
|
||||||
|
VALUE "InternalName", "Light Switch"
|
||||||
|
VALUE "LegalCopyright", "Copyright (C) 2019 Company Name"
|
||||||
|
VALUE "OriginalFilename", "PowerToys.LightSwitchModuleInterface.dll"
|
||||||
|
VALUE "ProductName", "Light Switch"
|
||||||
|
VALUE "ProductVersion", "0.1.0.0"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.14.36127.28 d17.14
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LightSwitchModuleInterface", "LightSwitchModuleInterface.vcxproj", "{38177D56-6AD1-4ADF-88C9-2843A7932166}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{38177D56-6AD1-4ADF-88C9-2843A7932166}.Release|x64.Build.0 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {FAF634A3-0D98-4A45-B082-D93B59782572}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|ARM64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>ARM64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|ARM64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>ARM64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{38177d56-6ad1-4adf-88c9-2843a7932166}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>LightSwitchModuleInterface</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
<ProjectName>LightSwitchModuleInterface</ProjectName>
|
||||||
|
<TargetName>PowerToys.LightSwitchModuleInterface</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>
|
||||||
|
$(SolutionDir)src\;
|
||||||
|
$(SolutionDir)src\modules;
|
||||||
|
$(SolutionDir)src\common\Telemetry;
|
||||||
|
%(AdditionalIncludeDirectories)
|
||||||
|
</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(CoreLibraryDependencies);%(AdditionalDependencies);advapi32.lib</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="pch.h" />
|
||||||
|
<ClInclude Include="resource.h" />
|
||||||
|
<ClInclude Include="ThemeHelper.h" />
|
||||||
|
<ClInclude Include="trace.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dllmain.cpp" />
|
||||||
|
<ClCompile Include="pch.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
|
||||||
|
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
|
||||||
|
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">pch.h</PrecompiledHeaderFile>
|
||||||
|
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ThemeHelper.cpp" />
|
||||||
|
<ClCompile Include="trace.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="LightSwitchModuleInterface.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||||
|
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj">
|
||||||
|
<Project>{4aed67b6-55fd-486f-b917-e543dee2cb3c}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||||
|
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||||
|
</ImportGroup>
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||||
|
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dllmain.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="pch.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="trace.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ThemeHelper.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="pch.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="resource.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="trace.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ThemeHelper.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{bbf22ac8-46f8-4206-b44b-9c3897e99ce5}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{530ed784-9a70-46a0-8fb6-20d5dee4f7d3}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{da1cb871-86d3-414c-adf5-a7e9f2077d2f}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="LightSwitchModuleInterface.rc">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include <windows.h>
|
||||||
|
#include "ThemeHelper.h"
|
||||||
|
|
||||||
|
// Controls changing the themes.
|
||||||
|
|
||||||
|
void SetAppsTheme(bool mode)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||||
|
0,
|
||||||
|
KEY_SET_VALUE,
|
||||||
|
&hKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
DWORD value = mode;
|
||||||
|
RegSetValueEx(hKey, L"AppsUseLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
|
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||||
|
|
||||||
|
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSystemTheme(bool mode)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||||
|
0,
|
||||||
|
KEY_SET_VALUE,
|
||||||
|
&hKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
DWORD value = mode;
|
||||||
|
RegSetValueEx(hKey, L"SystemUsesLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
|
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||||
|
|
||||||
|
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetCurrentSystemTheme()
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
DWORD value = 1; // default = light
|
||||||
|
DWORD size = sizeof(value);
|
||||||
|
|
||||||
|
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||||
|
0,
|
||||||
|
KEY_READ,
|
||||||
|
&hKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value == 0; // 0 = dark, 1 = light
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetCurrentAppsTheme()
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
DWORD value = 1;
|
||||||
|
DWORD size = sizeof(value);
|
||||||
|
|
||||||
|
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||||
|
0,
|
||||||
|
KEY_READ,
|
||||||
|
&hKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value == 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
void SetSystemTheme(bool dark);
|
||||||
|
void SetAppsTheme(bool dark);
|
||||||
|
bool GetCurrentSystemTheme();
|
||||||
|
bool GetCurrentAppsTheme();
|
||||||
669
src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp
Normal file
669
src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp
Normal file
@@ -0,0 +1,669 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include <interface/powertoy_module_interface.h>
|
||||||
|
#include "trace.h"
|
||||||
|
#include <common/logger/logger.h>
|
||||||
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
|
#include <common/SettingsAPI/settings_helpers.h>
|
||||||
|
#include <locale>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <common/utils/logger_helper.h>
|
||||||
|
#include "ThemeHelper.h"
|
||||||
|
|
||||||
|
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const wchar_t JSON_KEY_PROPERTIES[] = L"properties";
|
||||||
|
const wchar_t JSON_KEY_WIN[] = L"win";
|
||||||
|
const wchar_t JSON_KEY_ALT[] = L"alt";
|
||||||
|
const wchar_t JSON_KEY_CTRL[] = L"ctrl";
|
||||||
|
const wchar_t JSON_KEY_SHIFT[] = L"shift";
|
||||||
|
const wchar_t JSON_KEY_CODE[] = L"code";
|
||||||
|
const wchar_t JSON_KEY_FORCE_LIGHT_HOTKEY[] = L"force-light-mode-hotkey";
|
||||||
|
const wchar_t JSON_KEY_FORCE_DARK_HOTKEY[] = L"force-dark-mode-hotkey";
|
||||||
|
const wchar_t JSON_KEY_VALUE[] = L"value";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||||
|
{
|
||||||
|
switch (ul_reason_for_call)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
Trace::RegisterProvider();
|
||||||
|
break;
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
break;
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
Trace::UnregisterProvider();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The PowerToy name that will be shown in the settings.
|
||||||
|
const static wchar_t* MODULE_NAME = L"LightSwitch";
|
||||||
|
// Add a description that will we shown in the module settings page.
|
||||||
|
const static wchar_t* MODULE_DESC = L"This is a module that allows you to control light/dark theming via set times, sun rise, or directly invoking the change.";
|
||||||
|
|
||||||
|
enum class ScheduleMode
|
||||||
|
{
|
||||||
|
FixedHours,
|
||||||
|
SunsetToSunriseGeo,
|
||||||
|
SunsetToSunriseUser
|
||||||
|
// add more later
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::wstring ToString(ScheduleMode mode)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case ScheduleMode::SunsetToSunriseGeo:
|
||||||
|
return L"SunsetToSunriseGeo";
|
||||||
|
case ScheduleMode::SunsetToSunriseUser:
|
||||||
|
return L"SunsetToSunriseUser";
|
||||||
|
case ScheduleMode::FixedHours:
|
||||||
|
default:
|
||||||
|
return L"FixedHours";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ScheduleMode FromString(const std::wstring& str)
|
||||||
|
{
|
||||||
|
if (str == L"SunsetToSunriseGeo")
|
||||||
|
return ScheduleMode::SunsetToSunriseGeo;
|
||||||
|
if (str == L"SunsetToSunriseUser")
|
||||||
|
return ScheduleMode::SunsetToSunriseUser;
|
||||||
|
return ScheduleMode::FixedHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the properties shown in the Settings page.
|
||||||
|
struct ModuleSettings
|
||||||
|
{
|
||||||
|
bool m_changeSystem = true;
|
||||||
|
bool m_changeApps = true;
|
||||||
|
ScheduleMode m_scheduleMode = ScheduleMode::FixedHours;
|
||||||
|
int m_lightTime = 480;
|
||||||
|
int m_darkTime = 1200;
|
||||||
|
int m_offset = 0;
|
||||||
|
std::wstring m_latitude = L"0.0";
|
||||||
|
std::wstring m_longitude = L"0.0";
|
||||||
|
} g_settings;
|
||||||
|
|
||||||
|
// Implement the PowerToy Module Interface and all the required methods.
|
||||||
|
class LightSwitchInterface : public PowertoyModuleIface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// The PowerToy state.
|
||||||
|
bool m_enabled = false;
|
||||||
|
|
||||||
|
HANDLE m_process{ nullptr };
|
||||||
|
HANDLE m_force_light_event_handle;
|
||||||
|
HANDLE m_force_dark_event_handle;
|
||||||
|
|
||||||
|
static const constexpr int NUM_DEFAULT_HOTKEYS = 4;
|
||||||
|
|
||||||
|
Hotkey m_force_light_mode_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'L' };
|
||||||
|
Hotkey m_force_dark_mode_hotkey = { .win = true, .ctrl = true, .shift = true, .alt = false, .key = 'D' };
|
||||||
|
|
||||||
|
// Load initial settings from the persisted values.
|
||||||
|
void init_settings();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
LightSwitchInterface()
|
||||||
|
{
|
||||||
|
LoggerHelpers::init_logger(L"LightSwitch", L"ModuleInterface", LogSettings::lightSwitchLoggerName);
|
||||||
|
|
||||||
|
m_force_light_event_handle = CreateDefaultEvent(L"POWEROYS_LIGHTSWITCH_FORCE_LIGHT");
|
||||||
|
m_force_dark_event_handle = CreateDefaultEvent(L"POWEROYS_LIGHTSWITCH_FORCE_DARK");
|
||||||
|
|
||||||
|
init_settings();
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual const wchar_t* get_key() override
|
||||||
|
{
|
||||||
|
return L"LightSwitch"; // your unique key string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the powertoy and free memory
|
||||||
|
virtual void destroy() override
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the display name of the powertoy, this will be cached by the runner
|
||||||
|
virtual const wchar_t* get_name() override
|
||||||
|
{
|
||||||
|
return MODULE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the configured status for the gpo policy for the module
|
||||||
|
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
|
||||||
|
{
|
||||||
|
return powertoys_gpo::getConfiguredLightSwitchEnabledValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return array of the names of all events that this powertoy listens for, with
|
||||||
|
// nullptr as the last element of the array. Nullptr can also be retured for empty
|
||||||
|
// list.
|
||||||
|
//virtual const wchar_t** get_events() override
|
||||||
|
//{
|
||||||
|
// static const wchar_t* events[] = { nullptr };
|
||||||
|
// // Available events:
|
||||||
|
// // - ll_keyboard
|
||||||
|
// // - win_hook_event
|
||||||
|
// //
|
||||||
|
// // static const wchar_t* events[] = { ll_keyboard,
|
||||||
|
// // win_hook_event,
|
||||||
|
// // nullptr };
|
||||||
|
|
||||||
|
// return events;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Return JSON with the configuration options.
|
||||||
|
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||||
|
{
|
||||||
|
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||||
|
|
||||||
|
// Create a Settings object with your module name
|
||||||
|
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||||
|
settings.set_description(MODULE_DESC);
|
||||||
|
settings.set_overview_link(L"https://aka.ms/powertoys");
|
||||||
|
|
||||||
|
// Boolean toggles
|
||||||
|
settings.add_bool_toggle(
|
||||||
|
L"changeSystem",
|
||||||
|
L"Change System Theme",
|
||||||
|
g_settings.m_changeSystem);
|
||||||
|
|
||||||
|
settings.add_bool_toggle(
|
||||||
|
L"changeApps",
|
||||||
|
L"Change Apps Theme",
|
||||||
|
g_settings.m_changeApps);
|
||||||
|
|
||||||
|
settings.add_choice_group(
|
||||||
|
L"scheduleMode",
|
||||||
|
L"Theme schedule mode",
|
||||||
|
ToString(g_settings.m_scheduleMode),
|
||||||
|
{ { L"FixedHours", L"Set hours manually" },
|
||||||
|
{ L"SunsetToSunriseGeo", L"Use sunrise/sunset times (Geolocation)" },
|
||||||
|
{ L"SunsetToSunriseUser", L"Use sunrise/sunset times (User selected)" } });
|
||||||
|
|
||||||
|
// Integer spinners (for time in minutes since midnight)
|
||||||
|
settings.add_int_spinner(
|
||||||
|
L"lightTime",
|
||||||
|
L"Time to switch to light theme (minutes after midnight).",
|
||||||
|
g_settings.m_lightTime,
|
||||||
|
0,
|
||||||
|
1439,
|
||||||
|
1);
|
||||||
|
|
||||||
|
settings.add_int_spinner(
|
||||||
|
L"darkTime",
|
||||||
|
L"Time to switch to dark theme (minutes after midnight).",
|
||||||
|
g_settings.m_darkTime,
|
||||||
|
0,
|
||||||
|
1439,
|
||||||
|
1);
|
||||||
|
|
||||||
|
settings.add_int_spinner(
|
||||||
|
L"offset",
|
||||||
|
L"Time to offset turning on your light/dark themes.",
|
||||||
|
g_settings.m_offset,
|
||||||
|
0,
|
||||||
|
1439,
|
||||||
|
1);
|
||||||
|
|
||||||
|
// Strings for latitude and longitude
|
||||||
|
settings.add_string(
|
||||||
|
L"latitude",
|
||||||
|
L"Your latitude in decimal degrees (e.g. 39.95).",
|
||||||
|
g_settings.m_latitude);
|
||||||
|
|
||||||
|
settings.add_string(
|
||||||
|
L"longitude",
|
||||||
|
L"Your longitude in decimal degrees (e.g. -75.16).",
|
||||||
|
g_settings.m_longitude);
|
||||||
|
|
||||||
|
// One-shot actions (buttons)
|
||||||
|
settings.add_custom_action(
|
||||||
|
L"forceLight",
|
||||||
|
L"Switch immediately to light theme",
|
||||||
|
L"Force Light",
|
||||||
|
L"{}");
|
||||||
|
|
||||||
|
settings.add_custom_action(
|
||||||
|
L"forceDark",
|
||||||
|
L"Switch immediately to dark theme",
|
||||||
|
L"Force Dark",
|
||||||
|
L"{}");
|
||||||
|
|
||||||
|
PowerToysSettings::HotkeyObject lm_hk = PowerToysSettings::HotkeyObject::from_settings(
|
||||||
|
m_force_light_mode_hotkey.win,
|
||||||
|
m_force_light_mode_hotkey.ctrl,
|
||||||
|
m_force_light_mode_hotkey.alt,
|
||||||
|
m_force_light_mode_hotkey.shift,
|
||||||
|
m_force_light_mode_hotkey.key);
|
||||||
|
|
||||||
|
settings.add_hotkey(
|
||||||
|
L"force-light-hotkey",
|
||||||
|
L"Shortcut to force light theme immediately",
|
||||||
|
lm_hk);
|
||||||
|
|
||||||
|
PowerToysSettings::HotkeyObject dm_hk = PowerToysSettings::HotkeyObject::from_settings(
|
||||||
|
m_force_dark_mode_hotkey.win,
|
||||||
|
m_force_dark_mode_hotkey.ctrl,
|
||||||
|
m_force_dark_mode_hotkey.alt,
|
||||||
|
m_force_dark_mode_hotkey.shift,
|
||||||
|
m_force_dark_mode_hotkey.key);
|
||||||
|
|
||||||
|
settings.add_hotkey(
|
||||||
|
L"force-dark-hotkey",
|
||||||
|
L"Shortcut to force dark theme immediately",
|
||||||
|
dm_hk);
|
||||||
|
|
||||||
|
// Serialize to buffer for the PowerToys runner
|
||||||
|
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal from the Settings editor to call a custom action.
|
||||||
|
// This can be used to spawn more complex editors.
|
||||||
|
void call_custom_action(const wchar_t* action) override
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto action_object = PowerToysSettings::CustomActionObject::from_json_string(action);
|
||||||
|
|
||||||
|
if (action_object.get_name() == L"forceLight")
|
||||||
|
{
|
||||||
|
Logger::info(L"[Light Switch] Custom action triggered: Force Light");
|
||||||
|
SetSystemTheme(true);
|
||||||
|
SetAppsTheme(true);
|
||||||
|
}
|
||||||
|
else if (action_object.get_name() == L"forceDark")
|
||||||
|
{
|
||||||
|
Logger::info(L"[Light Switch] Custom action triggered: Force Dark");
|
||||||
|
SetSystemTheme(false);
|
||||||
|
SetAppsTheme(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Logger::error(L"[Light Switch] Invalid custom action JSON");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||||
|
virtual void set_config(const wchar_t* config) override
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto values = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||||
|
|
||||||
|
parse_hotkey(values);
|
||||||
|
|
||||||
|
if (auto v = values.get_bool_value(L"changeSystem"))
|
||||||
|
{
|
||||||
|
g_settings.m_changeSystem = *v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto v = values.get_bool_value(L"changeApps"))
|
||||||
|
{
|
||||||
|
g_settings.m_changeApps = *v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto v = values.get_string_value(L"scheduleMode"))
|
||||||
|
{
|
||||||
|
g_settings.m_scheduleMode = FromString(*v);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto v = values.get_int_value(L"lightTime"))
|
||||||
|
{
|
||||||
|
g_settings.m_lightTime = *v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto v = values.get_int_value(L"darkTime"))
|
||||||
|
{
|
||||||
|
g_settings.m_darkTime = *v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto v = values.get_int_value(L"offset"))
|
||||||
|
{
|
||||||
|
g_settings.m_offset = *v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto v = values.get_string_value(L"latitude"))
|
||||||
|
{
|
||||||
|
g_settings.m_latitude = *v;
|
||||||
|
}
|
||||||
|
if (auto v = values.get_string_value(L"longitude"))
|
||||||
|
{
|
||||||
|
g_settings.m_longitude = *v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
values.save_to_settings_file();
|
||||||
|
}
|
||||||
|
catch (const std::exception&)
|
||||||
|
{
|
||||||
|
Logger::error("[Light Switch] set_config: Failed to parse or apply config.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void enable()
|
||||||
|
{
|
||||||
|
m_enabled = true;
|
||||||
|
Logger::info(L"Enabling Light Switch module...");
|
||||||
|
|
||||||
|
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||||
|
std::wstring args = L"--pid " + std::to_wstring(powertoys_pid);
|
||||||
|
std::wstring exe_name = L"LightSwitchService\\PowerToys.LightSwitchService.exe";
|
||||||
|
|
||||||
|
// Resolve the executable path
|
||||||
|
std::wstring resolved_path(MAX_PATH, L'\0');
|
||||||
|
DWORD result = SearchPathW(
|
||||||
|
nullptr,
|
||||||
|
exe_name.c_str(),
|
||||||
|
nullptr,
|
||||||
|
static_cast<DWORD>(resolved_path.size()),
|
||||||
|
resolved_path.data(),
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
if (result == 0 || result >= resolved_path.size())
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to locate Light Switch executable: '{}'", exe_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved_path.resize(result);
|
||||||
|
Logger::debug(L"Resolved executable path: {}", resolved_path);
|
||||||
|
|
||||||
|
std::wstring command_line = L"\"" + resolved_path + L"\" " + args;
|
||||||
|
|
||||||
|
STARTUPINFO si = { sizeof(si) };
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
|
||||||
|
if (!CreateProcessW(
|
||||||
|
resolved_path.c_str(), // lpApplicationName
|
||||||
|
command_line.data(), // lpCommandLine (must be mutable)
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
TRUE,
|
||||||
|
0,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
&si,
|
||||||
|
&pi))
|
||||||
|
{
|
||||||
|
Logger::error(L"Failed to launch Light Switch process. {}", get_last_error_or_default(GetLastError()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::info(L"Light Switch process launched successfully (PID: {}).", pi.dwProcessId);
|
||||||
|
m_process = pi.hProcess;
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable the powertoy
|
||||||
|
virtual void disable()
|
||||||
|
{
|
||||||
|
Logger::info("Light Switch disabling");
|
||||||
|
m_enabled = false;
|
||||||
|
|
||||||
|
if (m_process)
|
||||||
|
{
|
||||||
|
// Try waiting briefly to allow graceful exit, if needed
|
||||||
|
constexpr DWORD timeout_ms = 1500;
|
||||||
|
DWORD result = WaitForSingleObject(m_process, timeout_ms);
|
||||||
|
|
||||||
|
if (result == WAIT_TIMEOUT)
|
||||||
|
{
|
||||||
|
// Force kill if it didn<64>t exit in time
|
||||||
|
Logger::warn("Light Switch: Process didn't exit in time. Forcing termination.");
|
||||||
|
TerminateProcess(m_process, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always clean up the handle
|
||||||
|
CloseHandle(m_process);
|
||||||
|
m_process = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns if the powertoys is enabled
|
||||||
|
virtual bool is_enabled() override
|
||||||
|
{
|
||||||
|
return m_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_hotkey(PowerToysSettings::PowerToyValues& settings)
|
||||||
|
{
|
||||||
|
auto settingsObject = settings.get_raw_json();
|
||||||
|
if (settingsObject.GetView().Size())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Hotkey _temp_force_light;
|
||||||
|
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_FORCE_LIGHT_HOTKEY).GetNamedObject(JSON_KEY_VALUE);
|
||||||
|
_temp_force_light.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
|
||||||
|
_temp_force_light.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
|
||||||
|
_temp_force_light.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||||
|
_temp_force_light.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||||
|
_temp_force_light.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||||
|
m_force_light_mode_hotkey = _temp_force_light;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Logger::error("Failed to initialize Light Switch force light mode shortcut from settings. Value will keep unchanged.");
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Hotkey _temp_force_dark;
|
||||||
|
auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(JSON_KEY_FORCE_DARK_HOTKEY).GetNamedObject(JSON_KEY_VALUE);
|
||||||
|
_temp_force_dark.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN);
|
||||||
|
_temp_force_dark.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT);
|
||||||
|
_temp_force_dark.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT);
|
||||||
|
_temp_force_dark.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL);
|
||||||
|
_temp_force_dark.key = static_cast<unsigned char>(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE));
|
||||||
|
m_force_dark_mode_hotkey = _temp_force_dark;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Logger::error("Failed to initialize Light Switch force dark mode shortcut from settings. Value will keep unchanged.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::info("Light Switch settings are empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override
|
||||||
|
{
|
||||||
|
if (hotkeys && buffer_size >= 2)
|
||||||
|
{
|
||||||
|
hotkeys[0] = m_force_light_mode_hotkey;
|
||||||
|
hotkeys[1] = m_force_dark_mode_hotkey;
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool on_hotkey(size_t hotkeyId) override
|
||||||
|
{
|
||||||
|
if (m_enabled)
|
||||||
|
{
|
||||||
|
Logger::trace(L"Light Switch hotkey pressed");
|
||||||
|
if (!is_process_running())
|
||||||
|
{
|
||||||
|
enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hotkeyId == 0)
|
||||||
|
{
|
||||||
|
Logger::info(L"[Light Switch] Hotkey triggered: Force Light");
|
||||||
|
SetSystemTheme(true);
|
||||||
|
SetAppsTheme(true);
|
||||||
|
}
|
||||||
|
else if (hotkeyId == 1)
|
||||||
|
{
|
||||||
|
Logger::info(L"[Light Switch] Hotkey triggered: Force Dark");
|
||||||
|
SetSystemTheme(false);
|
||||||
|
SetAppsTheme(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_process_running()
|
||||||
|
{
|
||||||
|
return WaitForSingleObject(m_process, 0) == WAIT_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle incoming event, data is event-specific
|
||||||
|
//virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override
|
||||||
|
//{
|
||||||
|
// if (wcscmp(name, ll_keyboard) == 0)
|
||||||
|
// {
|
||||||
|
// auto& event = *(reinterpret_cast<LowlevelKeyboardEvent*>(data));
|
||||||
|
// // Return 1 if the keypress is to be suppressed (not forwarded to Windows),
|
||||||
|
// // otherwise return 0.
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
// else if (wcscmp(name, win_hook_event) == 0)
|
||||||
|
// {
|
||||||
|
// auto& event = *(reinterpret_cast<WinHookEvent*>(data));
|
||||||
|
// // Return value is ignored
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
// return 0;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//// This methods are part of an experimental features not fully supported yet
|
||||||
|
//virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//virtual void signal_system_menu_action(const wchar_t* name) override
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::wstring utf8_to_wstring(const std::string& str)
|
||||||
|
{
|
||||||
|
if (str.empty())
|
||||||
|
return std::wstring();
|
||||||
|
|
||||||
|
int size_needed = MultiByteToWideChar(
|
||||||
|
CP_UTF8,
|
||||||
|
0,
|
||||||
|
str.c_str(),
|
||||||
|
static_cast<int>(str.size()),
|
||||||
|
nullptr,
|
||||||
|
0);
|
||||||
|
|
||||||
|
std::wstring wstr(size_needed, 0);
|
||||||
|
|
||||||
|
MultiByteToWideChar(
|
||||||
|
CP_UTF8,
|
||||||
|
0,
|
||||||
|
str.c_str(),
|
||||||
|
static_cast<int>(str.size()),
|
||||||
|
&wstr[0],
|
||||||
|
size_needed);
|
||||||
|
|
||||||
|
return wstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the settings file.
|
||||||
|
void LightSwitchInterface::init_settings()
|
||||||
|
{
|
||||||
|
Logger::info(L"[Light Switch] init_settings: starting to load settings for module");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PowerToysSettings::PowerToyValues settings =
|
||||||
|
PowerToysSettings::PowerToyValues::load_from_settings_file(get_name());
|
||||||
|
|
||||||
|
parse_hotkey(settings);
|
||||||
|
|
||||||
|
if (auto v = settings.get_bool_value(L"changeSystem"))
|
||||||
|
g_settings.m_changeSystem = *v;
|
||||||
|
if (auto v = settings.get_bool_value(L"changeApps"))
|
||||||
|
g_settings.m_changeApps = *v;
|
||||||
|
if (auto v = settings.get_string_value(L"scheduleMode"))
|
||||||
|
g_settings.m_scheduleMode = FromString(*v);
|
||||||
|
if (auto v = settings.get_int_value(L"lightTime"))
|
||||||
|
g_settings.m_lightTime = *v;
|
||||||
|
if (auto v = settings.get_int_value(L"darkTime"))
|
||||||
|
g_settings.m_darkTime = *v;
|
||||||
|
if (auto v = settings.get_int_value(L"offset"))
|
||||||
|
g_settings.m_offset = *v;
|
||||||
|
if (auto v = settings.get_string_value(L"latitude"))
|
||||||
|
g_settings.m_latitude = *v;
|
||||||
|
if (auto v = settings.get_string_value(L"longitude"))
|
||||||
|
g_settings.m_longitude = *v;
|
||||||
|
|
||||||
|
Logger::info(L"[Light Switch] init_settings: loaded successfully");
|
||||||
|
}
|
||||||
|
catch (const winrt::hresult_error& e)
|
||||||
|
{
|
||||||
|
Logger::error(L"[Light Switch] init_settings: hresult_error 0x{:08X} - {}", e.code(), e.message().c_str());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
std::wstring whatStr = utf8_to_wstring(e.what());
|
||||||
|
Logger::error(L"[Light Switch] init_settings: std::exception - {}", whatStr);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Logger::error(L"[Light Switch] init_settings: unknown exception while loading settings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method of saving the module settings is only required if you need to do any
|
||||||
|
// custom processing of the settings before saving them to disk.
|
||||||
|
//void $projectname$::save_settings() {
|
||||||
|
// try {
|
||||||
|
// // Create a PowerToyValues object for this PowerToy
|
||||||
|
// PowerToysSettings::PowerToyValues values(get_name());
|
||||||
|
//
|
||||||
|
// // Save a bool property.
|
||||||
|
// //values.add_property(
|
||||||
|
// // L"bool_toggle_1", // property name
|
||||||
|
// // g_settings.bool_prop // property value
|
||||||
|
// // g_settings.bool_prop // property value
|
||||||
|
// //);
|
||||||
|
//
|
||||||
|
// // Save an int property.
|
||||||
|
// //values.add_property(
|
||||||
|
// // L"int_spinner_1", // property name
|
||||||
|
// // g_settings.int_prop // property value
|
||||||
|
// //);
|
||||||
|
//
|
||||||
|
// // Save a string property.
|
||||||
|
// //values.add_property(
|
||||||
|
// // L"string_text_1", // property name
|
||||||
|
// // g_settings.string_prop // property value
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// // Save a color property.
|
||||||
|
// //values.add_property(
|
||||||
|
// // L"color_picker_1", // property name
|
||||||
|
// // g_settings.color_prop // property value
|
||||||
|
// //);
|
||||||
|
//
|
||||||
|
// // Save the PowerToyValues JSON to the power toy settings file.
|
||||||
|
// values.save_to_settings_file();
|
||||||
|
// }
|
||||||
|
// catch (std::exception ex) {
|
||||||
|
// // Couldn't save the settings.
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||||
|
{
|
||||||
|
return new LightSwitchInterface();
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#pragma comment(lib, "windowsapp")
|
||||||
14
src/modules/LightSwitch/LightSwitchModuleInterface/pch.h
Normal file
14
src/modules/LightSwitch/LightSwitchModuleInterface/pch.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <common/SettingsAPI/settings_helpers.h>
|
||||||
|
#include <common/utils/gpo.h>
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <winrt/Windows.Foundation.h>
|
||||||
|
#include <winrt/Windows.System.h>
|
||||||
|
#include <winrt/Windows.Globalization.h>
|
||||||
|
#include <winrt/Windows.ApplicationModel.h>
|
||||||
|
#include <winrt/Windows.ApplicationModel.Core.h>
|
||||||
30
src/modules/LightSwitch/LightSwitchModuleInterface/trace.cpp
Normal file
30
src/modules/LightSwitch/LightSwitchModuleInterface/trace.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include <TraceLoggingProvider.h>
|
||||||
|
|
||||||
|
TRACELOGGING_DEFINE_PROVIDER(
|
||||||
|
g_hProvider,
|
||||||
|
"Microsoft.PowerToys",
|
||||||
|
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||||
|
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||||
|
TraceLoggingOptionProjectTelemetry());
|
||||||
|
|
||||||
|
void Trace::RegisterProvider()
|
||||||
|
{
|
||||||
|
TraceLoggingRegister(g_hProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::UnregisterProvider()
|
||||||
|
{
|
||||||
|
TraceLoggingUnregister(g_hProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::MyEvent()
|
||||||
|
{
|
||||||
|
TraceLoggingWrite(
|
||||||
|
g_hProvider,
|
||||||
|
"PowerToyName_MyEvent",
|
||||||
|
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||||
|
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||||
|
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||||
|
}
|
||||||
15
src/modules/LightSwitch/LightSwitchModuleInterface/trace.h
Normal file
15
src/modules/LightSwitch/LightSwitchModuleInterface/trace.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <TraceLoggingActivity.h>
|
||||||
|
#include <common/telemetry/ProjectTelemetry.h>
|
||||||
|
|
||||||
|
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
|
||||||
|
|
||||||
|
class Trace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void RegisterProvider();
|
||||||
|
static void UnregisterProvider();
|
||||||
|
static void MyEvent();
|
||||||
|
};
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include "ThemeScheduler.h"
|
||||||
|
#include "ThemeHelper.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
#include <LightSwitchSettings.h>
|
||||||
|
#include <common/utils/gpo.h>
|
||||||
|
|
||||||
|
// Global service variables
|
||||||
|
SERVICE_STATUS g_ServiceStatus = {};
|
||||||
|
SERVICE_STATUS_HANDLE g_StatusHandle = nullptr;
|
||||||
|
HANDLE g_ServiceStopEvent = nullptr;
|
||||||
|
|
||||||
|
// Forward declarations of service functions (we<77>ll define them later)
|
||||||
|
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
|
||||||
|
VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl);
|
||||||
|
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
|
||||||
|
|
||||||
|
// Entry point for the executable
|
||||||
|
int _tmain(int argc, TCHAR* argv[])
|
||||||
|
{
|
||||||
|
// Parse args
|
||||||
|
DWORD parentPid = 0;
|
||||||
|
bool debug = false;
|
||||||
|
for (int i = 1; i < argc; ++i)
|
||||||
|
{
|
||||||
|
if (_tcscmp(argv[i], _T("--debug")) == 0)
|
||||||
|
debug = true;
|
||||||
|
else if (_tcscmp(argv[i], _T("--pid")) == 0 && i + 1 < argc)
|
||||||
|
parentPid = _tstoi(argv[++i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
// Create a console window for debug output
|
||||||
|
AllocConsole();
|
||||||
|
FILE* f;
|
||||||
|
freopen_s(&f, "CONOUT$", "w", stdout);
|
||||||
|
freopen_s(&f, "CONOUT$", "w", stderr);
|
||||||
|
|
||||||
|
// Optional: set a title so you can find it easily
|
||||||
|
SetConsoleTitle(L"LightSwitchService Debug");
|
||||||
|
|
||||||
|
// Console mode (debug)
|
||||||
|
g_ServiceStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
|
ServiceWorkerThread(reinterpret_cast<void*>(static_cast<ULONG_PTR>(parentPid)));
|
||||||
|
CloseHandle(g_ServiceStopEvent);
|
||||||
|
|
||||||
|
// Keep window open until a key is pressed (optional)
|
||||||
|
// system("pause");
|
||||||
|
|
||||||
|
FreeConsole();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to connect to SCM
|
||||||
|
wchar_t serviceName[] = L"LightSwitchService";
|
||||||
|
SERVICE_TABLE_ENTRYW table[] = { { serviceName, ServiceMain }, { nullptr, nullptr } };
|
||||||
|
|
||||||
|
if (!StartServiceCtrlDispatcherW(table))
|
||||||
|
{
|
||||||
|
DWORD err = GetLastError();
|
||||||
|
if (err == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) // not launched by SCM
|
||||||
|
{
|
||||||
|
g_ServiceStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
|
HANDLE hThread = CreateThread(
|
||||||
|
nullptr, 0, ServiceWorkerThread, reinterpret_cast<void*>(static_cast<ULONG_PTR>(parentPid)), 0, nullptr);
|
||||||
|
|
||||||
|
// Wait so the process stays alive
|
||||||
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
|
CloseHandle(hThread);
|
||||||
|
CloseHandle(g_ServiceStopEvent);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return static_cast<int>(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when the service is launched by Windows
|
||||||
|
VOID WINAPI ServiceMain(DWORD, LPTSTR*)
|
||||||
|
{
|
||||||
|
g_StatusHandle = RegisterServiceCtrlHandler(_T("LightSwitchService"), ServiceCtrlHandler);
|
||||||
|
if (!g_StatusHandle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||||
|
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||||
|
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
||||||
|
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||||
|
|
||||||
|
g_ServiceStopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
|
if (!g_ServiceStopEvent)
|
||||||
|
{
|
||||||
|
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||||
|
g_ServiceStatus.dwWin32ExitCode = GetLastError();
|
||||||
|
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECURITY_ATTRIBUTES sa{ sizeof(sa) };
|
||||||
|
sa.bInheritHandle = FALSE;
|
||||||
|
sa.lpSecurityDescriptor = nullptr;
|
||||||
|
|
||||||
|
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
||||||
|
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||||
|
|
||||||
|
HANDLE hThread = CreateThread(nullptr, 0, ServiceWorkerThread, nullptr, 0, nullptr);
|
||||||
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
|
CloseHandle(hThread);
|
||||||
|
|
||||||
|
CloseHandle(g_ServiceStopEvent);
|
||||||
|
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||||
|
g_ServiceStatus.dwWin32ExitCode = 0;
|
||||||
|
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl)
|
||||||
|
{
|
||||||
|
switch (dwCtrl)
|
||||||
|
{
|
||||||
|
case SERVICE_CONTROL_STOP:
|
||||||
|
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
|
||||||
|
break;
|
||||||
|
|
||||||
|
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
||||||
|
SetServiceStatus(g_StatusHandle, &g_ServiceStatus);
|
||||||
|
|
||||||
|
// Signal the service to stop
|
||||||
|
SetEvent(g_ServiceStopEvent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||||
|
{
|
||||||
|
DWORD parentPid = static_cast<DWORD>(reinterpret_cast<ULONG_PTR>(lpParam));
|
||||||
|
HANDLE hParent = nullptr;
|
||||||
|
if (parentPid)
|
||||||
|
hParent = OpenProcess(SYNCHRONIZE, FALSE, parentPid);
|
||||||
|
|
||||||
|
OutputDebugString(L"[LightSwitchService] Worker thread starting...\n");
|
||||||
|
|
||||||
|
// Initialize settings system
|
||||||
|
LightSwitchSettings::instance().InitFileWatcher();
|
||||||
|
|
||||||
|
auto applyTheme = [](int nowMinutes, int lightMinutes, int darkMinutes, const auto& settings) {
|
||||||
|
bool isLightActive = false;
|
||||||
|
|
||||||
|
if (lightMinutes < darkMinutes)
|
||||||
|
{
|
||||||
|
// Normal case: sunrise < sunset
|
||||||
|
isLightActive = (nowMinutes >= lightMinutes && nowMinutes < darkMinutes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Wraparound case: e.g. light at 21:00, dark at 06:00
|
||||||
|
isLightActive = (nowMinutes >= lightMinutes || nowMinutes < darkMinutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLightActive)
|
||||||
|
{
|
||||||
|
if (settings.changeSystem)
|
||||||
|
SetSystemTheme(true);
|
||||||
|
if (settings.changeApps)
|
||||||
|
SetAppsTheme(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (settings.changeSystem)
|
||||||
|
SetSystemTheme(false);
|
||||||
|
if (settings.changeApps)
|
||||||
|
SetAppsTheme(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- At service start: immediately honor the schedule ---
|
||||||
|
{
|
||||||
|
SYSTEMTIME st;
|
||||||
|
GetLocalTime(&st);
|
||||||
|
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||||
|
|
||||||
|
LightSwitchSettings::instance().LoadSettings();
|
||||||
|
const auto& settings = LightSwitchSettings::instance().settings();
|
||||||
|
|
||||||
|
applyTheme(nowMinutes, settings.lightTime + settings.offset, settings.darkTime + settings.offset, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Main loop: wakes once per minute or stop/parent death ---
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
HANDLE waits[2] = { g_ServiceStopEvent, hParent };
|
||||||
|
DWORD count = hParent ? 2 : 1;
|
||||||
|
|
||||||
|
SYSTEMTIME st;
|
||||||
|
GetLocalTime(&st);
|
||||||
|
int nowMinutes = st.wHour * 60 + st.wMinute;
|
||||||
|
|
||||||
|
LightSwitchSettings::instance().LoadSettings();
|
||||||
|
const auto& settings = LightSwitchSettings::instance().settings();
|
||||||
|
|
||||||
|
// Debug print
|
||||||
|
wchar_t msg[160];
|
||||||
|
swprintf_s(msg,
|
||||||
|
L"[LightSwitchService] now=%02d:%02d | light=%02d:%02d | dark=%02d:%02d\n",
|
||||||
|
st.wHour,
|
||||||
|
st.wMinute,
|
||||||
|
settings.lightTime / 60,
|
||||||
|
settings.lightTime % 60,
|
||||||
|
settings.darkTime / 60,
|
||||||
|
settings.darkTime % 60);
|
||||||
|
OutputDebugString(msg);
|
||||||
|
|
||||||
|
// Apply theme logic
|
||||||
|
applyTheme(nowMinutes, settings.lightTime + settings.offset, settings.darkTime + settings.offset, settings);
|
||||||
|
|
||||||
|
// Sleep until next minute, wake early if stop/parent dies
|
||||||
|
GetLocalTime(&st);
|
||||||
|
int msToNextMinute = (60 - st.wSecond) * 1000 - st.wMilliseconds;
|
||||||
|
if (msToNextMinute < 50)
|
||||||
|
msToNextMinute = 50;
|
||||||
|
|
||||||
|
DWORD wait = WaitForMultipleObjects(count, waits, FALSE, msToNextMinute);
|
||||||
|
if (wait == WAIT_OBJECT_0) // stop event
|
||||||
|
break;
|
||||||
|
if (hParent && wait == WAIT_OBJECT_0 + 1) // parent exited
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hParent)
|
||||||
|
CloseHandle(hParent);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
|
||||||
|
{
|
||||||
|
if (powertoys_gpo::getConfiguredLightSwitchEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled)
|
||||||
|
{
|
||||||
|
wchar_t msg[160];
|
||||||
|
swprintf_s(
|
||||||
|
msg,
|
||||||
|
L"Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.\n");
|
||||||
|
OutputDebugString(msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int argc = 0;
|
||||||
|
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||||
|
int rc = _tmain(argc, argv); // reuse your existing logic
|
||||||
|
LocalFree(argv);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|ARM64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>ARM64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|ARM64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>ARM64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>17.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{08e71c67-6a7e-4ca1-b04e-2fb336410bac}</ProjectGuid>
|
||||||
|
<RootNamespace>LightSwitchService</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
|
||||||
|
<ProjectName>LightSwitchService</ProjectName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v143</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||||
|
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
|
||||||
|
<TargetName>PowerToys.LightSwitchService</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
|
<AdditionalIncludeDirectories>
|
||||||
|
./../;
|
||||||
|
$(SolutionDir)src\common\Telemetry;
|
||||||
|
$(SolutionDir)src\common;
|
||||||
|
$(SolutionDir)src\;
|
||||||
|
$(SolutionDir)deps\spdlog\include;
|
||||||
|
./;
|
||||||
|
%(AdditionalIncludeDirectories)
|
||||||
|
</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>Advapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||||
|
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||||
|
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\common\notifications\notifications.vcxproj">
|
||||||
|
<Project>{1d5be09d-78c0-4fd7-af00-ae7c1af7c525}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\common\Telemetry\EtwTrace\EtwTrace.vcxproj">
|
||||||
|
<Project>{8f021b46-362b-485c-bfba-ccf83e820cbd}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\..\common\SettingsAPI\FileWatcher.cpp" />
|
||||||
|
<ClCompile Include="..\..\..\common\SettingsAPI\settings_helpers.cpp" />
|
||||||
|
<ClCompile Include="..\..\..\common\SettingsAPI\settings_objects.cpp" />
|
||||||
|
<ClCompile Include="LightSwitchService.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LightSwitchSettings.cpp" />
|
||||||
|
<ClCompile Include="SettingsConstants.cpp" />
|
||||||
|
<ClCompile Include="ThemeHelper.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ThemeScheduler.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">NotUsing</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="WinHookEventIDs.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="LightSwitchSettings.h" />
|
||||||
|
<ClInclude Include="SettingsConstants.h" />
|
||||||
|
<ClInclude Include="SettingsObserver.h" />
|
||||||
|
<ClInclude Include="ThemeHelper.h" />
|
||||||
|
<ClInclude Include="ThemeScheduler.h">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">false</ExcludedFromBuild>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="WinHookEventIDs.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||||
|
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||||
|
</ImportGroup>
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||||
|
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||||
|
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="LightSwitchService.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ThemeScheduler.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ThemeHelper.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\common\SettingsAPI\settings_helpers.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\common\SettingsAPI\settings_objects.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\common\SettingsAPI\FileWatcher.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="LightSwitchSettings.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SettingsConstants.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="WinHookEventIDs.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="ThemeScheduler.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ThemeHelper.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="LightSwitchSettings.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SettingsConstants.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SettingsObserver.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="WinHookEventIDs.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
#include "LightSwitchSettings.h"
|
||||||
|
#include <common/utils/json.h>
|
||||||
|
#include <common/SettingsAPI/settings_helpers.h>
|
||||||
|
#include "SettingsObserver.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <WinHookEventIDs.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
LightSwitchSettings& LightSwitchSettings::instance()
|
||||||
|
{
|
||||||
|
static LightSwitchSettings inst;
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
LightSwitchSettings::LightSwitchSettings()
|
||||||
|
{
|
||||||
|
LoadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring LightSwitchSettings::GetSettingsFileName()
|
||||||
|
{
|
||||||
|
// Mirrors AlwaysOnTop: <module name>.json
|
||||||
|
return PTSettingsHelper::get_module_save_file_location(L"LightSwitch");
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightSwitchSettings::InitFileWatcher()
|
||||||
|
{
|
||||||
|
const std::wstring& settingsFileName = GetSettingsFileName();
|
||||||
|
m_settingsFileWatcher = std::make_unique<FileWatcher>(settingsFileName, [&]() {
|
||||||
|
PostMessageW(HWND_BROADCAST, WM_PRIV_SETTINGS_CHANGED, NULL, NULL);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightSwitchSettings::AddObserver(SettingsObserver& observer)
|
||||||
|
{
|
||||||
|
m_observers.insert(&observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightSwitchSettings::RemoveObserver(SettingsObserver& observer)
|
||||||
|
{
|
||||||
|
m_observers.erase(&observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightSwitchSettings::NotifyObservers(SettingId id) const
|
||||||
|
{
|
||||||
|
for (auto observer : m_observers)
|
||||||
|
{
|
||||||
|
if (observer->WantsToBeNotified(id))
|
||||||
|
{
|
||||||
|
observer->SettingsUpdate(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightSwitchSettings::LoadSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PowerToysSettings::PowerToyValues values =
|
||||||
|
PowerToysSettings::PowerToyValues::load_from_settings_file(L"LightSwitch");
|
||||||
|
|
||||||
|
|
||||||
|
if (const auto jsonVal = values.get_string_value(L"scheduleMode"))
|
||||||
|
{
|
||||||
|
auto val = *jsonVal;
|
||||||
|
auto newMode = FromString(val);
|
||||||
|
if (m_settings.scheduleMode != newMode)
|
||||||
|
{
|
||||||
|
m_settings.scheduleMode = newMode;
|
||||||
|
NotifyObservers(SettingId::ScheduleMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latitude
|
||||||
|
if (const auto jsonVal = values.get_string_value(L"latitude"))
|
||||||
|
{
|
||||||
|
auto val = *jsonVal;
|
||||||
|
if (m_settings.latitude != val)
|
||||||
|
{
|
||||||
|
m_settings.latitude = val;
|
||||||
|
NotifyObservers(SettingId::Latitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Longitude
|
||||||
|
if (const auto jsonVal = values.get_string_value(L"longitude"))
|
||||||
|
{
|
||||||
|
auto val = *jsonVal;
|
||||||
|
if (m_settings.longitude != val)
|
||||||
|
{
|
||||||
|
m_settings.longitude = val;
|
||||||
|
NotifyObservers(SettingId::Longitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LightTime
|
||||||
|
if (const auto jsonVal = values.get_int_value(L"lightTime"))
|
||||||
|
{
|
||||||
|
auto val = *jsonVal;
|
||||||
|
if (m_settings.lightTime != val)
|
||||||
|
{
|
||||||
|
m_settings.lightTime = val;
|
||||||
|
NotifyObservers(SettingId::LightTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DarkTime
|
||||||
|
if (const auto jsonVal = values.get_int_value(L"darkTime"))
|
||||||
|
{
|
||||||
|
auto val = *jsonVal;
|
||||||
|
if (m_settings.darkTime != val)
|
||||||
|
{
|
||||||
|
m_settings.darkTime = val;
|
||||||
|
NotifyObservers(SettingId::DarkTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeSystem
|
||||||
|
if (const auto jsonVal = values.get_bool_value(L"changeSystem"))
|
||||||
|
{
|
||||||
|
auto val = *jsonVal;
|
||||||
|
if (m_settings.changeSystem != val)
|
||||||
|
{
|
||||||
|
m_settings.changeSystem = val;
|
||||||
|
NotifyObservers(SettingId::ChangeSystem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeApps
|
||||||
|
if (const auto jsonVal = values.get_bool_value(L"changeApps"))
|
||||||
|
{
|
||||||
|
auto val = *jsonVal;
|
||||||
|
if (m_settings.changeApps != val)
|
||||||
|
{
|
||||||
|
m_settings.changeApps = val;
|
||||||
|
NotifyObservers(SettingId::ChangeApps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
//Logger::error(L"[LightSwitchSettings] Failed to read settings file");
|
||||||
|
// Keeps defaults if load fails
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <common/SettingsAPI/FileWatcher.h>
|
||||||
|
#include <common/SettingsAPI/settings_objects.h>
|
||||||
|
#include <SettingsConstants.h>
|
||||||
|
|
||||||
|
class SettingsObserver;
|
||||||
|
|
||||||
|
enum class ScheduleMode
|
||||||
|
{
|
||||||
|
FixedHours,
|
||||||
|
SunsetToSunrise
|
||||||
|
// Add more in the future
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::wstring ToString(ScheduleMode mode)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case ScheduleMode::FixedHours:
|
||||||
|
return L"FixedHours";
|
||||||
|
case ScheduleMode::SunsetToSunrise:
|
||||||
|
return L"SunsetToSunrise";
|
||||||
|
default:
|
||||||
|
return L"FixedHours";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ScheduleMode FromString(const std::wstring& str)
|
||||||
|
{
|
||||||
|
if (str == L"SunsetToSunrise")
|
||||||
|
return ScheduleMode::SunsetToSunrise;
|
||||||
|
else
|
||||||
|
return ScheduleMode::FixedHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LightSwitchConfig
|
||||||
|
{
|
||||||
|
ScheduleMode scheduleMode = ScheduleMode::FixedHours;
|
||||||
|
|
||||||
|
std::wstring latitude = L"0.0";
|
||||||
|
std::wstring longitude = L"0.0";
|
||||||
|
|
||||||
|
// Stored as minutes since midnight
|
||||||
|
int lightTime = 8 * 60; // 08:00 default
|
||||||
|
int darkTime = 20 * 60; // 20:00 default
|
||||||
|
|
||||||
|
int offset = 0; // offset in minutes to apply to calculated times
|
||||||
|
|
||||||
|
bool changeSystem = false;
|
||||||
|
bool changeApps = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LightSwitchSettings
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static LightSwitchSettings& instance();
|
||||||
|
|
||||||
|
static inline const LightSwitchConfig& settings()
|
||||||
|
{
|
||||||
|
return instance().m_settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitFileWatcher();
|
||||||
|
static std::wstring GetSettingsFileName();
|
||||||
|
|
||||||
|
void AddObserver(SettingsObserver& observer);
|
||||||
|
void RemoveObserver(SettingsObserver& observer);
|
||||||
|
|
||||||
|
void LoadSettings();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LightSwitchSettings();
|
||||||
|
~LightSwitchSettings() = default;
|
||||||
|
|
||||||
|
LightSwitchConfig m_settings;
|
||||||
|
std::unique_ptr<FileWatcher> m_settingsFileWatcher;
|
||||||
|
std::unordered_set<SettingsObserver*> m_observers;
|
||||||
|
|
||||||
|
void NotifyObservers(SettingId id) const;
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include "SettingsConstants.h"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class SettingId
|
||||||
|
{
|
||||||
|
ScheduleMode = 0,
|
||||||
|
Latitude,
|
||||||
|
Longitude,
|
||||||
|
LightTime,
|
||||||
|
DarkTime,
|
||||||
|
ChangeSystem,
|
||||||
|
ChangeApps
|
||||||
|
};
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include "SettingsConstants.h"
|
||||||
|
|
||||||
|
class LightSwitchSettings;
|
||||||
|
|
||||||
|
class SettingsObserver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SettingsObserver(std::unordered_set<SettingId> observedSettings) :
|
||||||
|
m_observedSettings(std::move(observedSettings))
|
||||||
|
{
|
||||||
|
LightSwitchSettings::instance().AddObserver(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~SettingsObserver()
|
||||||
|
{
|
||||||
|
LightSwitchSettings::instance().RemoveObserver(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override this in your class to respond to updates
|
||||||
|
virtual void SettingsUpdate(SettingId type) {}
|
||||||
|
|
||||||
|
bool WantsToBeNotified(SettingId type) const noexcept
|
||||||
|
{
|
||||||
|
return m_observedSettings.contains(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unordered_set<SettingId> m_observedSettings;
|
||||||
|
};
|
||||||
80
src/modules/LightSwitch/LightSwitchService/ThemeHelper.cpp
Normal file
80
src/modules/LightSwitch/LightSwitchService/ThemeHelper.cpp
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include "ThemeHelper.h"
|
||||||
|
|
||||||
|
// Controls changing the themes.
|
||||||
|
|
||||||
|
void SetAppsTheme(bool mode)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||||
|
0,
|
||||||
|
KEY_SET_VALUE,
|
||||||
|
&hKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
DWORD value = mode;
|
||||||
|
RegSetValueEx(hKey, L"AppsUseLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
|
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||||
|
|
||||||
|
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSystemTheme(bool mode)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||||
|
0,
|
||||||
|
KEY_SET_VALUE,
|
||||||
|
&hKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
DWORD value = mode;
|
||||||
|
RegSetValueEx(hKey, L"SystemUsesLightTheme", 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
|
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast<LPARAM>(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||||
|
|
||||||
|
SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetCurrentSystemTheme()
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
DWORD value = 1; // default = light
|
||||||
|
DWORD size = sizeof(value);
|
||||||
|
|
||||||
|
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||||
|
0,
|
||||||
|
KEY_READ,
|
||||||
|
&hKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value == 0; // 0 = dark, 1 = light
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetCurrentAppsTheme()
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
DWORD value = 1;
|
||||||
|
DWORD size = sizeof(value);
|
||||||
|
|
||||||
|
if (RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
||||||
|
0,
|
||||||
|
KEY_READ,
|
||||||
|
&hKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value == 0;
|
||||||
|
}
|
||||||
5
src/modules/LightSwitch/LightSwitchService/ThemeHelper.h
Normal file
5
src/modules/LightSwitch/LightSwitchService/ThemeHelper.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
void SetSystemTheme(bool dark);
|
||||||
|
void SetAppsTheme(bool dark);
|
||||||
|
bool GetCurrentSystemTheme();
|
||||||
|
bool GetCurrentAppsTheme();
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#include "ThemeScheduler.h"
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
SunTimes CalculateSunriseSunset(double latitude, double longitude, int year, int month, int day)
|
||||||
|
{
|
||||||
|
double zenith = 90.833;
|
||||||
|
int N1 = static_cast<int>(floor(275.0 * month / 9.0));
|
||||||
|
int N2 = static_cast<int>(floor((static_cast<double>(month) + 9) / 12.0));
|
||||||
|
int N3 = static_cast<int>(floor((1.0 + floor((year - 4.0 * floor(year / 4.0) + 2.0) / 3.0))));
|
||||||
|
int N = N1 - (N2 * N3) + day - 30;
|
||||||
|
|
||||||
|
auto calcTime = [&](bool sunrise) -> double {
|
||||||
|
double lngHour = longitude / 15.0;
|
||||||
|
double t = sunrise ? N + ((6 - lngHour) / 24) : N + ((18 - lngHour) / 24);
|
||||||
|
|
||||||
|
double M = (0.9856 * t) - 3.289;
|
||||||
|
double L = M + (1.916 * sin(deg2rad(M))) + (0.020 * sin(2 * deg2rad(M))) + 282.634;
|
||||||
|
if (L < 0)
|
||||||
|
L += 360;
|
||||||
|
if (L > 360)
|
||||||
|
L -= 360;
|
||||||
|
|
||||||
|
double RA = rad2deg(atan(0.91764 * tan(deg2rad(L))));
|
||||||
|
if (RA < 0)
|
||||||
|
RA += 360;
|
||||||
|
if (RA > 360)
|
||||||
|
RA -= 360;
|
||||||
|
|
||||||
|
double Lquadrant = floor(L / 90) * 90;
|
||||||
|
double RAquadrant = floor(RA / 90) * 90;
|
||||||
|
RA = RA + (Lquadrant - RAquadrant);
|
||||||
|
RA /= 15;
|
||||||
|
|
||||||
|
double sinDec = 0.39782 * sin(deg2rad(L));
|
||||||
|
double cosDec = cos(asin(sinDec));
|
||||||
|
|
||||||
|
double cosH = (cos(deg2rad(zenith)) - (sinDec * sin(deg2rad(latitude)))) / (cosDec * cos(deg2rad(latitude)));
|
||||||
|
if (cosH > 1 || cosH < -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
double H = sunrise ? 360 - rad2deg(acos(cosH)) : rad2deg(acos(cosH));
|
||||||
|
H /= 15;
|
||||||
|
|
||||||
|
double T = H + RA - (0.06571 * t) - 6.622;
|
||||||
|
double UT = T - lngHour;
|
||||||
|
while (UT < 0)
|
||||||
|
UT += 24;
|
||||||
|
while (UT >= 24)
|
||||||
|
UT -= 24;
|
||||||
|
|
||||||
|
return UT;
|
||||||
|
};
|
||||||
|
|
||||||
|
double riseUT = calcTime(true);
|
||||||
|
double setUT = calcTime(false);
|
||||||
|
|
||||||
|
auto toLocal = [](double UT) {
|
||||||
|
TIME_ZONE_INFORMATION tz;
|
||||||
|
DWORD state = GetTimeZoneInformation(&tz);
|
||||||
|
double totalBias = tz.Bias;
|
||||||
|
|
||||||
|
if (state == TIME_ZONE_ID_DAYLIGHT)
|
||||||
|
totalBias += tz.DaylightBias;
|
||||||
|
else if (state == TIME_ZONE_ID_STANDARD)
|
||||||
|
totalBias += tz.StandardBias;
|
||||||
|
|
||||||
|
double biasHours = -(totalBias / 60.0);
|
||||||
|
double localTime = UT + biasHours;
|
||||||
|
|
||||||
|
while (localTime < 0)
|
||||||
|
localTime += 24;
|
||||||
|
while (localTime >= 24)
|
||||||
|
localTime -= 24;
|
||||||
|
|
||||||
|
int hour = static_cast<int>(localTime);
|
||||||
|
int minute = static_cast<int>((localTime - hour) * 60);
|
||||||
|
return std::pair<int, int>{ hour, minute };
|
||||||
|
};
|
||||||
|
|
||||||
|
auto [riseHour, riseMinute] = toLocal(riseUT);
|
||||||
|
auto [setHour, setMinute] = toLocal(setUT);
|
||||||
|
|
||||||
|
SunTimes result;
|
||||||
|
result.sunriseHour = riseHour;
|
||||||
|
result.sunriseMinute = riseMinute;
|
||||||
|
result.sunsetHour = setHour;
|
||||||
|
result.sunsetMinute = setMinute;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
25
src/modules/LightSwitch/LightSwitchService/ThemeScheduler.h
Normal file
25
src/modules/LightSwitch/LightSwitchService/ThemeScheduler.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cmath>
|
||||||
|
#include <ctime>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// Struct to hold calculated sunrise/sunset times
|
||||||
|
struct SunTimes
|
||||||
|
{
|
||||||
|
int sunriseHour;
|
||||||
|
int sunriseMinute;
|
||||||
|
int sunsetHour;
|
||||||
|
int sunsetMinute;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr double PI = 3.14159265358979323846;
|
||||||
|
constexpr double deg2rad(double deg)
|
||||||
|
{
|
||||||
|
return deg * PI / 180.0;
|
||||||
|
}
|
||||||
|
constexpr double rad2deg(double rad)
|
||||||
|
{
|
||||||
|
return rad * 180.0 / PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
SunTimes CalculateSunriseSunset(double latitude, double longitude, int year, int month, int day);
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
#include "WinHookEventIDs.h"
|
||||||
|
#include <wtypes.h>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
UINT WM_PRIV_SETTINGS_CHANGED = 0;
|
||||||
|
|
||||||
|
std::once_flag init_flag;
|
||||||
|
|
||||||
|
void InitializeWinhookEventIds()
|
||||||
|
{
|
||||||
|
std::call_once(init_flag, [&] {
|
||||||
|
WM_PRIV_SETTINGS_CHANGED = RegisterWindowMessage(L"{11978F7B-221A-4E65-B9A9-693F7D6E4B25}");
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
extern UINT WM_PRIV_SETTINGS_CHANGED; // Scheduled when a watched settings file is updated
|
||||||
|
|
||||||
|
void InitializeWinhookEventIds();
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||||
|
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
|
||||||
|
</packages>
|
||||||
@@ -1194,15 +1194,6 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Dark mode.
|
|
||||||
/// </summary>
|
|
||||||
internal static string DarkMode {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("DarkMode", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Data usage.
|
/// Looks up a localized string similar to Data usage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2130,6 +2121,15 @@ namespace Microsoft.CmdPal.Ext.WindowsSettings.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Light Switch.
|
||||||
|
/// </summary>
|
||||||
|
internal static string LightSwitch {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LightSwitch", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Local Computer Policy.
|
/// Looks up a localized string similar to Local Computer Policy.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -572,8 +572,8 @@
|
|||||||
<data name="DarkColor" xml:space="preserve">
|
<data name="DarkColor" xml:space="preserve">
|
||||||
<value>Dark color</value>
|
<value>Dark color</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DarkMode" xml:space="preserve">
|
<data name="LightSwitch" xml:space="preserve">
|
||||||
<value>Dark mode</value>
|
<value>Light Switch</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DataUsage" xml:space="preserve">
|
<data name="DataUsage" xml:space="preserve">
|
||||||
<value>Data usage</value>
|
<value>Data usage</value>
|
||||||
|
|||||||
@@ -0,0 +1,324 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<AssemblyName>PowerToys.ImageResizer</AssemblyName>
|
||||||
|
<IntermediateOutputPath>obj\ARM64\Debug\</IntermediateOutputPath>
|
||||||
|
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
|
||||||
|
<MSBuildProjectExtensionsPath>D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\</MSBuildProjectExtensionsPath>
|
||||||
|
<_TargetAssemblyProjectName>ImageResizerUI</_TargetAssemblyProjectName>
|
||||||
|
<RootNamespace>ImageResizer</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
|
||||||
|
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||||
|
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||||
|
<Import Project="..\..\..\Common.SelfContained.props" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<AssemblyTitle>PowerToys.ImageResizer</AssemblyTitle>
|
||||||
|
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||||
|
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ProjectGuid>{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}</ProjectGuid>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<RootNamespace>ImageResizer</RootNamespace>
|
||||||
|
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationIcon>Resources\ImageResizer.ico</ApplicationIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Update="Properties\Resources.resx">
|
||||||
|
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" />
|
||||||
|
<PackageReference Include="System.IO.Abstractions" />
|
||||||
|
<PackageReference Include="WPF-UI" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\common\GPOWrapperProjection\GPOWrapperProjection.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||||
|
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Properties\Resources.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Accessibility.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\controlzex\6.0.0\lib\net5.0-windows7.0\ControlzEx.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.tracing.traceevent\3.1.16\lib\netstandard2.0\Dia2Lib.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\Microsoft.CSharp.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.tracing.traceevent\3.1.16\lib\netstandard2.0\Microsoft.Diagnostics.FastSerialization.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.netcore.client\0.2.510501\lib\net6.0\Microsoft.Diagnostics.NETCore.Client.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.tracing.traceevent\3.1.16\lib\netstandard2.0\Microsoft.Diagnostics.Tracing.TraceEvent.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.dependencyinjection.abstractions\9.0.8\lib\net9.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.dependencyinjection\9.0.8\lib\net9.0\Microsoft.Extensions.DependencyInjection.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.logging.abstractions\9.0.8\lib\net9.0\Microsoft.Extensions.Logging.Abstractions.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.logging\9.0.8\lib\net9.0\Microsoft.Extensions.Logging.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.options\9.0.8\lib\net9.0\Microsoft.Extensions.Options.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.primitives\9.0.8\lib\net9.0\Microsoft.Extensions.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\Microsoft.VisualBasic.Core.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Microsoft.VisualBasic.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Microsoft.VisualBasic.Forms.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\Microsoft.Win32.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Microsoft.Win32.Registry.AccessControl.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\Microsoft.Win32.Registry.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\Microsoft.Win32.SystemEvents.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.windows.sdk.net.ref\10.0.26100.68-preview\lib\net8.0\Microsoft.Windows.SDK.NET.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.xaml.behaviors.wpf\1.1.39\lib\net5.0-windows7.0\Microsoft.Xaml.Behaviors.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\mscorlib.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\netstandard.dll" />
|
||||||
|
<ReferencePath Include="D:\source\repos\PowerToys\src\common\Common.UI\bin\ARM64\Debug\net9.0-windows10.0.26100.0\PowerToys.Common.UI.dll" />
|
||||||
|
<ReferencePath Include="D:\source\repos\PowerToys\src\common\GPOWrapperProjection\bin\ARM64\Debug\net9.0-windows10.0.26100.0\PowerToys.GPOWrapperProjection.dll" />
|
||||||
|
<ReferencePath Include="D:\source\repos\PowerToys\src\common\ManagedCommon\bin\ARM64\Debug\net9.0-windows10.0.26100.0\PowerToys.ManagedCommon.dll" />
|
||||||
|
<ReferencePath Include="D:\source\repos\PowerToys\src\common\ManagedTelemetry\Telemetry\bin\ARM64\Debug\net9.0-windows10.0.26100.0\PowerToys.ManagedTelemetry.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationCore.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Aero.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Aero2.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.AeroLite.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Classic.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Luna.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationFramework.Royale.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\PresentationUI.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\ReachFramework.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.AppContext.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Buffers.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.CodeDom.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.Concurrent.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.Immutable.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.NonGeneric.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Collections.Specialized.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.Annotations.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.DataAnnotations.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.EventBasedAsync.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ComponentModel.TypeConverter.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Configuration.ConfigurationManager.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Configuration.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Console.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Core.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Data.Common.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Data.DataSetExtensions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Data.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Design.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Contracts.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Debug.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.DiagnosticSource.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.EventLog.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.FileVersionInfo.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.PerformanceCounter.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Process.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.StackTrace.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.TextWriterTraceListener.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Tools.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.TraceSource.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Diagnostics.Tracing.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.DirectoryServices.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Drawing.Common.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Drawing.Design.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Drawing.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Drawing.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Dynamic.Runtime.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Formats.Asn1.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Formats.Nrbf.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Formats.Tar.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Globalization.Calendars.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Globalization.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Globalization.Extensions.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\system.io.abstractions\22.0.13\lib\net9.0\System.IO.Abstractions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Compression.Brotli.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Compression.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Compression.FileSystem.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Compression.ZipFile.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.AccessControl.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.DriveInfo.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.FileSystem.Watcher.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.IsolatedStorage.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.MemoryMappedFiles.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.IO.Packaging.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Pipelines.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Pipes.AccessControl.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.Pipes.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.IO.UnmanagedMemoryStream.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Linq.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Linq.Expressions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Linq.Parallel.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Linq.Queryable.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\system.management\9.0.8\lib\net9.0\System.Management.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Memory.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Http.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Http.Json.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.HttpListener.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Mail.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.NameResolution.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.NetworkInformation.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Ping.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Quic.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Requests.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Security.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.ServicePoint.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.Sockets.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebClient.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebHeaderCollection.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebProxy.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebSockets.Client.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Net.WebSockets.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Numerics.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Numerics.Vectors.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ObjectModel.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Printing.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Private.Windows.Core.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.DispatchProxy.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Emit.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Emit.ILGeneration.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Emit.Lightweight.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Extensions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Metadata.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Reflection.TypeExtensions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Resources.Extensions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Resources.Reader.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Resources.ResourceManager.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Resources.Writer.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.CompilerServices.Unsafe.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.CompilerServices.VisualC.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Extensions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Handles.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.InteropServices.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.InteropServices.JavaScript.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.InteropServices.RuntimeInformation.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Intrinsics.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Loader.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Numerics.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.Formatters.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.Json.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Runtime.Serialization.Xml.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.AccessControl.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Claims.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Algorithms.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Cng.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Csp.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Encoding.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.OpenSsl.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Pkcs.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.ProtectedData.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.X509Certificates.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Security.Cryptography.Xml.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Security.Permissions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Principal.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.Principal.Windows.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Security.SecureString.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ServiceModel.Web.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ServiceProcess.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Encoding.CodePages.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Encoding.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Encoding.Extensions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Encodings.Web.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.Json.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Text.RegularExpressions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Threading.AccessControl.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Channels.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Overlapped.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Tasks.Dataflow.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Tasks.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Tasks.Extensions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Tasks.Parallel.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Thread.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.ThreadPool.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Threading.Timer.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Transactions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Transactions.Local.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.ValueTuple.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Web.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Web.HttpUtility.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Controls.Ribbon.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Windows.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Extensions.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Forms.Design.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Forms.Design.Editors.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Forms.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Forms.Primitives.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Input.Manipulations.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Windows.Presentation.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\System.Xaml.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.Linq.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.ReaderWriter.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.Serialization.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XDocument.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XmlDocument.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XmlSerializer.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XPath.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\ref\net9.0\System.Xml.XPath.XDocument.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\testableio.system.io.abstractions\22.0.13\lib\net9.0\TestableIO.System.IO.Abstractions.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\testableio.system.io.abstractions.wrappers\22.0.13\lib\net9.0\TestableIO.System.IO.Abstractions.Wrappers.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\testably.abstractions.filesystem.interface\9.0.0\lib\net9.0\Testably.Abstractions.FileSystem.Interface.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.diagnostics.tracing.traceevent\3.1.16\lib\netstandard2.0\TraceReloggerLib.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\UIAutomationClient.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\UIAutomationClientSideProviders.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\UIAutomationProvider.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\UIAutomationTypes.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\WindowsBase.dll" />
|
||||||
|
<ReferencePath Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\ref\net9.0\WindowsFormsIntegration.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.windows.sdk.net.ref\10.0.26100.68-preview\lib\net8.0\WinRT.Runtime.dll" />
|
||||||
|
<ReferencePath Include="C:\Users\jaylynbarbee\.nuget\packages\wpf-ui\3.0.5\lib\net8.0-windows7.0\Wpf.Ui.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\Views\InputPage.g.cs" />
|
||||||
|
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\Views\MainWindow.g.cs" />
|
||||||
|
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\Views\ProgressPage.g.cs" />
|
||||||
|
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\Views\ResultsPage.g.cs" />
|
||||||
|
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\App.g.cs" />
|
||||||
|
<Compile Include="D:\source\repos\PowerToys\src\modules\imageresizer\ui\obj\ARM64\Debug\GeneratedInternalTypeHelper.g.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.codeanalysis.netanalyzers\9.0.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.NetAnalyzers.dll" />
|
||||||
|
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.codeanalysis.netanalyzers\9.0.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.NetAnalyzers.dll" />
|
||||||
|
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.logging.abstractions\9.0.8\analyzers\dotnet\roslyn4.4\cs\Microsoft.Extensions.Logging.Generators.dll" />
|
||||||
|
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.extensions.options\9.0.8\analyzers\dotnet\roslyn4.4\cs\Microsoft.Extensions.Options.SourceGeneration.dll" />
|
||||||
|
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\stylecop.analyzers.unstable\1.2.0.556\analyzers\dotnet\cs\StyleCop.Analyzers.CodeFixes.dll" />
|
||||||
|
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\stylecop.analyzers.unstable\1.2.0.556\analyzers\dotnet\cs\StyleCop.Analyzers.dll" />
|
||||||
|
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/Microsoft.Interop.ComInterfaceGenerator.dll" />
|
||||||
|
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/Microsoft.Interop.JavaScript.JSImportGenerator.dll" />
|
||||||
|
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/Microsoft.Interop.LibraryImportGenerator.dll" />
|
||||||
|
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/Microsoft.Interop.SourceGeneration.dll" />
|
||||||
|
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/System.Text.Json.SourceGeneration.dll" />
|
||||||
|
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.8\analyzers/dotnet/cs/System.Text.RegularExpressions.Generator.dll" />
|
||||||
|
<Analyzer Include="C:\Users\jaylynbarbee\.nuget\packages\microsoft.windows.sdk.net.ref\10.0.26100.68-preview\analyzers/dotnet/cs/WinRT.SourceGenerator.dll" />
|
||||||
|
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\analyzers/dotnet/System.Windows.Forms.Analyzers.dll" />
|
||||||
|
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\analyzers/dotnet/cs/System.Windows.Forms.Analyzers.CSharp.dll" />
|
||||||
|
<Analyzer Include="C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\9.0.8\analyzers/dotnet/cs/System.Windows.Forms.Analyzers.CodeFixes.CSharp.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
|
||||||
|
</Project>
|
||||||
@@ -14,7 +14,8 @@ namespace Microsoft.PowerToys.Run.Plugin.PowerToys.Components
|
|||||||
ShortcutGuide = 5,
|
ShortcutGuide = 5,
|
||||||
RegistryPreview = 6,
|
RegistryPreview = 6,
|
||||||
CropAndLock = 7,
|
CropAndLock = 7,
|
||||||
EnvironmentVariables = 8,
|
LightSwitch = 8,
|
||||||
Workspaces = 9,
|
EnvironmentVariables = 9,
|
||||||
|
Workspaces = 10,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,18 @@ namespace Microsoft.PowerToys.Run.Plugin.PowerToys.Properties {
|
|||||||
return ResourceManager.GetString("Action_Run_As_Administrator", resourceCulture);
|
return ResourceManager.GetString("Action_Run_As_Administrator", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Light Switch.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Light_Switch
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ResourceManager.GetString("Light_Switch", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Color Picker.
|
/// Looks up a localized string similar to Color Picker.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -572,8 +572,8 @@
|
|||||||
<data name="DarkColor" xml:space="preserve">
|
<data name="DarkColor" xml:space="preserve">
|
||||||
<value>Dark color</value>
|
<value>Dark color</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DarkMode" xml:space="preserve">
|
<data name="LightSwitch" xml:space="preserve">
|
||||||
<value>Dark mode</value>
|
<value>Light Switch</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DataUsage" xml:space="preserve">
|
<data name="DataUsage" xml:space="preserve">
|
||||||
<value>Data usage</value>
|
<value>Data usage</value>
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
|||||||
L"PowerToys.WorkspacesModuleInterface.dll",
|
L"PowerToys.WorkspacesModuleInterface.dll",
|
||||||
L"PowerToys.CmdPalModuleInterface.dll",
|
L"PowerToys.CmdPalModuleInterface.dll",
|
||||||
L"PowerToys.ZoomItModuleInterface.dll",
|
L"PowerToys.ZoomItModuleInterface.dll",
|
||||||
|
L"PowerToys.LightSwitchModuleInterface.dll",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto moduleSubdir : knownModules)
|
for (auto moduleSubdir : knownModules)
|
||||||
|
|||||||
@@ -683,6 +683,8 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
|
|||||||
return "ColorPicker";
|
return "ColorPicker";
|
||||||
case ESettingsWindowNames::CmdNotFound:
|
case ESettingsWindowNames::CmdNotFound:
|
||||||
return "CmdNotFound";
|
return "CmdNotFound";
|
||||||
|
case ESettingsWindowNames::LightSwitch:
|
||||||
|
return "LightSwitch";
|
||||||
case ESettingsWindowNames::FancyZones:
|
case ESettingsWindowNames::FancyZones:
|
||||||
return "FancyZones";
|
return "FancyZones";
|
||||||
case ESettingsWindowNames::FileLocksmith:
|
case ESettingsWindowNames::FileLocksmith:
|
||||||
@@ -768,6 +770,10 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
|
|||||||
{
|
{
|
||||||
return ESettingsWindowNames::CmdNotFound;
|
return ESettingsWindowNames::CmdNotFound;
|
||||||
}
|
}
|
||||||
|
else if (value == "LightSwitch")
|
||||||
|
{
|
||||||
|
return ESettingsWindowNames::LightSwitch;
|
||||||
|
}
|
||||||
else if (value == "FancyZones")
|
else if (value == "FancyZones")
|
||||||
{
|
{
|
||||||
return ESettingsWindowNames::FancyZones;
|
return ESettingsWindowNames::FancyZones;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ enum class ESettingsWindowNames
|
|||||||
Awake,
|
Awake,
|
||||||
ColorPicker,
|
ColorPicker,
|
||||||
CmdNotFound,
|
CmdNotFound,
|
||||||
|
LightSwitch,
|
||||||
FancyZones,
|
FancyZones,
|
||||||
FileLocksmith,
|
FileLocksmith,
|
||||||
Run,
|
Run,
|
||||||
|
|||||||
@@ -513,6 +513,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool lightSwitch;
|
||||||
|
|
||||||
|
[JsonPropertyName("LightSwitch")]
|
||||||
|
public bool LightSwitch
|
||||||
|
{
|
||||||
|
get => lightSwitch;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (lightSwitch != value)
|
||||||
|
{
|
||||||
|
LogTelemetryEvent(value);
|
||||||
|
lightSwitch = value;
|
||||||
|
NotifyChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void NotifyChange()
|
private void NotifyChange()
|
||||||
{
|
{
|
||||||
notifyEnabledChangedAction?.Invoke();
|
notifyEnabledChangedAction?.Invoke();
|
||||||
|
|||||||
19
src/settings-ui/Settings.UI.Library/Helpers/City.cs
Normal file
19
src/settings-ui/Settings.UI.Library/Helpers/City.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// 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 System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Settings.UI.Library.Helpers
|
||||||
|
{
|
||||||
|
public sealed record City(string Name, string Country, double Latitude, double Longitude)
|
||||||
|
{
|
||||||
|
public string Display => string.IsNullOrWhiteSpace(Country)
|
||||||
|
? Name
|
||||||
|
: $"{Name}, {Country}";
|
||||||
|
}
|
||||||
|
}
|
||||||
122
src/settings-ui/Settings.UI.Library/Helpers/CityLoader.cs
Normal file
122
src/settings-ui/Settings.UI.Library/Helpers/CityLoader.cs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
// 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 System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using Settings.UI.Library.Helpers;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Helpers
|
||||||
|
{
|
||||||
|
public static class CityLoader
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Loads all cities from a world_cities.csv file.
|
||||||
|
/// Expected columns: city, city_ascii, lat, lng, country
|
||||||
|
/// </summary>
|
||||||
|
public static IEnumerable<City> LoadCities(string path)
|
||||||
|
{
|
||||||
|
using StreamReader reader = new(path);
|
||||||
|
|
||||||
|
// Read header
|
||||||
|
string header = reader.ReadLine();
|
||||||
|
if (header is null)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> headerCols = SplitCsvLine(header);
|
||||||
|
int idxCity = headerCols.FindIndex(h => string.Equals(h, "city", StringComparison.OrdinalIgnoreCase));
|
||||||
|
int idxCityAscii = headerCols.FindIndex(h => string.Equals(h, "city_ascii", StringComparison.OrdinalIgnoreCase));
|
||||||
|
int idxLat = headerCols.FindIndex(h => string.Equals(h, "lat", StringComparison.OrdinalIgnoreCase));
|
||||||
|
int idxLng = headerCols.FindIndex(h => string.Equals(h, "lng", StringComparison.OrdinalIgnoreCase));
|
||||||
|
int idxCountry = headerCols.FindIndex(h => string.Equals(h, "country", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
string line;
|
||||||
|
while ((line = reader.ReadLine()) is not null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> cols = SplitCsvLine(line);
|
||||||
|
|
||||||
|
string rawCity = idxCity >= 0 && idxCity < cols.Count ? cols[idxCity] : string.Empty;
|
||||||
|
string cityAscii = idxCityAscii >= 0 && idxCityAscii < cols.Count ? cols[idxCityAscii] : string.Empty;
|
||||||
|
string cityName = string.IsNullOrWhiteSpace(cityAscii) ? rawCity : cityAscii;
|
||||||
|
string country = idxCountry >= 0 && idxCountry < cols.Count ? cols[idxCountry] : string.Empty;
|
||||||
|
|
||||||
|
if (!(idxLat >= 0 && idxLat < cols.Count && idxLng >= 0 && idxLng < cols.Count))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!double.TryParse(cols[idxLat], NumberStyles.Float, CultureInfo.InvariantCulture, out double lat))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!double.TryParse(cols[idxLng], NumberStyles.Float, CultureInfo.InvariantCulture, out double lng))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(cityName))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return new City(cityName, country, lat, lng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Splits a CSV line, handling commas inside quotes and escaped quotes.
|
||||||
|
/// </summary>
|
||||||
|
private static List<string> SplitCsvLine(string line)
|
||||||
|
{
|
||||||
|
List<string> result = new();
|
||||||
|
if (string.IsNullOrEmpty(line))
|
||||||
|
{
|
||||||
|
result.Add(string.Empty);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool inQuotes = false;
|
||||||
|
StringBuilder current = new();
|
||||||
|
|
||||||
|
for (int i = 0; i < line.Length; i++)
|
||||||
|
{
|
||||||
|
char c = line[i];
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
if (inQuotes && i + 1 < line.Length && line[i + 1] == '"')
|
||||||
|
{
|
||||||
|
current.Append('"');
|
||||||
|
i++; // skip escaped quote
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inQuotes = !inQuotes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == ',' && !inQuotes)
|
||||||
|
{
|
||||||
|
result.Add(current.ToString());
|
||||||
|
current.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Add(current.ToString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
131
src/settings-ui/Settings.UI.Library/Helpers/SunCalc.cs
Normal file
131
src/settings-ui/Settings.UI.Library/Helpers/SunCalc.cs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Library.Helpers
|
||||||
|
{
|
||||||
|
public static class SunCalc
|
||||||
|
{
|
||||||
|
public static SunTimes CalculateSunriseSunset(double latitude, double longitude, int year, int month, int day)
|
||||||
|
{
|
||||||
|
double zenith = 90.833; // official sunrise/sunset
|
||||||
|
|
||||||
|
int n1 = (int)Math.Floor(275.0 * month / 9.0);
|
||||||
|
int n2 = (int)Math.Floor((month + 9.0) / 12.0);
|
||||||
|
int n3 = (int)Math.Floor(1.0 + Math.Floor((year - (4.0 * Math.Floor(year / 4.0)) + 2.0) / 3.0));
|
||||||
|
int n = n1 - (n2 * n3) + day - 30;
|
||||||
|
|
||||||
|
double? riseUT = CalcTime(isSunrise: true);
|
||||||
|
double? setUT = CalcTime(isSunrise: false);
|
||||||
|
|
||||||
|
var riseLocal = ToLocal(riseUT, year, month, day);
|
||||||
|
var setLocal = ToLocal(setUT, year, month, day);
|
||||||
|
|
||||||
|
var result = new SunTimes
|
||||||
|
{
|
||||||
|
HasSunrise = riseLocal.HasValue,
|
||||||
|
HasSunset = setLocal.HasValue,
|
||||||
|
SunriseHour = riseLocal?.Hour ?? -1,
|
||||||
|
SunriseMinute = riseLocal?.Minute ?? -1,
|
||||||
|
SunsetHour = setLocal?.Hour ?? -1,
|
||||||
|
SunsetMinute = setLocal?.Minute ?? -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// Local functions
|
||||||
|
double? CalcTime(bool isSunrise)
|
||||||
|
{
|
||||||
|
double lngHour = longitude / 15.0;
|
||||||
|
double t = isSunrise ? n + ((6 - lngHour) / 24.0) : n + ((18 - lngHour) / 24.0);
|
||||||
|
|
||||||
|
double m1 = (0.9856 * t) - 3.289;
|
||||||
|
double l = m1 + (1.916 * Math.Sin(Deg2Rad(m1))) + (0.020 * Math.Sin(2 * Deg2Rad(m1))) + 282.634;
|
||||||
|
l = NormalizeDegrees(l);
|
||||||
|
|
||||||
|
double rA = Rad2Deg(Math.Atan(0.91764 * Math.Tan(Deg2Rad(l))));
|
||||||
|
rA = NormalizeDegrees(rA);
|
||||||
|
|
||||||
|
double lquadrant = Math.Floor(l / 90.0) * 90.0;
|
||||||
|
double rAquadrant = Math.Floor(rA / 90.0) * 90.0;
|
||||||
|
rA = rA + (lquadrant - rAquadrant);
|
||||||
|
rA /= 15.0;
|
||||||
|
|
||||||
|
double sinDec = 0.39782 * Math.Sin(Deg2Rad(l));
|
||||||
|
double cosDec = Math.Cos(Math.Asin(sinDec));
|
||||||
|
|
||||||
|
double cosH = (Math.Cos(Deg2Rad(zenith)) - (sinDec * Math.Sin(Deg2Rad(latitude))))
|
||||||
|
/ (cosDec * Math.Cos(Deg2Rad(latitude)));
|
||||||
|
|
||||||
|
if (cosH > 1.0 || cosH < -1.0)
|
||||||
|
{
|
||||||
|
// Sun never rises or never sets on this date at this location
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
double h = isSunrise ? 360.0 - Rad2Deg(Math.Acos(cosH)) : Rad2Deg(Math.Acos(cosH));
|
||||||
|
h /= 15.0;
|
||||||
|
|
||||||
|
double t1 = h + rA - (0.06571 * t) - 6.622;
|
||||||
|
double uT = t1 - lngHour;
|
||||||
|
uT = NormalizeHours(uT);
|
||||||
|
|
||||||
|
return uT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static (int Hour, int Minute)? ToLocal(double? ut, int y, int m, int d)
|
||||||
|
{
|
||||||
|
if (!ut.HasValue)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert fractional hours to hh:mm with proper rounding
|
||||||
|
int hours = (int)Math.Floor(ut.Value);
|
||||||
|
int minutes = (int)((ut.Value - hours) * 60.0);
|
||||||
|
|
||||||
|
// Normalize minute overflow
|
||||||
|
if (minutes == 60)
|
||||||
|
{
|
||||||
|
minutes = 0;
|
||||||
|
hours = (hours + 1) % 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a UTC DateTime on the given date
|
||||||
|
var utc = new DateTime(y, m, d, hours, minutes, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
// Convert to local time using system time zone rules for that date
|
||||||
|
var local = TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.Local);
|
||||||
|
|
||||||
|
return (local.Hour, local.Minute);
|
||||||
|
}
|
||||||
|
|
||||||
|
static double Deg2Rad(double deg) => deg * Math.PI / 180.0;
|
||||||
|
static double Rad2Deg(double rad) => rad * 180.0 / Math.PI;
|
||||||
|
|
||||||
|
static double NormalizeDegrees(double angle)
|
||||||
|
{
|
||||||
|
angle %= 360.0;
|
||||||
|
if (angle < 0)
|
||||||
|
{
|
||||||
|
angle += 360.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double NormalizeHours(double hours)
|
||||||
|
{
|
||||||
|
hours %= 24.0;
|
||||||
|
if (hours < 0)
|
||||||
|
{
|
||||||
|
hours += 24.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hours;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/settings-ui/Settings.UI.Library/Helpers/SunTimes.cs
Normal file
24
src/settings-ui/Settings.UI.Library/Helpers/SunTimes.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// 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 System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Library.Helpers
|
||||||
|
{
|
||||||
|
public struct SunTimes
|
||||||
|
{
|
||||||
|
public int SunriseHour;
|
||||||
|
public int SunriseMinute;
|
||||||
|
public int SunsetHour;
|
||||||
|
public int SunsetMinute;
|
||||||
|
public string Text;
|
||||||
|
|
||||||
|
public bool HasSunrise;
|
||||||
|
public bool HasSunset;
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/settings-ui/Settings.UI.Library/LightSwitchProperties.cs
Normal file
66
src/settings-ui/Settings.UI.Library/LightSwitchProperties.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// 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.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||||
|
{
|
||||||
|
public class LightSwitchProperties
|
||||||
|
{
|
||||||
|
public const bool DefaultChangeSystem = false;
|
||||||
|
public const bool DefaultChangeApps = false;
|
||||||
|
public const int DefaultLightTime = 480; // 08:00
|
||||||
|
public const int DefaultDarkTime = 1200; // 20:001
|
||||||
|
public const int DefaultOffset = 0;
|
||||||
|
public const string DefaultLatitude = "0.0";
|
||||||
|
public const string DefaultLongitude = "0.0";
|
||||||
|
public const string DefaultScheduleMode = "FixedHours";
|
||||||
|
public static readonly HotkeySettings DefaultForceLightModeValue = new HotkeySettings(true, true, false, true, 0x4C); // Ctrl+Win+Shift+L
|
||||||
|
public static readonly HotkeySettings DefaultForceDarkModeValue = new HotkeySettings(true, true, false, true, 0x44); // Ctrl+Win+Shift+D
|
||||||
|
|
||||||
|
public LightSwitchProperties()
|
||||||
|
{
|
||||||
|
ChangeSystem = new BoolProperty(DefaultChangeSystem);
|
||||||
|
ChangeApps = new BoolProperty(DefaultChangeApps);
|
||||||
|
LightTime = new IntProperty(DefaultLightTime);
|
||||||
|
DarkTime = new IntProperty(DefaultDarkTime);
|
||||||
|
Latitude = new StringProperty(DefaultLatitude);
|
||||||
|
Longitude = new StringProperty(DefaultLongitude);
|
||||||
|
Offset = new IntProperty(DefaultOffset);
|
||||||
|
ScheduleMode = new StringProperty(DefaultScheduleMode);
|
||||||
|
ForceLightModeHotkey = new KeyboardKeysProperty(DefaultForceLightModeValue);
|
||||||
|
ForceDarkModeHotkey = new KeyboardKeysProperty(DefaultForceDarkModeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonPropertyName("changeSystem")]
|
||||||
|
public BoolProperty ChangeSystem { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("changeApps")]
|
||||||
|
public BoolProperty ChangeApps { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("lightTime")]
|
||||||
|
public IntProperty LightTime { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("darkTime")]
|
||||||
|
public IntProperty DarkTime { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("offset")]
|
||||||
|
public IntProperty Offset { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("latitude")]
|
||||||
|
public StringProperty Latitude { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("longitude")]
|
||||||
|
public StringProperty Longitude { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("scheduleMode")]
|
||||||
|
public StringProperty ScheduleMode { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("force-light-mode-hotkey")]
|
||||||
|
public KeyboardKeysProperty ForceLightModeHotkey { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("force-dark-mode-hotkey")]
|
||||||
|
public KeyboardKeysProperty ForceDarkModeHotkey { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/settings-ui/Settings.UI.Library/LightSwitchSettings.cs
Normal file
57
src/settings-ui/Settings.UI.Library/LightSwitchSettings.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// 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 System.Reflection;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
|
|
||||||
|
namespace Settings.UI.Library
|
||||||
|
{
|
||||||
|
public class LightSwitchSettings : BasePTModuleSettings, ISettingsConfig, ICloneable
|
||||||
|
{
|
||||||
|
public const string ModuleName = "LightSwitch";
|
||||||
|
|
||||||
|
public LightSwitchSettings()
|
||||||
|
{
|
||||||
|
Name = ModuleName;
|
||||||
|
Version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||||
|
Properties = new LightSwitchProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonPropertyName("properties")]
|
||||||
|
public LightSwitchProperties Properties { get; set; }
|
||||||
|
|
||||||
|
public object Clone()
|
||||||
|
{
|
||||||
|
return new LightSwitchSettings()
|
||||||
|
{
|
||||||
|
Name = Name,
|
||||||
|
Version = Version,
|
||||||
|
Properties = new LightSwitchProperties()
|
||||||
|
{
|
||||||
|
ChangeSystem = new BoolProperty(Properties.ChangeSystem.Value),
|
||||||
|
ChangeApps = new BoolProperty(Properties.ChangeApps.Value),
|
||||||
|
ScheduleMode = new StringProperty(Properties.ScheduleMode.Value),
|
||||||
|
LightTime = new IntProperty((int)Properties.LightTime.Value),
|
||||||
|
DarkTime = new IntProperty((int)Properties.DarkTime.Value),
|
||||||
|
Offset = new IntProperty((int)Properties.Offset.Value),
|
||||||
|
Latitude = new StringProperty(Properties.Latitude.Value),
|
||||||
|
Longitude = new StringProperty(Properties.Longitude.Value),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetModuleName()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UpgradeSettingsConfiguration()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// 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.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Settings.UI.Library;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||||
|
{
|
||||||
|
public class SndLightSwitchSettings
|
||||||
|
{
|
||||||
|
[JsonPropertyName("LightSwitch")]
|
||||||
|
public LightSwitchSettings Settings { get; set; }
|
||||||
|
|
||||||
|
public SndLightSwitchSettings()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SndLightSwitchSettings(LightSwitchSettings settings)
|
||||||
|
{
|
||||||
|
Settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToJsonString()
|
||||||
|
{
|
||||||
|
return JsonSerializer.Serialize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 968 B |
3632
src/settings-ui/Settings.UI/Assets/Settings/search.index.json
Normal file
3632
src/settings-ui/Settings.UI/Assets/Settings/search.index.json
Normal file
File diff suppressed because it is too large
Load Diff
7323
src/settings-ui/Settings.UI/Assets/world_cities.csv
Normal file
7323
src/settings-ui/Settings.UI/Assets/world_cities.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||||
|
{
|
||||||
|
public partial class EnumToVisibilityConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value == null || parameter == null)
|
||||||
|
{
|
||||||
|
return Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
string enumString = value.ToString();
|
||||||
|
string targetString = parameter.ToString();
|
||||||
|
|
||||||
|
return enumString.Equals(targetString, StringComparison.OrdinalIgnoreCase)
|
||||||
|
? Visibility.Visible
|
||||||
|
: Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
|||||||
case ModuleType.CmdPal: return generalSettingsConfig.Enabled.CmdPal;
|
case ModuleType.CmdPal: return generalSettingsConfig.Enabled.CmdPal;
|
||||||
case ModuleType.ColorPicker: return generalSettingsConfig.Enabled.ColorPicker;
|
case ModuleType.ColorPicker: return generalSettingsConfig.Enabled.ColorPicker;
|
||||||
case ModuleType.CropAndLock: return generalSettingsConfig.Enabled.CropAndLock;
|
case ModuleType.CropAndLock: return generalSettingsConfig.Enabled.CropAndLock;
|
||||||
|
case ModuleType.LightSwitch: return generalSettingsConfig.Enabled.LightSwitch;
|
||||||
case ModuleType.EnvironmentVariables: return generalSettingsConfig.Enabled.EnvironmentVariables;
|
case ModuleType.EnvironmentVariables: return generalSettingsConfig.Enabled.EnvironmentVariables;
|
||||||
case ModuleType.FancyZones: return generalSettingsConfig.Enabled.FancyZones;
|
case ModuleType.FancyZones: return generalSettingsConfig.Enabled.FancyZones;
|
||||||
case ModuleType.FileLocksmith: return generalSettingsConfig.Enabled.FileLocksmith;
|
case ModuleType.FileLocksmith: return generalSettingsConfig.Enabled.FileLocksmith;
|
||||||
@@ -88,6 +89,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
|||||||
case ModuleType.CmdPal: generalSettingsConfig.Enabled.CmdPal = isEnabled; break;
|
case ModuleType.CmdPal: generalSettingsConfig.Enabled.CmdPal = isEnabled; break;
|
||||||
case ModuleType.ColorPicker: generalSettingsConfig.Enabled.ColorPicker = isEnabled; break;
|
case ModuleType.ColorPicker: generalSettingsConfig.Enabled.ColorPicker = isEnabled; break;
|
||||||
case ModuleType.CropAndLock: generalSettingsConfig.Enabled.CropAndLock = isEnabled; break;
|
case ModuleType.CropAndLock: generalSettingsConfig.Enabled.CropAndLock = isEnabled; break;
|
||||||
|
case ModuleType.LightSwitch: generalSettingsConfig.Enabled.LightSwitch = isEnabled; break;
|
||||||
case ModuleType.EnvironmentVariables: generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break;
|
case ModuleType.EnvironmentVariables: generalSettingsConfig.Enabled.EnvironmentVariables = isEnabled; break;
|
||||||
case ModuleType.FancyZones: generalSettingsConfig.Enabled.FancyZones = isEnabled; break;
|
case ModuleType.FancyZones: generalSettingsConfig.Enabled.FancyZones = isEnabled; break;
|
||||||
case ModuleType.FileLocksmith: generalSettingsConfig.Enabled.FileLocksmith = isEnabled; break;
|
case ModuleType.FileLocksmith: generalSettingsConfig.Enabled.FileLocksmith = isEnabled; break;
|
||||||
@@ -159,6 +161,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
|
|||||||
ModuleType.CmdPal => typeof(CmdPalPage),
|
ModuleType.CmdPal => typeof(CmdPalPage),
|
||||||
ModuleType.ColorPicker => typeof(ColorPickerPage),
|
ModuleType.ColorPicker => typeof(ColorPickerPage),
|
||||||
ModuleType.CropAndLock => typeof(CropAndLockPage),
|
ModuleType.CropAndLock => typeof(CropAndLockPage),
|
||||||
|
ModuleType.LightSwitch => typeof(LightSwitchPage),
|
||||||
ModuleType.EnvironmentVariables => typeof(EnvironmentVariablesPage),
|
ModuleType.EnvironmentVariables => typeof(EnvironmentVariablesPage),
|
||||||
ModuleType.FancyZones => typeof(FancyZonesPage),
|
ModuleType.FancyZones => typeof(FancyZonesPage),
|
||||||
ModuleType.FileLocksmith => typeof(FileLocksmithPage),
|
ModuleType.FileLocksmith => typeof(FileLocksmithPage),
|
||||||
|
|||||||
@@ -19,12 +19,19 @@
|
|||||||
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
|
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
|
||||||
<ProjectPriFileName>PowerToys.Settings.pri</ProjectPriFileName>
|
<ProjectPriFileName>PowerToys.Settings.pri</ProjectPriFileName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Content Remove="Assets\world_cities.csv" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="Assets\Settings\Icons\LightSwitch.png" />
|
||||||
<None Remove="Assets\Settings\Modules\APDialog.dark.png" />
|
<None Remove="Assets\Settings\Modules\APDialog.dark.png" />
|
||||||
<None Remove="Assets\Settings\Modules\APDialog.light.png" />
|
<None Remove="Assets\Settings\Modules\APDialog.light.png" />
|
||||||
<None Remove="SettingsXAML\Controls\Dashboard\CheckUpdateControl.xaml" />
|
<None Remove="SettingsXAML\Controls\Dashboard\CheckUpdateControl.xaml" />
|
||||||
<None Remove="SettingsXAML\Controls\Dashboard\ShortcutConflictControl.xaml" />
|
<None Remove="SettingsXAML\Controls\Dashboard\ShortcutConflictControl.xaml" />
|
||||||
<None Remove="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml" />
|
<None Remove="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml" />
|
||||||
|
<None Remove="SettingsXAML\Controls\Timeline\Timeline.xaml" />
|
||||||
|
<None Remove="SettingsXAML\Controls\Timeline\TimelineStyles.xaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Remove="SettingsXAML\App.xaml" />
|
<Page Remove="SettingsXAML\App.xaml" />
|
||||||
@@ -135,6 +142,18 @@
|
|||||||
<None Update="Assets\Settings\Scripts\DisableModule.ps1">
|
<None Update="Assets\Settings\Scripts\DisableModule.ps1">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="Assets\world_cities.csv">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<Page Update="SettingsXAML\Controls\Timeline\TimelineStyles.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Update="SettingsXAML\Controls\Timeline\Timeline.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Update="SettingsXAML\Views\LightSwitchPage.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Update="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml">
|
<Page Update="SettingsXAML\Controls\KeyVisual\KeyCharPresenter.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Text.Json.Serialization;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Settings.UI.Library;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.SerializationContext;
|
namespace Microsoft.PowerToys.Settings.UI.SerializationContext;
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.SerializationContext;
|
|||||||
[JsonSerializable(typeof(AlwaysOnTopSettings))]
|
[JsonSerializable(typeof(AlwaysOnTopSettings))]
|
||||||
[JsonSerializable(typeof(ColorPickerSettings))]
|
[JsonSerializable(typeof(ColorPickerSettings))]
|
||||||
[JsonSerializable(typeof(CropAndLockSettings))]
|
[JsonSerializable(typeof(CropAndLockSettings))]
|
||||||
|
[JsonSerializable(typeof(LightSwitchSettings))]
|
||||||
[JsonSerializable(typeof(FileLocksmithSettings))]
|
[JsonSerializable(typeof(FileLocksmithSettings))]
|
||||||
[JsonSerializable(typeof(MeasureToolSettings))]
|
[JsonSerializable(typeof(MeasureToolSettings))]
|
||||||
[JsonSerializable(typeof(MouseWithoutBordersSettings))]
|
[JsonSerializable(typeof(MouseWithoutBordersSettings))]
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
<ResourceDictionary Source="/SettingsXAML/Styles/InfoBadge.xaml" />
|
<ResourceDictionary Source="/SettingsXAML/Styles/InfoBadge.xaml" />
|
||||||
<ResourceDictionary Source="/SettingsXAML/Themes/Colors.xaml" />
|
<ResourceDictionary Source="/SettingsXAML/Themes/Colors.xaml" />
|
||||||
<ResourceDictionary Source="/SettingsXAML/Themes/Generic.xaml" />
|
<ResourceDictionary Source="/SettingsXAML/Themes/Generic.xaml" />
|
||||||
|
<ResourceDictionary Source="/SettingsXAML/Controls/Timeline/TimelineStyles.xaml" />
|
||||||
|
|
||||||
<!-- Other merged dictionaries here -->
|
<!-- Other merged dictionaries here -->
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|||||||
@@ -403,6 +403,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
|||||||
case "Awake": return typeof(AwakePage);
|
case "Awake": return typeof(AwakePage);
|
||||||
case "CmdNotFound": return typeof(CmdNotFoundPage);
|
case "CmdNotFound": return typeof(CmdNotFoundPage);
|
||||||
case "ColorPicker": return typeof(ColorPickerPage);
|
case "ColorPicker": return typeof(ColorPickerPage);
|
||||||
|
case "LightSwitch": return typeof(LightSwitchPage);
|
||||||
case "FancyZones": return typeof(FancyZonesPage);
|
case "FancyZones": return typeof(FancyZonesPage);
|
||||||
case "FileLocksmith": return typeof(FileLocksmithPage);
|
case "FileLocksmith": return typeof(FileLocksmithPage);
|
||||||
case "Run": return typeof(PowerLauncherPage);
|
case "Run": return typeof(PowerLauncherPage);
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<UserControl
|
||||||
|
x:Class="Microsoft.PowerToys.Settings.UI.Controls.Timeline"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Canvas
|
||||||
|
x:Name="HeaderCanvas"
|
||||||
|
Grid.Row="0"
|
||||||
|
Height="24" />
|
||||||
|
|
||||||
|
<!-- Timeline (bands + ticks + labels) -->
|
||||||
|
<Border
|
||||||
|
Grid.Row="1"
|
||||||
|
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="{ThemeResource OverlayCornerRadius}">
|
||||||
|
<Canvas
|
||||||
|
x:Name="TimelineCanvas"
|
||||||
|
Height="36"
|
||||||
|
Loaded="TimelineCanvas_Loaded" />
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Below-chart annotations (sunrise/sunset panels + major labels) -->
|
||||||
|
<Canvas
|
||||||
|
x:Name="AnnotationCanvas"
|
||||||
|
Grid.Row="2"
|
||||||
|
Height="32" />
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,672 @@
|
|||||||
|
// 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 System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Microsoft.UI.Xaml.Shapes;
|
||||||
|
using Windows.Foundation;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||||
|
{
|
||||||
|
public sealed partial class Timeline : UserControl
|
||||||
|
{
|
||||||
|
public TimeSpan StartTime
|
||||||
|
{
|
||||||
|
get => (TimeSpan)GetValue(StartTimeProperty);
|
||||||
|
set => SetValue(StartTimeProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty StartTimeProperty = DependencyProperty.Register(nameof(StartTime), typeof(TimeSpan), typeof(Timeline), new PropertyMetadata(defaultValue: new TimeSpan(22, 0, 0), OnTimeChanged));
|
||||||
|
|
||||||
|
public TimeSpan EndTime
|
||||||
|
{
|
||||||
|
get => (TimeSpan)GetValue(EndTimeProperty);
|
||||||
|
set => SetValue(EndTimeProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty EndTimeProperty = DependencyProperty.Register(nameof(EndTime), typeof(TimeSpan), typeof(Timeline), new PropertyMetadata(defaultValue: new TimeSpan(7, 0, 0), OnTimeChanged));
|
||||||
|
|
||||||
|
public TimeSpan? Sunrise
|
||||||
|
{
|
||||||
|
get => (TimeSpan?)GetValue(SunriseProperty);
|
||||||
|
set => SetValue(SunriseProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty SunriseProperty = DependencyProperty.Register(nameof(Sunrise), typeof(TimeSpan), typeof(Timeline), new PropertyMetadata(defaultValue: null, OnTimeChanged));
|
||||||
|
|
||||||
|
public TimeSpan? Sunset
|
||||||
|
{
|
||||||
|
get => (TimeSpan?)GetValue(SunsetProperty);
|
||||||
|
set => SetValue(SunsetProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty SunsetProperty = DependencyProperty.Register(nameof(Sunset), typeof(TimeSpan), typeof(Timeline), new PropertyMetadata(defaultValue: null, OnTimeChanged));
|
||||||
|
|
||||||
|
private readonly List<int> _tickHours = new();
|
||||||
|
|
||||||
|
// Locale 24h/12h
|
||||||
|
private readonly bool _is24h = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern.Contains('H');
|
||||||
|
|
||||||
|
// Visuals
|
||||||
|
private readonly List<Line> _ticks = new();
|
||||||
|
private readonly List<TextBlock> _majorTickBottomLabels = new(); // 00,06,12,18,24 (below)
|
||||||
|
|
||||||
|
private readonly List<Border> _darkRects = new(); // up to 2 (wrap)
|
||||||
|
private readonly List<Border> _lightRects = new(); // up to 2 (complement)
|
||||||
|
|
||||||
|
private TextBlock _startEdgeLabel; // top-of-chart
|
||||||
|
private TextBlock _endEdgeLabel;
|
||||||
|
|
||||||
|
private Line _sunriseTick;
|
||||||
|
private Line _sunsetTick;
|
||||||
|
|
||||||
|
// Add/replace these constants (top of your class)
|
||||||
|
private const int TickHourStep = 2; // <-- every 2 hours
|
||||||
|
|
||||||
|
private StackPanel _sunrisePanel; // icon + time (below chart)
|
||||||
|
private StackPanel _sunsetPanel;
|
||||||
|
|
||||||
|
public Timeline()
|
||||||
|
{
|
||||||
|
this.InitializeComponent();
|
||||||
|
this.Loaded += Timeline_Loaded;
|
||||||
|
this.IsEnabledChanged += Timeline_IsEnabledChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Timeline_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
CheckEnabledState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Timeline_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
CheckEnabledState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckEnabledState()
|
||||||
|
{
|
||||||
|
if (IsEnabled)
|
||||||
|
{
|
||||||
|
this.Opacity = 1.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Opacity = 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
((Timeline)d).Setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Setup()
|
||||||
|
{
|
||||||
|
EnsureBands();
|
||||||
|
EnsureTicks();
|
||||||
|
EnsureStartEndEdgeLabels();
|
||||||
|
EnsureSunriseSunsetTicks();
|
||||||
|
EnsureSunPanels();
|
||||||
|
EnsureMajorTickLabels();
|
||||||
|
UpdateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimelineCanvas_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// SizeChanged wiring here (as requested)
|
||||||
|
HeaderCanvas.SizeChanged += (_, __) => UpdateAll();
|
||||||
|
TimelineCanvas.SizeChanged += (_, __) => UpdateAll();
|
||||||
|
AnnotationCanvas.SizeChanged += (_, __) => UpdateAll();
|
||||||
|
Setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAll()
|
||||||
|
{
|
||||||
|
UpdateBandsLayout();
|
||||||
|
UpdateTicksLayout();
|
||||||
|
UpdateStartEndEdgeLabelsLayout();
|
||||||
|
UpdateSunriseSunsetTicksLayout();
|
||||||
|
UpdateSunPanelsLayout();
|
||||||
|
UpdateMajorTickLabelsLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Ticks =====
|
||||||
|
private void EnsureTicks()
|
||||||
|
{
|
||||||
|
if (_ticks.Count > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tickHours.Clear();
|
||||||
|
|
||||||
|
// Build ticks at 0,2,4,...,24 but skip the first/last MAJOR ticks (0 and 24)
|
||||||
|
for (int hour = 0; hour <= 24; hour += TickHourStep)
|
||||||
|
{
|
||||||
|
bool isMajor = hour % 6 == 0;
|
||||||
|
if (isMajor && (hour == 0 || hour == 24))
|
||||||
|
{
|
||||||
|
continue; // skip first/last major ticks
|
||||||
|
}
|
||||||
|
|
||||||
|
var line = new Line
|
||||||
|
{
|
||||||
|
Style = (Style)Application.Current.Resources[isMajor ? "MajorHourTickStyle" : "HourTickStyle"],
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.SetZIndex(line, 0); // above bands (adjust if needed)
|
||||||
|
|
||||||
|
_ticks.Add(line);
|
||||||
|
_tickHours.Add(hour);
|
||||||
|
|
||||||
|
// If you actually want these IN the chart, use TimelineCanvas instead:
|
||||||
|
AnnotationCanvas.Children.Add(line); // or TimelineCanvas.Children.Add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTicksLayout()
|
||||||
|
{
|
||||||
|
double w = TimelineCanvas.ActualWidth;
|
||||||
|
double h = TimelineCanvas.ActualHeight; // keeping your offset
|
||||||
|
if (w <= 0 || h <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double minorLen = h * 0.1;
|
||||||
|
double majorLen = h * 0.2;
|
||||||
|
|
||||||
|
for (int i = 0; i < _ticks.Count; i++)
|
||||||
|
{
|
||||||
|
int hour = _tickHours[i];
|
||||||
|
double x = Math.Round((hour / 24.0) * w);
|
||||||
|
|
||||||
|
var line = _ticks[i];
|
||||||
|
double len = (hour % 6 == 0) ? majorLen : minorLen;
|
||||||
|
|
||||||
|
line.X1 = x;
|
||||||
|
line.Y1 = 0;
|
||||||
|
line.X2 = x;
|
||||||
|
line.Y2 = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Bands (Dark + Light) =====
|
||||||
|
private void EnsureBands()
|
||||||
|
{
|
||||||
|
if (_darkRects.Count == 0)
|
||||||
|
{
|
||||||
|
_darkRects.Add(MakeBandRect(isDark: true));
|
||||||
|
_darkRects.Add(MakeBandRect(isDark: true));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_lightRects.Count == 0)
|
||||||
|
{
|
||||||
|
_lightRects.Add(MakeBandRect(isDark: false));
|
||||||
|
_lightRects.Add(MakeBandRect(isDark: false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Border MakeBandRect(bool isDark)
|
||||||
|
{
|
||||||
|
var r = new Border();
|
||||||
|
if (isDark)
|
||||||
|
{
|
||||||
|
r.Style = (Style)Application.Current.Resources["DarkBandStyle"];
|
||||||
|
FontIcon icon = new FontIcon();
|
||||||
|
icon.Style = (Style)Application.Current.Resources["DarkBandIconStyle"];
|
||||||
|
r.Child = icon;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r.Style = (Style)Application.Current.Resources["LightBandStyle"];
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas.SetZIndex(r, 5); // below ticks/labels
|
||||||
|
TimelineCanvas.Children.Add(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateBandsLayout()
|
||||||
|
{
|
||||||
|
double w = TimelineCanvas.ActualWidth;
|
||||||
|
double h = TimelineCanvas.ActualHeight;
|
||||||
|
if (w <= 0 || h <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var r in _darkRects)
|
||||||
|
{
|
||||||
|
r.Height = h;
|
||||||
|
Canvas.SetTop(r, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var r in _lightRects)
|
||||||
|
{
|
||||||
|
r.Height = h;
|
||||||
|
Canvas.SetTop(r, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var darkRanges = ToRanges(StartTime, EndTime); // 1 or 2 segments
|
||||||
|
var lightRanges = ComplementRanges(darkRanges); // 0..2
|
||||||
|
|
||||||
|
LayoutRangeRects(_darkRects, darkRanges, w);
|
||||||
|
LayoutRangeRects(_lightRects, lightRanges, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LayoutRangeRects(List<Border> rects, List<(TimeSpan Start, TimeSpan End)> ranges, double width)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < rects.Count; i++)
|
||||||
|
{
|
||||||
|
if (i < ranges.Count)
|
||||||
|
{
|
||||||
|
var (start, end) = ranges[i];
|
||||||
|
double x = Math.Round((start.TotalHours / 24.0) * width);
|
||||||
|
double x2 = Math.Round((end.TotalHours / 24.0) * width);
|
||||||
|
|
||||||
|
var r = rects[i];
|
||||||
|
Canvas.SetLeft(r, x);
|
||||||
|
r.Width = Math.Max(0, x2 - x);
|
||||||
|
r.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rects[i].Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<(TimeSpan Start, TimeSpan End)> ToRanges(TimeSpan start, TimeSpan end)
|
||||||
|
{
|
||||||
|
// Full day
|
||||||
|
if (start == end)
|
||||||
|
{
|
||||||
|
return new() { (TimeSpan.Zero, TimeSpan.FromHours(24)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start < end)
|
||||||
|
{
|
||||||
|
return new() { (start, end) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wraps midnight
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
(start, TimeSpan.FromHours(24)),
|
||||||
|
(TimeSpan.Zero, end),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<(TimeSpan Start, TimeSpan End)> ComplementRanges(List<(TimeSpan Start, TimeSpan End)> dark)
|
||||||
|
{
|
||||||
|
var res = new List<(TimeSpan, TimeSpan)>();
|
||||||
|
|
||||||
|
// If dark covers the full day, there is no light
|
||||||
|
if (dark.Count == 1 && dark[0].Start == TimeSpan.Zero && dark[0].End == TimeSpan.FromHours(24))
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dark.Count == 1)
|
||||||
|
{
|
||||||
|
var (ds, de) = dark[0];
|
||||||
|
if (ds > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
res.Add((TimeSpan.Zero, ds));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (de < TimeSpan.FromHours(24))
|
||||||
|
{
|
||||||
|
res.Add((de, TimeSpan.FromHours(24)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// dark[0] = [a,24), dark[1] = [0,b) => single light [b,a)
|
||||||
|
var a = dark[0].Start;
|
||||||
|
var b = dark[1].End;
|
||||||
|
res.Add((b, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Start & End labels (TOP of chart, ABOVE rectangles) =====
|
||||||
|
private void EnsureStartEndEdgeLabels()
|
||||||
|
{
|
||||||
|
if (_startEdgeLabel == null)
|
||||||
|
{
|
||||||
|
_startEdgeLabel = new TextBlock { Style = (Style)Application.Current.Resources["EdgeLabelStyle"] };
|
||||||
|
HeaderCanvas.Children.Add(_startEdgeLabel);
|
||||||
|
Canvas.SetZIndex(_startEdgeLabel, 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_endEdgeLabel == null)
|
||||||
|
{
|
||||||
|
_endEdgeLabel = new TextBlock { Style = (Style)Application.Current.Resources["EdgeLabelStyle"] };
|
||||||
|
HeaderCanvas.Children.Add(_endEdgeLabel);
|
||||||
|
Canvas.SetZIndex(_endEdgeLabel, 25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateStartEndEdgeLabelsLayout()
|
||||||
|
{
|
||||||
|
double w = TimelineCanvas.ActualWidth;
|
||||||
|
if (w <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_startEdgeLabel.Text = FormatTime(StartTime);
|
||||||
|
_endEdgeLabel.Text = FormatTime(EndTime);
|
||||||
|
|
||||||
|
PlaceTopLabelAtTime(_startEdgeLabel, StartTime, w);
|
||||||
|
PlaceTopLabelAtTime(_endEdgeLabel, EndTime, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlaceTopLabelAtTime(TextBlock tb, TimeSpan t, double timelineWidth)
|
||||||
|
{
|
||||||
|
double x = Math.Round((t.TotalHours / 24.0) * timelineWidth);
|
||||||
|
double textW = MeasureTextWidth(tb);
|
||||||
|
double desiredLeft = x - (textW / 2.0);
|
||||||
|
|
||||||
|
Canvas.SetLeft(tb, Clamp(desiredLeft, 0, timelineWidth - textW));
|
||||||
|
Canvas.SetTop(tb, 0);
|
||||||
|
tb.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Sunrise/Sunset ticks on chart =====
|
||||||
|
private void EnsureSunriseSunsetTicks()
|
||||||
|
{
|
||||||
|
if (_sunriseTick == null)
|
||||||
|
{
|
||||||
|
_sunriseTick = new Line { Style = (Style)Application.Current.Resources["SunRiseMarkerTickStyle"] };
|
||||||
|
TimelineCanvas.Children.Add(_sunriseTick);
|
||||||
|
Canvas.SetZIndex(_sunriseTick, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sunsetTick == null)
|
||||||
|
{
|
||||||
|
_sunsetTick = new Line { Style = (Style)Application.Current.Resources["SunSetMarkerTickStyle"] };
|
||||||
|
TimelineCanvas.Children.Add(_sunsetTick);
|
||||||
|
Canvas.SetZIndex(_sunsetTick, 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSunriseSunsetTicksLayout()
|
||||||
|
{
|
||||||
|
double w = TimelineCanvas.ActualWidth;
|
||||||
|
double h = TimelineCanvas.ActualHeight + 24;
|
||||||
|
if (w <= 0 || h <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Place(Line tick, TimeSpan t)
|
||||||
|
{
|
||||||
|
double x = Math.Round((t.TotalHours / 24.0) * w);
|
||||||
|
tick.X1 = x;
|
||||||
|
tick.X2 = x;
|
||||||
|
tick.Y1 = 0;
|
||||||
|
tick.Y2 = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sunriseTick != null)
|
||||||
|
{
|
||||||
|
if (Sunrise.HasValue)
|
||||||
|
{
|
||||||
|
Place(_sunriseTick, Sunrise.Value);
|
||||||
|
_sunriseTick.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_sunriseTick.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sunsetTick != null)
|
||||||
|
{
|
||||||
|
if (Sunset.HasValue)
|
||||||
|
{
|
||||||
|
Place(_sunsetTick, Sunset.Value);
|
||||||
|
_sunsetTick.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_sunsetTick.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Sunrise/Sunset panels (below chart) =====
|
||||||
|
private void EnsureSunPanels()
|
||||||
|
{
|
||||||
|
if (_sunrisePanel == null)
|
||||||
|
{
|
||||||
|
_sunrisePanel = MakeSunPanel("\uEC8A");
|
||||||
|
AnnotationCanvas.Children.Add(_sunrisePanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sunsetPanel == null)
|
||||||
|
{
|
||||||
|
_sunsetPanel = MakeSunPanel("\uED3A");
|
||||||
|
AnnotationCanvas.Children.Add(_sunsetPanel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private StackPanel MakeSunPanel(string iconEmoji)
|
||||||
|
{
|
||||||
|
var icon = new FontIcon { Glyph = iconEmoji, Style = (Style)Application.Current.Resources["SunIconStyle"] };
|
||||||
|
var sp = new StackPanel { Orientation = Orientation.Vertical, Spacing = 2 };
|
||||||
|
sp.Children.Add(icon);
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSunPanelsLayout()
|
||||||
|
{
|
||||||
|
double timelineW = TimelineCanvas.ActualWidth;
|
||||||
|
double annotationW = AnnotationCanvas.ActualWidth;
|
||||||
|
if (annotationW <= 0)
|
||||||
|
{
|
||||||
|
annotationW = timelineW;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timelineW <= 0 || annotationW <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Place(StackPanel sp, TimeSpan t)
|
||||||
|
{
|
||||||
|
double panelW = MeasureElementWidth(sp);
|
||||||
|
double xTimeline = Math.Round((t.TotalHours / 24.0) * timelineW);
|
||||||
|
double left = Clamp(xTimeline - (panelW / 2.0), 0, annotationW - panelW);
|
||||||
|
Canvas.SetLeft(sp, left);
|
||||||
|
Canvas.SetTop(sp, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sunrisePanel != null)
|
||||||
|
{
|
||||||
|
if (Sunrise.HasValue)
|
||||||
|
{
|
||||||
|
ToolTipService.SetToolTip(_sunrisePanel, $"Sunrise: {FormatTime(Sunrise.Value)}");
|
||||||
|
_sunrisePanel.Visibility = Visibility.Visible;
|
||||||
|
Place(_sunrisePanel, Sunrise.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ToolTipService.SetToolTip(_sunrisePanel, null);
|
||||||
|
_sunrisePanel.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sunsetPanel != null)
|
||||||
|
{
|
||||||
|
if (Sunset.HasValue)
|
||||||
|
{
|
||||||
|
ToolTipService.SetToolTip(_sunsetPanel, $"Sunset: {FormatTime(Sunset.Value)}");
|
||||||
|
_sunsetPanel.Visibility = Visibility.Visible;
|
||||||
|
Place(_sunsetPanel, Sunset.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ToolTipService.SetToolTip(_sunsetPanel, null);
|
||||||
|
_sunsetPanel.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Major labels BELOW chart (00,06,12,18,24) =====
|
||||||
|
private void EnsureMajorTickLabels()
|
||||||
|
{
|
||||||
|
if (_majorTickBottomLabels.Count > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Includes 24:00 at end
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
var tb = new TextBlock { Style = (Style)Application.Current.Resources["MajorTickLabelStyle"] };
|
||||||
|
Canvas.SetZIndex(tb, 5); // on annotation canvas
|
||||||
|
_majorTickBottomLabels.Add(tb);
|
||||||
|
AnnotationCanvas.Children.Add(tb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateMajorTickLabelsLayout()
|
||||||
|
{
|
||||||
|
double timelineW = TimelineCanvas.ActualWidth;
|
||||||
|
double annotationW = AnnotationCanvas.ActualWidth;
|
||||||
|
if (annotationW <= 0)
|
||||||
|
{
|
||||||
|
annotationW = timelineW;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timelineW <= 0 || annotationW <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] hours = { 0, 6, 12, 18, 24 };
|
||||||
|
|
||||||
|
// 1) Place labels first
|
||||||
|
for (int i = 0; i < hours.Length; i++)
|
||||||
|
{
|
||||||
|
var tb = _majorTickBottomLabels[i];
|
||||||
|
var t = TimeSpan.FromHours(hours[i]);
|
||||||
|
tb.Text = FormatTime(t);
|
||||||
|
|
||||||
|
double xTimeline = Math.Round((t.TotalHours / 24.0) * timelineW);
|
||||||
|
double textW = MeasureTextWidth(tb);
|
||||||
|
double left = xTimeline - (textW / 2.0);
|
||||||
|
|
||||||
|
// Middle ones (06, 12) exact center; edges clamp inside canvas
|
||||||
|
if (i == 1 || i == 2)
|
||||||
|
{
|
||||||
|
Canvas.SetLeft(tb, left);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Canvas.SetLeft(tb, Clamp(left, 0, annotationW - textW));
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas.SetTop(tb, 8); // your existing baseline below chart
|
||||||
|
tb.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Compute sunrise/sunset occupied horizontal ranges (if present)
|
||||||
|
(double Left, double Right)? sunriseBounds = null;
|
||||||
|
(double Left, double Right)? sunsetBounds = null;
|
||||||
|
|
||||||
|
if (Sunrise.HasValue && _sunrisePanel != null)
|
||||||
|
{
|
||||||
|
sunriseBounds = GetAnnotationBoundsForTime(Sunrise.Value, timelineW, annotationW, _sunrisePanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Sunset.HasValue && _sunsetPanel != null)
|
||||||
|
{
|
||||||
|
sunsetBounds = GetAnnotationBoundsForTime(Sunset.Value, timelineW, annotationW, _sunsetPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Hide any label that intersects the sunrise/sunset panel bounds
|
||||||
|
for (int i = 0; i < hours.Length; i++)
|
||||||
|
{
|
||||||
|
var tb = _majorTickBottomLabels[i];
|
||||||
|
if (tb.Visibility != Visibility.Visible)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lbl = GetLabelBounds(tb);
|
||||||
|
|
||||||
|
bool hide =
|
||||||
|
(sunriseBounds.HasValue && Intersects(lbl, sunriseBounds.Value)) ||
|
||||||
|
(sunsetBounds.HasValue && Intersects(lbl, sunsetBounds.Value)); // include sunset too; remove if you only want sunrise
|
||||||
|
|
||||||
|
tb.Visibility = hide ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Utilities =====
|
||||||
|
private string FormatTime(TimeSpan ts)
|
||||||
|
{
|
||||||
|
var dt = DateTime.Today.Add(ts);
|
||||||
|
if (_is24h)
|
||||||
|
{
|
||||||
|
if (ts.TotalHours >= 24)
|
||||||
|
{
|
||||||
|
dt = DateTime.Today; // show 24:00 as 00:00
|
||||||
|
}
|
||||||
|
|
||||||
|
return dt.ToString("HH:mm", CultureInfo.CurrentCulture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return dt.ToString("h:mm", CultureInfo.CurrentCulture)
|
||||||
|
+ dt.ToString("tt", CultureInfo.CurrentCulture).ToUpper(CultureInfo.CurrentCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double Clamp(double v, double min, double max) => Math.Max(min, Math.Min(max, v));
|
||||||
|
|
||||||
|
private static double MeasureElementWidth(FrameworkElement el)
|
||||||
|
{
|
||||||
|
el.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||||
|
return el.DesiredSize.Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double MeasureTextWidth(TextBlock tb)
|
||||||
|
{
|
||||||
|
tb.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||||
|
return tb.DesiredSize.Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool Intersects((double Left, double Right) a, (double Left, double Right) b, double pad = 4)
|
||||||
|
{
|
||||||
|
// Horizontal overlap with padding
|
||||||
|
return !(a.Right + pad <= b.Left || b.Right + pad <= a.Left);
|
||||||
|
}
|
||||||
|
|
||||||
|
private (double Left, double Right) GetAnnotationBoundsForTime(TimeSpan t, double timelineW, double annotationW, FrameworkElement element)
|
||||||
|
{
|
||||||
|
// Compute the *actual* left/right the panel will occupy in AnnotationCanvas
|
||||||
|
double panelW = MeasureElementWidth(element);
|
||||||
|
double xTimeline = Math.Round((t.TotalHours / 24.0) * timelineW);
|
||||||
|
double left = Clamp(xTimeline - (panelW / 2.0), 0, annotationW - panelW);
|
||||||
|
return (left, left + panelW);
|
||||||
|
}
|
||||||
|
|
||||||
|
private (double Left, double Right) GetLabelBounds(TextBlock tb)
|
||||||
|
{
|
||||||
|
double w = MeasureTextWidth(tb);
|
||||||
|
double left = Canvas.GetLeft(tb);
|
||||||
|
return (left, left + w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<Style x:Key="HourTickStyle" TargetType="Line">
|
||||||
|
<Setter Property="Stroke" Value="{ThemeResource TextFillColorTertiaryBrush}" />
|
||||||
|
<Setter Property="StrokeThickness" Value="1" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style
|
||||||
|
x:Key="MajorHourTickStyle"
|
||||||
|
BasedOn="{StaticResource HourTickStyle}"
|
||||||
|
TargetType="Line">
|
||||||
|
<Setter Property="StrokeThickness" Value="2" />
|
||||||
|
<Setter Property="Stroke" Value="{ThemeResource TextFillColorTertiaryBrush}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="SunRiseMarkerTickStyle" TargetType="Line">
|
||||||
|
<Setter Property="Stroke" Value="{ThemeResource TextFillColorTertiaryBrush}" />
|
||||||
|
<Setter Property="StrokeThickness" Value="1" />
|
||||||
|
<Setter Property="StrokeDashArray" Value="2,2" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
|
||||||
|
<Style x:Key="SunSetMarkerTickStyle" TargetType="Line">
|
||||||
|
<Setter Property="Stroke" Value="{ThemeResource TextFillColorTertiaryBrush}" />
|
||||||
|
<Setter Property="StrokeThickness" Value="1" />
|
||||||
|
<Setter Property="StrokeDashArray" Value="2,2" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- ===== Text / Labels ===== -->
|
||||||
|
<Style x:Key="EdgeLabelStyle" TargetType="TextBlock">
|
||||||
|
<Setter Property="FontSize" Value="14" />
|
||||||
|
<Setter Property="FontWeight" Value="SemiBold" />
|
||||||
|
<Setter Property="Foreground" Value="{ThemeResource AccentTextFillColorPrimaryBrush}" />
|
||||||
|
<Setter Property="IsHitTestVisible" Value="False" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Below-chart labels for 00/06/12/18/24 -->
|
||||||
|
<Style x:Key="MajorTickLabelStyle" TargetType="TextBlock">
|
||||||
|
<Setter Property="FontSize" Value="12" />
|
||||||
|
<Setter Property="Foreground" Value="{ThemeResource TextFillColorTertiaryBrush}" />
|
||||||
|
<Setter Property="IsHitTestVisible" Value="False" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Sunrise/Sunset panel styles -->
|
||||||
|
<Style x:Key="SunIconStyle" TargetType="FontIcon">
|
||||||
|
<Setter Property="FontSize" Value="18" />
|
||||||
|
<Setter Property="Foreground" Value="{ThemeResource TextFillColorTertiaryBrush}" />
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- ===== Bands ===== -->
|
||||||
|
<Style x:Key="DarkBandStyle" TargetType="Border">
|
||||||
|
<Setter Property="Background" Value="{ThemeResource AccentFillColorDefaultBrush}" />
|
||||||
|
<Setter Property="CornerRadius" Value="8" />
|
||||||
|
<Setter Property="Padding" Value="4" />
|
||||||
|
<Setter Property="ToolTipService.ToolTip" Value="Dark mode" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="LightBandStyle" TargetType="Border">
|
||||||
|
<Setter Property="Background" Value="{ThemeResource CardBackgroundFillColorDefaultBrush}" />
|
||||||
|
<Setter Property="ToolTipService.ToolTip" Value="Light mode" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="DarkBandIconStyle" TargetType="FontIcon">
|
||||||
|
<Setter Property="FontSize" Value="14" />
|
||||||
|
<Setter Property="Glyph" Value="" />
|
||||||
|
<Setter Property="Foreground" Value="{ThemeResource TextOnAccentFillColorPrimaryBrush}" />
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||||
|
</Style>
|
||||||
|
<Style
|
||||||
|
x:Key="LightBandIconStyle"
|
||||||
|
BasedOn="{StaticResource DarkBandIconStyle}"
|
||||||
|
TargetType="FontIcon">
|
||||||
|
<Setter Property="Glyph" Value="" />
|
||||||
|
<Setter Property="Foreground" Value="{ThemeResource TextFillColorSecondaryBrush}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Page
|
||||||
|
x:Class="Microsoft.PowerToys.Settings.UI.Views.LightSwitchPage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:ViewModel="using:Microsoft.PowerToys.Settings.UI.ViewModels"
|
||||||
|
xmlns:animations="using:CommunityToolkit.WinUI.Animations"
|
||||||
|
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||||
|
xmlns:converters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:helpers="using:Settings.UI.Library.Helpers"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||||
|
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
|
||||||
|
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||||
|
d:DataContext="{d:DesignInstance Type=ViewModel:LightSwitchViewModel}"
|
||||||
|
AutomationProperties.LandmarkType="Main"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Page.Resources>
|
||||||
|
<converters:EnumToVisibilityConverter x:Key="EnumToVisibilityConverter" />
|
||||||
|
<animations:ImplicitAnimationSet x:Name="ShowTransitions">
|
||||||
|
<animations:OffsetAnimation
|
||||||
|
EasingMode="EaseOut"
|
||||||
|
From="0,24,0"
|
||||||
|
To="0"
|
||||||
|
Duration="0:0:0.4" />
|
||||||
|
<animations:OpacityAnimation
|
||||||
|
EasingMode="EaseOut"
|
||||||
|
From="0"
|
||||||
|
To="1"
|
||||||
|
Duration="0:0:0.2" />
|
||||||
|
</animations:ImplicitAnimationSet>
|
||||||
|
<animations:ImplicitAnimationSet x:Name="HideTransitions">
|
||||||
|
<animations:OffsetAnimation
|
||||||
|
EasingMode="EaseOut"
|
||||||
|
From="0"
|
||||||
|
To="0,24,0"
|
||||||
|
Duration="0:0:0.2" />
|
||||||
|
<animations:OpacityAnimation
|
||||||
|
EasingMode="EaseOut"
|
||||||
|
From="1"
|
||||||
|
To="0"
|
||||||
|
Duration="0:0:0.1" />
|
||||||
|
</animations:ImplicitAnimationSet>
|
||||||
|
</Page.Resources>
|
||||||
|
|
||||||
|
<controls:SettingsPageControl
|
||||||
|
x:Uid="LightSwitch"
|
||||||
|
IsTabStop="False"
|
||||||
|
ModuleImageSource="ms-appx:///Assets/Settings/Modules/Awake.png">
|
||||||
|
<controls:SettingsPageControl.ModuleContent>
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<tkcontrols:SettingsCard
|
||||||
|
Header="Enable LightSwitch"
|
||||||
|
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/LightSwitch.png}"
|
||||||
|
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||||
|
<ToggleSwitch IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
|
||||||
|
<InfoBar
|
||||||
|
x:Uid="GPO_SettingIsManaged"
|
||||||
|
IsClosable="False"
|
||||||
|
IsOpen="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay}"
|
||||||
|
IsTabStop="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay}"
|
||||||
|
Severity="Informational" />
|
||||||
|
|
||||||
|
<controls:SettingsGroup Header="Schedule" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||||
|
<tkcontrols:SettingsCard
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
ContentAlignment="Vertical"
|
||||||
|
Description="See when dark mode and light mode kick in"
|
||||||
|
Header="Schedule preview">
|
||||||
|
<controls:Timeline
|
||||||
|
Margin="0,48,0,48"
|
||||||
|
EndTime="{x:Bind ViewModel.DarkTimeTimeSpan, Mode=OneWay}"
|
||||||
|
StartTime="{x:Bind ViewModel.LightTimeTimeSpan, Mode=OneWay}"
|
||||||
|
Sunrise="07:00"
|
||||||
|
Sunset="21:00" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
|
||||||
|
<tkcontrols:SettingsExpander
|
||||||
|
Description="Determine when dark mode should be turned on"
|
||||||
|
Header="Set schedule"
|
||||||
|
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<ComboBox
|
||||||
|
SelectedValue="{x:Bind ViewModel.ScheduleMode, Mode=TwoWay}"
|
||||||
|
SelectedValuePath="Tag"
|
||||||
|
SelectionChanged="ScheduleMode_SelectionChanged">
|
||||||
|
<ComboBoxItem Content="Manual" Tag="FixedHours" />
|
||||||
|
<ComboBoxItem Content="Sunset to sunrise" Tag="SunsetToSunriseGeo" />
|
||||||
|
</ComboBox>
|
||||||
|
<tkcontrols:SettingsExpander.Items>
|
||||||
|
<tkcontrols:SettingsCard Header="Turn on darkmode" Visibility="{x:Bind ViewModel.ScheduleMode, Mode=OneWay, Converter={StaticResource EnumToVisibilityConverter}, ConverterParameter=FixedHours}">
|
||||||
|
<TimePicker ClockIdentifier="24HourClock" Time="{x:Bind ViewModel.LightTimeTimeSpan, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
<tkcontrols:SettingsCard Header="Turn off darkmode" Visibility="{x:Bind ViewModel.ScheduleMode, Mode=OneWay, Converter={StaticResource EnumToVisibilityConverter}, ConverterParameter=FixedHours}">
|
||||||
|
<TimePicker ClockIdentifier="24HourClock" Time="{x:Bind ViewModel.DarkTimeTimeSpan, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
<tkcontrols:SettingsCard
|
||||||
|
Description="Calculated by the selected location"
|
||||||
|
Header="Sunrise and sunset times"
|
||||||
|
Visibility="{x:Bind ViewModel.ScheduleMode, Mode=OneWay, Converter={StaticResource EnumToVisibilityConverter}, ConverterParameter=SunsetToSunriseGeo}">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
Text="08:00 - 17:00" />
|
||||||
|
<Button Click="SyncLocationButton_Click" Content="Sync" />
|
||||||
|
</StackPanel>
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
<tkcontrols:SettingsCard
|
||||||
|
Description="Adjust the trigger time by starting earlier or later than the actual sunrise or sunset"
|
||||||
|
Header="Sunrise or sunset offset"
|
||||||
|
Visibility="{x:Bind ViewModel.ScheduleMode, Mode=OneWay, Converter={StaticResource EnumToVisibilityConverter}, ConverterParameter=SunsetToSunriseGeo}">
|
||||||
|
<Grid VerticalAlignment="Center" ColumnSpacing="8">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Slider
|
||||||
|
x:Name="geoOffsetSlider"
|
||||||
|
MinWidth="132"
|
||||||
|
Maximum="60"
|
||||||
|
Minimum="-60"
|
||||||
|
SnapsTo="StepValues"
|
||||||
|
TickFrequency="15"
|
||||||
|
TickPlacement="Outside"
|
||||||
|
Value="{x:Bind ViewModel.Offset, Mode=TwoWay}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
MinWidth="78"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
TextAlignment="Right">
|
||||||
|
<Run x:Name="geoOffsetValue" Text="{x:Bind ViewModel.Offset, Mode=OneWay}" />
|
||||||
|
<Run Text="minutes" />
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
|
||||||
|
<tkcontrols:SettingsCard Header="Apply an offset in minutes" Visibility="{x:Bind ViewModel.ScheduleMode, Mode=OneWay, Converter={StaticResource EnumToVisibilityConverter}, ConverterParameter=SunsetToSunriseUser}">
|
||||||
|
<Grid VerticalAlignment="Center">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Slider
|
||||||
|
x:Name="useroffsetSlider"
|
||||||
|
Grid.Column="0"
|
||||||
|
Maximum="60"
|
||||||
|
Minimum="-60"
|
||||||
|
SnapsTo="StepValues"
|
||||||
|
TickFrequency="15"
|
||||||
|
TickPlacement="Outside"
|
||||||
|
Value="{x:Bind ViewModel.Offset, Mode=TwoWay}" />
|
||||||
|
<TextBlock
|
||||||
|
x:Name="userOffsetValue"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="10,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
Text="{x:Bind ViewModel.Offset, Mode=OneWay}" />
|
||||||
|
</Grid>
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
</tkcontrols:SettingsExpander.Items>
|
||||||
|
</tkcontrols:SettingsExpander>
|
||||||
|
|
||||||
|
<controls:SettingsGroup Header="Behavior" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||||
|
<tkcontrols:SettingsExpander
|
||||||
|
Description="Pick which parts of your PC should follow dark mode"
|
||||||
|
Header="Apply dark mode to"
|
||||||
|
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||||
|
IsExpanded="True">
|
||||||
|
<tkcontrols:SettingsExpander.Items>
|
||||||
|
<tkcontrols:SettingsCard HorizontalContentAlignment="Stretch" ContentAlignment="Left">
|
||||||
|
<controls:CheckBoxWithDescriptionControl
|
||||||
|
Description="Taskbar, Start, and other system UI"
|
||||||
|
Header="System"
|
||||||
|
IsChecked="{x:Bind ViewModel.ChangeSystem, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
<tkcontrols:SettingsCard HorizontalContentAlignment="Stretch" ContentAlignment="Left">
|
||||||
|
<controls:CheckBoxWithDescriptionControl
|
||||||
|
Description="Supported applications"
|
||||||
|
Header="Apps"
|
||||||
|
IsChecked="{x:Bind ViewModel.ChangeApps, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
</tkcontrols:SettingsExpander.Items>
|
||||||
|
</tkcontrols:SettingsExpander>
|
||||||
|
</controls:SettingsGroup>
|
||||||
|
<!-- Force mode buttons -->
|
||||||
|
<!--<tkcontrols:SettingsCard
|
||||||
|
Header="Force mode now"
|
||||||
|
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||||
|
Description="Apply light or dark mode immediately">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="12">
|
||||||
|
<Button
|
||||||
|
Content="Force Light"
|
||||||
|
Command="{x:Bind ViewModel.ForceLightCommand}" />
|
||||||
|
<Button
|
||||||
|
Content="Force Dark"
|
||||||
|
Command="{x:Bind ViewModel.ForceDarkCommand}" />
|
||||||
|
</StackPanel>
|
||||||
|
</tkcontrols:SettingsCard>-->
|
||||||
|
|
||||||
|
<ContentDialog
|
||||||
|
x:Name="LocationDialog"
|
||||||
|
Title="Select a location"
|
||||||
|
IsPrimaryButtonEnabled="True"
|
||||||
|
IsSecondaryButtonEnabled="True"
|
||||||
|
PrimaryButtonStyle="{StaticResource AccentButtonStyle}"
|
||||||
|
PrimaryButtonText="Select"
|
||||||
|
SecondaryButtonText="Cancel">
|
||||||
|
<Grid MinHeight="268">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Text="To calculate the sunrise and sunset, enter a location to be used." />
|
||||||
|
<tkcontrols:Segmented
|
||||||
|
x:Name="locationSegmented"
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="0,16,0,12"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
SelectedIndex="0">
|
||||||
|
<tkcontrols:SegmentedItem Content="Find my location" Tag="Auto" />
|
||||||
|
<tkcontrols:SegmentedItem Content="Select a city" Tag="Selection" />
|
||||||
|
</tkcontrols:Segmented>
|
||||||
|
<tkcontrols:SwitchPresenter Grid.Row="2" Value="{Binding SelectedItem.Tag, ElementName=locationSegmented}">
|
||||||
|
<tkcontrols:Case Value="Auto">
|
||||||
|
<Grid animations:Implicit.HideAnimations="{StaticResource HideTransitions}" animations:Implicit.ShowAnimations="{StaticResource ShowTransitions}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid>
|
||||||
|
<TextBlock x:Name="SunTimes" VerticalAlignment="Center" />
|
||||||
|
<StackPanel
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
Spacing="8">
|
||||||
|
<ProgressRing
|
||||||
|
x:Name="SyncLoader"
|
||||||
|
Width="16"
|
||||||
|
Height="16"
|
||||||
|
IsActive="False"
|
||||||
|
Visibility="Collapsed" />
|
||||||
|
<Button
|
||||||
|
x:Name="SyncButton"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Click="GetLocation_Click"
|
||||||
|
Content="Sync" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
<TextBlock Grid.Row="1">
|
||||||
|
<Run Text="Sunrise:" />
|
||||||
|
<Run Text="{x:Bind ViewModel.LightTime}" />
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Grid.Row="2">
|
||||||
|
<Run Text="Sunset:" />
|
||||||
|
<Run Text="{x:Bind ViewModel.DarkTime}" />
|
||||||
|
</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
</tkcontrols:Case>
|
||||||
|
<tkcontrols:Case Value="Selection">
|
||||||
|
<Grid animations:Implicit.HideAnimations="{StaticResource HideTransitions}" animations:Implicit.ShowAnimations="{StaticResource ShowTransitions}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<ComboBox
|
||||||
|
x:Name="CityComboBox"
|
||||||
|
Margin="0,0,0,8"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
DisplayMemberPath="Display"
|
||||||
|
Header="Search for a city"
|
||||||
|
ItemsSource="{x:Bind ViewModel.Cities, Mode=OneWay}"
|
||||||
|
PlaceholderText="Select city"
|
||||||
|
SelectedItem="{x:Bind ViewModel.SelectedCity, Mode=TwoWay}">
|
||||||
|
<!--<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="helpers:City">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<TextBlock Text="{x:Bind Name}" />
|
||||||
|
<TextBlock
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
|
Text="{x:Bind Country}" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>-->
|
||||||
|
</ComboBox>
|
||||||
|
<!-- Todo: Updated times from changing city -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1">
|
||||||
|
<Run Text="Sunrise:" />
|
||||||
|
<Run Text="{x:Bind ViewModel.CityTimesText, Mode=OneWay}" />
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Grid.Row="2">
|
||||||
|
<Run Text="Sunset:" />
|
||||||
|
<Run Text="{x:Bind ViewModel.CityTimesText, Mode=OneWay}" />
|
||||||
|
</TextBlock>
|
||||||
|
<!-- Todo: Option to add an offset -->
|
||||||
|
</Grid>
|
||||||
|
</tkcontrols:Case>
|
||||||
|
</tkcontrols:SwitchPresenter>
|
||||||
|
</Grid>
|
||||||
|
</ContentDialog>
|
||||||
|
</controls:SettingsGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<controls:SettingsGroup Header="Shortcuts" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||||
|
|
||||||
|
<!--<tkcontrols:SettingsCard x:Uid="LightSwitch_ForceLightMode_Shortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||||
|
<controls:ShortcutControl
|
||||||
|
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||||
|
AllowDisable="True"
|
||||||
|
HotkeySettings="{x:Bind Path=ViewModel.ForceLightModeActivationShortcut, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>-->
|
||||||
|
<tkcontrols:SettingsCard x:Uid="LightSwitch_ThemeToggle_Shortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||||
|
<controls:ShortcutControl
|
||||||
|
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||||
|
AllowDisable="True"
|
||||||
|
HotkeySettings="{x:Bind Path=ViewModel.ForceDarkModeActivationShortcut, Mode=TwoWay}" />
|
||||||
|
</tkcontrols:SettingsCard>
|
||||||
|
</controls:SettingsGroup>
|
||||||
|
</StackPanel>
|
||||||
|
</controls:SettingsPageControl.ModuleContent>
|
||||||
|
|
||||||
|
<controls:SettingsPageControl.PrimaryLinks>
|
||||||
|
<controls:PageLink x:Uid="LearnMore_LightSwitch" Link="https://aka.ms/PowerToysOverview_ZoomIt" />
|
||||||
|
</controls:SettingsPageControl.PrimaryLinks>
|
||||||
|
</controls:SettingsPageControl>
|
||||||
|
</Page>
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
// 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 System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Abstractions;
|
||||||
|
using System.Linq;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||||
|
using Microsoft.UI.Dispatching;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using PowerToys.GPOWrapper;
|
||||||
|
using Settings.UI.Library;
|
||||||
|
using Windows.Devices.Geolocation;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||||
|
{
|
||||||
|
public sealed partial class LightSwitchPage : Page
|
||||||
|
{
|
||||||
|
private readonly string _appName = "LightSwitch";
|
||||||
|
private readonly SettingsUtils _settingsUtils;
|
||||||
|
private readonly Func<string, int> _sendConfigMsg = ShellPage.SendDefaultIPCMessage;
|
||||||
|
|
||||||
|
private readonly ISettingsRepository<GeneralSettings> _generalSettingsRepository;
|
||||||
|
private readonly ISettingsRepository<LightSwitchSettings> _moduleSettingsRepository;
|
||||||
|
|
||||||
|
private readonly IFileSystem _fileSystem;
|
||||||
|
private readonly IFileSystemWatcher _fileSystemWatcher;
|
||||||
|
private readonly DispatcherQueue _dispatcherQueue;
|
||||||
|
|
||||||
|
private LightSwitchViewModel ViewModel { get; set; }
|
||||||
|
|
||||||
|
public LightSwitchPage()
|
||||||
|
{
|
||||||
|
_settingsUtils = new SettingsUtils();
|
||||||
|
_sendConfigMsg = ShellPage.SendDefaultIPCMessage;
|
||||||
|
|
||||||
|
_generalSettingsRepository = SettingsRepository<GeneralSettings>.GetInstance(_settingsUtils);
|
||||||
|
_moduleSettingsRepository = SettingsRepository<LightSwitchSettings>.GetInstance(_settingsUtils);
|
||||||
|
|
||||||
|
// Get settings from JSON (or defaults if JSON missing)
|
||||||
|
var darkSettings = _moduleSettingsRepository.SettingsConfig;
|
||||||
|
|
||||||
|
// Pass them into the ViewModel
|
||||||
|
ViewModel = new LightSwitchViewModel(darkSettings, ShellPage.SendDefaultIPCMessage);
|
||||||
|
ViewModel.PropertyChanged += ViewModel_PropertyChanged;
|
||||||
|
|
||||||
|
LoadSettings(_generalSettingsRepository, _moduleSettingsRepository);
|
||||||
|
|
||||||
|
DataContext = ViewModel;
|
||||||
|
|
||||||
|
var settingsPath = _settingsUtils.GetSettingsFilePath(_appName);
|
||||||
|
|
||||||
|
_dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||||
|
_fileSystem = new FileSystem();
|
||||||
|
|
||||||
|
_fileSystemWatcher = _fileSystem.FileSystemWatcher.New();
|
||||||
|
_fileSystemWatcher.Path = _fileSystem.Path.GetDirectoryName(settingsPath);
|
||||||
|
_fileSystemWatcher.Filter = _fileSystem.Path.GetFileName(settingsPath);
|
||||||
|
_fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime;
|
||||||
|
_fileSystemWatcher.Changed += Settings_Changed;
|
||||||
|
_fileSystemWatcher.EnableRaisingEvents = true;
|
||||||
|
|
||||||
|
this.InitializeComponent();
|
||||||
|
this.Loaded += LightSwitchPage_Loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LightSwitchPage_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (ViewModel.Cities.Count == 0)
|
||||||
|
{
|
||||||
|
string csvPath = Path.Combine(AppContext.BaseDirectory, "Assets/world_cities.csv");
|
||||||
|
System.Diagnostics.Debug.WriteLine($"Looking for world_cities.csv at: {csvPath}");
|
||||||
|
if (File.Exists(csvPath))
|
||||||
|
{
|
||||||
|
foreach (var city in CityLoader.LoadCities(csvPath))
|
||||||
|
{
|
||||||
|
ViewModel.Cities.Add(city);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine("world_cities.csv not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ViewModel.ScheduleMode == "SunsetToSunriseUser" &&
|
||||||
|
double.TryParse(ViewModel.Latitude, NumberStyles.Float, CultureInfo.InvariantCulture, out double savedLat) &&
|
||||||
|
double.TryParse(ViewModel.Longitude, NumberStyles.Float, CultureInfo.InvariantCulture, out double savedLng))
|
||||||
|
{
|
||||||
|
var match = ViewModel.Cities.FirstOrDefault(c =>
|
||||||
|
Math.Abs(c.Latitude - savedLat) < 0.0001 &&
|
||||||
|
Math.Abs(c.Longitude - savedLng) < 0.0001);
|
||||||
|
|
||||||
|
if (match != null)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedCity = match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ViewModel.ScheduleMode == "SunsetToSunriseGeo")
|
||||||
|
{
|
||||||
|
SunTimes.Text = $"Sunrise: {ViewModel.LightTime / 60:D2}:{ViewModel.LightTime % 60:D2} " +
|
||||||
|
$"Sunset: {ViewModel.DarkTime / 60:D2}:{ViewModel.DarkTime % 60:D2}";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback text
|
||||||
|
SunTimes.Text = "Please Sync to update Sunrise/Sunset times";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
SunTimes.Text = "Please Sync to update Sunrise/Sunset times";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void GetLocation_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
SyncButton.IsEnabled = false;
|
||||||
|
SyncLoader.IsActive = true;
|
||||||
|
SyncLoader.Visibility = Visibility.Visible;
|
||||||
|
SunTimes.Text = "Loading...";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Request access
|
||||||
|
var accessStatus = await Geolocator.RequestAccessAsync();
|
||||||
|
if (accessStatus != GeolocationAccessStatus.Allowed)
|
||||||
|
{
|
||||||
|
// User denied location or it's not available
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var geolocator = new Geolocator { DesiredAccuracy = PositionAccuracy.Default };
|
||||||
|
|
||||||
|
// Get the position
|
||||||
|
Geoposition pos = await geolocator.GetGeopositionAsync();
|
||||||
|
|
||||||
|
double latitude = Math.Round(pos.Coordinate.Point.Position.Latitude);
|
||||||
|
double longitude = Math.Round(pos.Coordinate.Point.Position.Longitude);
|
||||||
|
|
||||||
|
SunTimes result = SunCalc.CalculateSunriseSunset(
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
DateTime.Now.Year,
|
||||||
|
DateTime.Now.Month,
|
||||||
|
DateTime.Now.Day);
|
||||||
|
|
||||||
|
SunTimes.Text = "Sunrise: " + result.SunriseHour + ":" + result.SunriseMinute + " " +
|
||||||
|
"Sunset: " + result.SunsetHour + ":" + result.SunsetMinute;
|
||||||
|
|
||||||
|
ViewModel.LightTime = (result.SunriseHour * 60) + result.SunriseMinute;
|
||||||
|
ViewModel.DarkTime = (result.SunsetHour * 60) + result.SunsetMinute;
|
||||||
|
|
||||||
|
SyncButton.IsEnabled = true;
|
||||||
|
SyncLoader.IsActive = false;
|
||||||
|
SyncLoader.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SyncButton.IsEnabled = true;
|
||||||
|
SyncLoader.IsActive = false;
|
||||||
|
System.Diagnostics.Debug.WriteLine("Location error: " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScheduleMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var combo = (ComboBox)sender;
|
||||||
|
var selectedTag = (combo.SelectedItem as ComboBoxItem)?.Tag?.ToString();
|
||||||
|
|
||||||
|
if (selectedTag == "FixedHours")
|
||||||
|
{
|
||||||
|
ViewModel.LightTime = 360;
|
||||||
|
ViewModel.DarkTime = 1080;
|
||||||
|
}
|
||||||
|
else if (selectedTag == "SunsetToSunrise")
|
||||||
|
{
|
||||||
|
SunTimes.Text = "Please Sync to update Sunrise/Sunset times";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == "IsEnabled")
|
||||||
|
{
|
||||||
|
if (ViewModel.IsEnabled != _generalSettingsRepository.SettingsConfig.Enabled.LightSwitch)
|
||||||
|
{
|
||||||
|
_generalSettingsRepository.SettingsConfig.Enabled.LightSwitch = ViewModel.IsEnabled;
|
||||||
|
|
||||||
|
var generalSettingsMessage = new OutGoingGeneralSettings(_generalSettingsRepository.SettingsConfig).ToString();
|
||||||
|
Logger.LogInfo($"Saved general settings from Light Switch page.");
|
||||||
|
|
||||||
|
_sendConfigMsg?.Invoke(generalSettingsMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ViewModel.ModuleSettings != null)
|
||||||
|
{
|
||||||
|
SndLightSwitchSettings currentSettings = new(_moduleSettingsRepository.SettingsConfig);
|
||||||
|
SndModuleSettings<SndLightSwitchSettings> csIpcMessage = new(currentSettings);
|
||||||
|
|
||||||
|
SndLightSwitchSettings outSettings = new(ViewModel.ModuleSettings);
|
||||||
|
SndModuleSettings<SndLightSwitchSettings> outIpcMessage = new(outSettings);
|
||||||
|
|
||||||
|
string csMessage = csIpcMessage.ToJsonString();
|
||||||
|
string outMessage = outIpcMessage.ToJsonString();
|
||||||
|
|
||||||
|
if (!csMessage.Equals(outMessage, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Logger.LogInfo($"Saved Light Switch settings from Light Switch page.");
|
||||||
|
|
||||||
|
_sendConfigMsg?.Invoke(outMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadSettings(ISettingsRepository<GeneralSettings> generalSettingsRepository, ISettingsRepository<LightSwitchSettings> moduleSettingsRepository)
|
||||||
|
{
|
||||||
|
if (generalSettingsRepository != null)
|
||||||
|
{
|
||||||
|
if (moduleSettingsRepository != null)
|
||||||
|
{
|
||||||
|
UpdateViewModelSettings(moduleSettingsRepository.SettingsConfig, generalSettingsRepository.SettingsConfig);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(moduleSettingsRepository));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(generalSettingsRepository));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateViewModelSettings(LightSwitchSettings lightSwitchSettings, GeneralSettings generalSettings)
|
||||||
|
{
|
||||||
|
if (lightSwitchSettings != null)
|
||||||
|
{
|
||||||
|
if (generalSettings != null)
|
||||||
|
{
|
||||||
|
ViewModel.IsEnabled = generalSettings.Enabled.LightSwitch;
|
||||||
|
ViewModel.ModuleSettings = (LightSwitchSettings)lightSwitchSettings.Clone();
|
||||||
|
|
||||||
|
UpdateEnabledState(generalSettings.Enabled.LightSwitch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(generalSettings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(lightSwitchSettings));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Settings_Changed(object sender, FileSystemEventArgs e)
|
||||||
|
{
|
||||||
|
_dispatcherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
_moduleSettingsRepository.ReloadSettings();
|
||||||
|
LoadSettings(_generalSettingsRepository, _moduleSettingsRepository);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEnabledState(bool recommendedState)
|
||||||
|
{
|
||||||
|
var enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredLightSwitchEnabledValue();
|
||||||
|
|
||||||
|
if (enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
||||||
|
{
|
||||||
|
// Get the enabled state from GPO.
|
||||||
|
ViewModel.IsEnabledGpoConfigured = true;
|
||||||
|
ViewModel.EnabledGPOConfiguration = enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ViewModel.IsEnabled = recommendedState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void SyncLocationButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await LocationDialog.ShowAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,15 +38,12 @@
|
|||||||
Command="{x:Bind ViewModel.LaunchEventHandler}"
|
Command="{x:Bind ViewModel.LaunchEventHandler}"
|
||||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||||
IsClickEnabled="True" />
|
IsClickEnabled="True" />
|
||||||
|
|
||||||
<tkcontrols:SettingsCard x:Uid="RegistryPreview_DefaultRegApp" HeaderIcon="{ui:FontIcon Glyph=}">
|
<tkcontrols:SettingsCard x:Uid="RegistryPreview_DefaultRegApp" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||||
<ToggleSwitch x:Uid="RegistryPreview_DefaultRegApp_ToggleSwitch" IsOn="{x:Bind ViewModel.IsRegistryPreviewDefaultRegApp, Mode=TwoWay}" />
|
<ToggleSwitch x:Uid="RegistryPreview_DefaultRegApp_ToggleSwitch" IsOn="{x:Bind ViewModel.IsRegistryPreviewDefaultRegApp, Mode=TwoWay}" />
|
||||||
</tkcontrols:SettingsCard>
|
</tkcontrols:SettingsCard>
|
||||||
</controls:SettingsGroup>
|
</controls:SettingsGroup>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</controls:SettingsPageControl.ModuleContent>
|
</controls:SettingsPageControl.ModuleContent>
|
||||||
|
|
||||||
<controls:SettingsPageControl.PrimaryLinks>
|
<controls:SettingsPageControl.PrimaryLinks>
|
||||||
<controls:PageLink x:Uid="LearnMore_RegistryPreview" Link="https://aka.ms/PowerToysOverview_RegistryPreview" />
|
<controls:PageLink x:Uid="LearnMore_RegistryPreview" Link="https://aka.ms/PowerToysOverview_RegistryPreview" />
|
||||||
</controls:SettingsPageControl.PrimaryLinks>
|
</controls:SettingsPageControl.PrimaryLinks>
|
||||||
|
|||||||
@@ -152,6 +152,10 @@
|
|||||||
x:Uid="Shell_ColorPicker"
|
x:Uid="Shell_ColorPicker"
|
||||||
helpers:NavHelper.NavigateTo="views:ColorPickerPage"
|
helpers:NavHelper.NavigateTo="views:ColorPickerPage"
|
||||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ColorPicker.png}" />
|
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ColorPicker.png}" />
|
||||||
|
<NavigationViewItem
|
||||||
|
x:Uid="Shell_LightSwitch"
|
||||||
|
helpers:NavHelper.NavigateTo="views:LightSwitchPage"
|
||||||
|
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/LightSwitch.png}" />
|
||||||
<NavigationViewItem
|
<NavigationViewItem
|
||||||
x:Uid="Shell_PowerLauncher"
|
x:Uid="Shell_PowerLauncher"
|
||||||
helpers:NavHelper.NavigateTo="views:PowerLauncherPage"
|
helpers:NavHelper.NavigateTo="views:PowerLauncherPage"
|
||||||
|
|||||||
@@ -3161,6 +3161,15 @@ Activate by holding the key for the character you want to add an accent to, then
|
|||||||
<data name="AlwaysOnTop_ShortDescription" xml:space="preserve">
|
<data name="AlwaysOnTop_ShortDescription" xml:space="preserve">
|
||||||
<value>Pin a window</value>
|
<value>Pin a window</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="LightSwitch_ThemeToggle_Shortcut.Header" xml:space="preserve">
|
||||||
|
<value>Toggle theme shortcut</value>
|
||||||
|
</data>
|
||||||
|
<data name="LightSwitch_ThemeToggle_Shortcut.Description" xml:space="preserve">
|
||||||
|
<value>Toggle between light and dark mode</value>
|
||||||
|
</data>
|
||||||
|
<data name="LightSwitch_ForceDarkMode" xml:space="preserve">
|
||||||
|
<value>Force Dark Mode</value>
|
||||||
|
</data>
|
||||||
<data name="ColorPicker_ShortDescription" xml:space="preserve">
|
<data name="ColorPicker_ShortDescription" xml:space="preserve">
|
||||||
<value>Pick a color</value>
|
<value>Pick a color</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -5124,6 +5133,24 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
|||||||
<data name="GeneralPage_EnableViewDiagnosticDataText.Text" xml:space="preserve">
|
<data name="GeneralPage_EnableViewDiagnosticDataText.Text" xml:space="preserve">
|
||||||
<value>Stores diagnostic data locally in .xml format; folder may include .etl files as well. May use up 1 GB or more of disk space.</value>
|
<value>Stores diagnostic data locally in .xml format; folder may include .etl files as well. May use up 1 GB or more of disk space.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Shell_LightSwitch.Content" xml:space="preserve">
|
||||||
|
<value>LightSwitch</value>
|
||||||
|
</data>
|
||||||
|
<data name="LightSwitch_EnableToggleControl_HeaderText.Header" xml:space="preserve">
|
||||||
|
<value>Enable Light Switch</value>
|
||||||
|
</data>
|
||||||
|
<data name="LightSwitch.ModuleDescription" xml:space="preserve">
|
||||||
|
<value>This is a module that allows you to control light/dark theming via set times, sun rise, or directly invoking the change.</value>
|
||||||
|
</data>
|
||||||
|
<data name="LightSwitch.ModuleTitle" xml:space="preserve">
|
||||||
|
<value>Light Switch</value>
|
||||||
|
</data>
|
||||||
|
<data name="LearnMore_LightSwitch.Text" xml:space="preserve">
|
||||||
|
<value>Learn more about Light Switch</value>
|
||||||
|
</data>
|
||||||
|
<data name="LightSwitch_BehaviorSettingsGroup.Header" xml:space="preserve">
|
||||||
|
<value>Behavior</value>
|
||||||
|
</data>
|
||||||
<data name="KeyBack" xml:space="preserve">
|
<data name="KeyBack" xml:space="preserve">
|
||||||
<value>Back key</value>
|
<value>Back key</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ using Microsoft.PowerToys.Settings.UI.Services;
|
|||||||
using Microsoft.PowerToys.Settings.UI.Views;
|
using Microsoft.PowerToys.Settings.UI.Views;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
using Settings.UI.Library;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||||
{
|
{
|
||||||
@@ -170,6 +171,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
ModuleType.CmdPal => GetModuleItemsCmdPal(),
|
ModuleType.CmdPal => GetModuleItemsCmdPal(),
|
||||||
ModuleType.ColorPicker => GetModuleItemsColorPicker(),
|
ModuleType.ColorPicker => GetModuleItemsColorPicker(),
|
||||||
ModuleType.CropAndLock => GetModuleItemsCropAndLock(),
|
ModuleType.CropAndLock => GetModuleItemsCropAndLock(),
|
||||||
|
ModuleType.LightSwitch => GetModuleItemsLightSwitch(),
|
||||||
ModuleType.EnvironmentVariables => GetModuleItemsEnvironmentVariables(),
|
ModuleType.EnvironmentVariables => GetModuleItemsEnvironmentVariables(),
|
||||||
ModuleType.FancyZones => GetModuleItemsFancyZones(),
|
ModuleType.FancyZones => GetModuleItemsFancyZones(),
|
||||||
ModuleType.FindMyMouse => GetModuleItemsFindMyMouse(),
|
ModuleType.FindMyMouse => GetModuleItemsFindMyMouse(),
|
||||||
@@ -222,6 +224,17 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|||||||
return new ObservableCollection<DashboardModuleItem>(list);
|
return new ObservableCollection<DashboardModuleItem>(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsLightSwitch()
|
||||||
|
{
|
||||||
|
ISettingsRepository<LightSwitchSettings> moduleSettingsRepository = SettingsRepository<LightSwitchSettings>.GetInstance(new SettingsUtils());
|
||||||
|
var settings = moduleSettingsRepository.SettingsConfig;
|
||||||
|
var list = new List<DashboardModuleItem>
|
||||||
|
{
|
||||||
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("LightSwitch_ForceDarkMode"), Shortcut = settings.Properties.ForceDarkModeHotkey.Value.GetKeysList() },
|
||||||
|
};
|
||||||
|
return new ObservableCollection<DashboardModuleItem>(list);
|
||||||
|
}
|
||||||
|
|
||||||
private ObservableCollection<DashboardModuleItem> GetModuleItemsCropAndLock()
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsCropAndLock()
|
||||||
{
|
{
|
||||||
ISettingsRepository<CropAndLockSettings> moduleSettingsRepository = SettingsRepository<CropAndLockSettings>.GetInstance(new SettingsUtils());
|
ISettingsRepository<CropAndLockSettings> moduleSettingsRepository = SettingsRepository<CropAndLockSettings>.GetInstance(new SettingsUtils());
|
||||||
|
|||||||
428
src/settings-ui/Settings.UI/ViewModels/LightSwitchViewModel.cs
Normal file
428
src/settings-ui/Settings.UI/ViewModels/LightSwitchViewModel.cs
Normal file
@@ -0,0 +1,428 @@
|
|||||||
|
// 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 System.Collections.ObjectModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using ManagedCommon;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.SerializationContext;
|
||||||
|
using Settings.UI.Library;
|
||||||
|
using Settings.UI.Library.Helpers;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||||
|
{
|
||||||
|
public partial class LightSwitchViewModel : Observable
|
||||||
|
{
|
||||||
|
private Func<string, int> SendConfigMSG { get; }
|
||||||
|
|
||||||
|
public ObservableCollection<City> Cities { get; } = new();
|
||||||
|
|
||||||
|
public LightSwitchViewModel(LightSwitchSettings initialSettings = null, Func<string, int> ipcMSGCallBackFunc = null)
|
||||||
|
{
|
||||||
|
_moduleSettings = initialSettings ?? new LightSwitchSettings();
|
||||||
|
SendConfigMSG = ipcMSGCallBackFunc;
|
||||||
|
|
||||||
|
ForceLightCommand = new RelayCommand(ForceLightNow);
|
||||||
|
ForceDarkCommand = new RelayCommand(ForceDarkNow);
|
||||||
|
|
||||||
|
// populate the list of modes for dropdown binding
|
||||||
|
AvailableScheduleModes = new ObservableCollection<string>
|
||||||
|
{
|
||||||
|
"FixedHours",
|
||||||
|
"SunsetToSunriseGeo",
|
||||||
|
"SunsetToSunriseUser",
|
||||||
|
};
|
||||||
|
|
||||||
|
_forceLightModeHotkey = _moduleSettings.Properties.ForceLightModeHotkey.Value;
|
||||||
|
_forceDarkModeHotkey = _moduleSettings.Properties.ForceDarkModeHotkey.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ForceLightNow()
|
||||||
|
{
|
||||||
|
Logger.LogInfo("Sending custom action: forceLight");
|
||||||
|
SendCustomAction("forceLight");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ForceDarkNow()
|
||||||
|
{
|
||||||
|
Logger.LogInfo("Sending custom action: forceDark");
|
||||||
|
SendCustomAction("forceDark");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendCustomAction(string actionName)
|
||||||
|
{
|
||||||
|
SendConfigMSG("{\"action\":{\"LightSwitch\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public LightSwitchSettings ModuleSettings
|
||||||
|
{
|
||||||
|
get => _moduleSettings;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_moduleSettings != value)
|
||||||
|
{
|
||||||
|
_moduleSettings = value;
|
||||||
|
|
||||||
|
OnPropertyChanged(nameof(ModuleSettings));
|
||||||
|
RefreshModuleSettings();
|
||||||
|
RefreshEnabledState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_enabledStateIsGPOConfigured)
|
||||||
|
{
|
||||||
|
return _enabledGPOConfiguration;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _isEnabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_isEnabled != value)
|
||||||
|
{
|
||||||
|
if (_enabledStateIsGPOConfigured)
|
||||||
|
{
|
||||||
|
// If it's GPO configured, shouldn't be able to change this state.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isEnabled = value;
|
||||||
|
|
||||||
|
RefreshEnabledState();
|
||||||
|
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabledGpoConfigured
|
||||||
|
{
|
||||||
|
get => _enabledStateIsGPOConfigured;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_enabledStateIsGPOConfigured != value)
|
||||||
|
{
|
||||||
|
_enabledStateIsGPOConfigured = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnabledGPOConfiguration
|
||||||
|
{
|
||||||
|
get => _enabledGPOConfiguration;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_enabledGPOConfiguration != value)
|
||||||
|
{
|
||||||
|
_enabledGPOConfiguration = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ScheduleMode
|
||||||
|
{
|
||||||
|
get => ModuleSettings.Properties.ScheduleMode.Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (ModuleSettings.Properties.ScheduleMode.Value != value)
|
||||||
|
{
|
||||||
|
ModuleSettings.Properties.ScheduleMode.Value = value;
|
||||||
|
OnPropertyChanged(nameof(ScheduleMode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// available values for the dropdown
|
||||||
|
public ObservableCollection<string> AvailableScheduleModes { get; }
|
||||||
|
|
||||||
|
public bool ChangeSystem
|
||||||
|
{
|
||||||
|
get => ModuleSettings.Properties.ChangeSystem.Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (ModuleSettings.Properties.ChangeSystem.Value != value)
|
||||||
|
{
|
||||||
|
ModuleSettings.Properties.ChangeSystem.Value = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ChangeApps
|
||||||
|
{
|
||||||
|
get => ModuleSettings.Properties.ChangeApps.Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (ModuleSettings.Properties.ChangeApps.Value != value)
|
||||||
|
{
|
||||||
|
ModuleSettings.Properties.ChangeApps.Value = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int LightTime
|
||||||
|
{
|
||||||
|
get => ModuleSettings.Properties.LightTime.Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (ModuleSettings.Properties.LightTime.Value != value)
|
||||||
|
{
|
||||||
|
ModuleSettings.Properties.LightTime.Value = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int DarkTime
|
||||||
|
{
|
||||||
|
get => ModuleSettings.Properties.DarkTime.Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (ModuleSettings.Properties.DarkTime.Value != value)
|
||||||
|
{
|
||||||
|
ModuleSettings.Properties.DarkTime.Value = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Offset
|
||||||
|
{
|
||||||
|
get => ModuleSettings.Properties.Offset.Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (ModuleSettings.Properties.Offset.Value != value)
|
||||||
|
{
|
||||||
|
ModuleSettings.Properties.Offset.Value = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeSpan LightTimeTimeSpan
|
||||||
|
{
|
||||||
|
get => TimeSpan.FromMinutes(LightTime);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
int minutes = (int)value.TotalMinutes;
|
||||||
|
if (LightTime != minutes)
|
||||||
|
{
|
||||||
|
LightTime = minutes;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
OnPropertyChanged(nameof(LightTimeTimeSpan));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeSpan DarkTimeTimeSpan
|
||||||
|
{
|
||||||
|
get => TimeSpan.FromMinutes(DarkTime);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
int minutes = (int)value.TotalMinutes;
|
||||||
|
if (DarkTime != minutes)
|
||||||
|
{
|
||||||
|
DarkTime = minutes;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
OnPropertyChanged(nameof(DarkTimeTimeSpan));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Latitude
|
||||||
|
{
|
||||||
|
get => ModuleSettings.Properties.Latitude.Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (ModuleSettings.Properties.Latitude.Value != value)
|
||||||
|
{
|
||||||
|
ModuleSettings.Properties.Latitude.Value = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Longitude
|
||||||
|
{
|
||||||
|
get => ModuleSettings.Properties.Longitude.Value;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (ModuleSettings.Properties.Longitude.Value != value)
|
||||||
|
{
|
||||||
|
ModuleSettings.Properties.Longitude.Value = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private City _selectedCity;
|
||||||
|
|
||||||
|
public City SelectedCity
|
||||||
|
{
|
||||||
|
get => _selectedCity;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_selectedCity != value)
|
||||||
|
{
|
||||||
|
_selectedCity = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
|
||||||
|
UpdateSunTimesForSelectedCity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _cityTimesText = "Please select a city";
|
||||||
|
|
||||||
|
public string CityTimesText
|
||||||
|
{
|
||||||
|
get => _cityTimesText;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_cityTimesText != value)
|
||||||
|
{
|
||||||
|
_cityTimesText = value;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotkeySettings ForceLightModeActivationShortcut
|
||||||
|
{
|
||||||
|
get => _forceLightModeHotkey;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _forceLightModeHotkey)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
_forceLightModeHotkey = LightSwitchProperties.DefaultForceLightModeValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_forceLightModeHotkey = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
_moduleSettings.Properties.ForceLightModeHotkey.Value = _forceLightModeHotkey;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
|
||||||
|
// Using InvariantCulture as this is an IPC message
|
||||||
|
SendConfigMSG(
|
||||||
|
string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"{{ \"powertoys\": {{ \"{0}\": {1} }} }}",
|
||||||
|
LightSwitchSettings.ModuleName,
|
||||||
|
JsonSerializer.Serialize(_moduleSettings, (System.Text.Json.Serialization.Metadata.JsonTypeInfo<LightSwitchSettings>)SourceGenerationContextContext.Default.LightSwitchSettings)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotkeySettings ForceDarkModeActivationShortcut
|
||||||
|
{
|
||||||
|
get => _forceDarkModeHotkey;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _forceDarkModeHotkey)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
_forceDarkModeHotkey = LightSwitchProperties.DefaultForceDarkModeValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_forceDarkModeHotkey = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
_moduleSettings.Properties.ForceDarkModeHotkey.Value = _forceDarkModeHotkey;
|
||||||
|
NotifyPropertyChanged();
|
||||||
|
|
||||||
|
// Using InvariantCulture as this is an IPC message
|
||||||
|
SendConfigMSG(
|
||||||
|
string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"{{ \"powertoys\": {{ \"{0}\": {1} }} }}",
|
||||||
|
LightSwitchSettings.ModuleName,
|
||||||
|
JsonSerializer.Serialize(_moduleSettings, (System.Text.Json.Serialization.Metadata.JsonTypeInfo<LightSwitchSettings>)SourceGenerationContextContext.Default.LightSwitchSettings)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
Logger.LogInfo($"Changed the property {propertyName}");
|
||||||
|
OnPropertyChanged(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshEnabledState()
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(IsEnabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshModuleSettings()
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(ChangeSystem));
|
||||||
|
OnPropertyChanged(nameof(ChangeApps));
|
||||||
|
OnPropertyChanged(nameof(LightTime));
|
||||||
|
OnPropertyChanged(nameof(DarkTime));
|
||||||
|
OnPropertyChanged(nameof(Offset));
|
||||||
|
OnPropertyChanged(nameof(Latitude));
|
||||||
|
OnPropertyChanged(nameof(Longitude));
|
||||||
|
OnPropertyChanged(nameof(ScheduleMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateSunTimesForSelectedCity()
|
||||||
|
{
|
||||||
|
if (SelectedCity == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SunTimes result = SunCalc.CalculateSunriseSunset(
|
||||||
|
SelectedCity.Latitude,
|
||||||
|
SelectedCity.Longitude,
|
||||||
|
DateTime.Now.Year,
|
||||||
|
DateTime.Now.Month,
|
||||||
|
DateTime.Now.Day);
|
||||||
|
|
||||||
|
LightTime = (result.SunriseHour * 60) + result.SunriseMinute;
|
||||||
|
DarkTime = (result.SunsetHour * 60) + result.SunsetMinute;
|
||||||
|
Latitude = SelectedCity.Latitude.ToString(CultureInfo.InvariantCulture);
|
||||||
|
Longitude = SelectedCity.Longitude.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
// If you want a ready-to-bind string
|
||||||
|
CityTimesText = $"Sunrise: {result.SunriseHour}:{result.SunriseMinute:D2} " +
|
||||||
|
$"Sunset: {result.SunsetHour}:{result.SunsetMinute:D2}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _enabledStateIsGPOConfigured;
|
||||||
|
private bool _enabledGPOConfiguration;
|
||||||
|
private LightSwitchSettings _moduleSettings;
|
||||||
|
private bool _isEnabled;
|
||||||
|
private HotkeySettings _forceLightModeHotkey;
|
||||||
|
private HotkeySettings _forceDarkModeHotkey;
|
||||||
|
|
||||||
|
public ICommand ForceLightCommand { get; }
|
||||||
|
|
||||||
|
public ICommand ForceDarkCommand { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user