Compare commits

...

31 Commits

Author SHA1 Message Date
Stefan Markovic
cfdd99b9b0 [Hosts] Re-add AppList to Lib Assets, [RegPrev] Copy lib assets to out dir 2024-04-19 22:15:53 +02:00
Darshak Bhatti
25600f3934 assets 2024-04-18 17:00:24 -07:00
Darshak Bhatti
e76205adb1 v0 2024-04-18 14:28:15 -07:00
Darshak Bhatti
3def0e4a42 nuget struct 2024-04-17 21:50:26 -07:00
Stefan Markovic
007177145d Assets cleanup 2024-04-17 11:54:06 +02:00
Stefan Markovic
5dcb564f01 Rename HostsPackageConsumer to Hosts and Hosts lib to HostsUILib 2024-04-17 11:13:35 +02:00
Stefan Markovic
62154ecf03 nuget 2024-04-17 09:18:34 +02:00
Stefan Markovic
9fc1f7a48c GPO 2024-04-16 22:50:53 +02:00
Stefan Markovic
16cb1b432c Telemetry 2024-04-16 22:50:02 +02:00
Stefan Markovic
9de67796e4 Add app and consume 2024-04-16 22:10:58 +02:00
Stefan Markovic
8fd97bead2 Rename to EnvironmentVariablesUILib and convert to lib 2024-04-16 21:02:02 +02:00
Stefan Markovic
ca4ee2bced Ship icons and assets in nuget packages 2024-04-15 15:25:14 +02:00
Stefan Markovic
f352cf0ead Back to consuming lib 2024-04-12 11:35:43 +02:00
Stefan Markovic
7b51a0eca2 Rename RegistryPreviewUI back to RegistryPreview 2024-04-12 11:35:22 +02:00
Stefan Markovic
4e028510b7 Fix RegistryPreview package creation 2024-04-12 10:52:05 +02:00
Stefan Markovic
d0b1247ed1 Update Hosts package creation 2024-04-12 10:41:14 +02:00
Stefan Markovic
ddf22c106f Consume the lib 2024-04-09 12:24:11 +02:00
Stefan Markovic
0a9e1ce68d Add exe app and move App.xaml and MainWindow.xaml 2024-04-09 12:13:56 +02:00
Stefan Markovic
071ecc5928 Convert to lib
Change namespace to RegistryPreviewUILib
Remove PT deps
2024-04-09 10:41:10 +02:00
Stefan Markovic
bfcc0b002b Extract UI and logic from MainWindow to RegistryPreviewMainPage 2024-04-09 10:26:29 +02:00
Stefan Markovic
f1c78b0c0d Fix build again 2024-03-22 16:52:35 +01:00
Stefan Markovic
126e3f9239 Remove unneeded stuff 2024-03-22 16:40:37 +01:00
Stefan Markovic
7793a19151 Fix installer 2024-03-22 16:22:40 +01:00
Stefan Markovic
b6e79b7f93 Merge remote-tracking branch 'origin/main' into stefan/decouple_wip 2024-03-22 12:37:47 +01:00
Stefan Markovic
a6525a9c46 Dependency injection
Refactor
Explicit page creation
Wire missing dependencies
2024-03-22 12:37:42 +01:00
Stefan Markovic
1aea2a789a Make it work with custom build targets 2024-03-19 17:46:29 +01:00
Stefan Markovic
0835b96b07 Fix errors 2024-03-13 13:33:46 +01:00
Stefan Markovic
11faa7702d Try consume it 2024-03-12 17:24:55 +01:00
Stefan Markovic
a631518680 Move App and MainWindow to Consumer app. Make Hosts dll 2024-03-12 14:29:43 +01:00
Stefan Markovic
fada064917 Add consumer app 2024-03-12 14:06:15 +01:00
Stefan Markovic
2a6d3b2094 WIP Hosts - remove deps 2024-03-12 13:21:38 +01:00
125 changed files with 2493 additions and 1965 deletions

View File

@@ -95,6 +95,7 @@
"PowerToys.SvgThumbnailProviderCpp.dll",
"WinUI3Apps\\PowerToys.HostsModuleInterface.dll",
"WinUI3Apps\\PowerToys.HostsUILib.dll",
"WinUI3Apps\\PowerToys.Hosts.dll",
"WinUI3Apps\\PowerToys.Hosts.exe",

View File

@@ -4,6 +4,7 @@
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Appium.WebDriver" Version="4.2.1" />
<PackageVersion Include="CommunityToolkit.Common" Version="8.2.2" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageVersion Include="CommunityToolkit.WinUI.Animations" Version="8.0.240109" />
<PackageVersion Include="CommunityToolkit.WinUI.Collections" Version="8.0.240109" />
@@ -57,6 +58,8 @@
<PackageVersion Include="NLog" Version="5.0.4" />
<PackageVersion Include="NLog.Extensions.Logging" Version="5.3.8" />
<PackageVersion Include="NLog.Schema" Version="5.2.8" />
<PackageVersion Include="PowerToys.Hosts" Version="0.0.1" />
<PackageVersion Include="PowerToys.RegistryPreviewUILib" Version="0.0.1" />
<PackageVersion Include="ScipBe.Common.Office.OneNote" Version="3.0.1" />
<PackageVersion Include="SharpCompress" Version="0.33.0" />
<PackageVersion Include="StreamJsonRpc" Version="2.14.24" />
@@ -89,7 +92,7 @@
<PackageVersion Include="UTF.Unknown" Version="2.5.1" />
<PackageVersion Include="Vanara.PInvoke.User32" Version="3.4.11" />
<PackageVersion Include="Vanara.PInvoke.Shell32" Version="3.4.11" />
<PackageVersion Include="WinUIEx" Version="2.2.0" />
<PackageVersion Include="WinUIEx" Version="2.3.4" />
<PackageVersion Include="WPF-UI" Version="3.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(IsExperimentationLive)'!=''">

View File

@@ -448,7 +448,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MeasureToolUI", "src\module
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerAccentKeyboardService", "src\modules\poweraccent\PowerAccentKeyboardService\PowerAccentKeyboardService.vcxproj", "{C97D9A5D-206C-454E-997E-009E227D7F02}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hosts", "src\modules\Hosts\Hosts\Hosts.csproj", "{31D1C81D-765F-4446-AA62-E743F6325049}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostsUILib", "src\modules\Hosts\HostsUILib\HostsUILib.csproj", "{31D1C81D-765F-4446-AA62-E743F6325049}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hosts", "Hosts", "{F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}"
EndProject
@@ -518,7 +518,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PastePlainModuleInterface",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AllExperiments", "src\common\AllExperiments\AllExperiments.csproj", "{9CE59ED5-7087-4353-88EB-788038A73CEC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RegistryPreviewUI", "src\modules\registrypreview\RegistryPreviewUI\RegistryPreviewUI.csproj", "{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RegistryPreviewUILib", "src\modules\registrypreview\RegistryPreviewUILib\RegistryPreviewUILib.csproj", "{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RegistryPreviewExt", "src\modules\registrypreview\RegistryPreviewExt\RegistryPreviewExt.vcxproj", "{697C6AF9-0A48-49A9-866C-67DA12384015}"
EndProject
@@ -546,7 +546,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-FancyZonesEditor"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EnvironmentVariables", "EnvironmentVariables", "{538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvironmentVariables", "src\modules\EnvironmentVariables\EnvironmentVariables\EnvironmentVariables.csproj", "{51465DA1-C18B-4B99-93E1-ECF8E0FA0CBA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvironmentVariablesUILib", "src\modules\EnvironmentVariables\EnvironmentVariablesUILib\EnvironmentVariablesUILib.csproj", "{51465DA1-C18B-4B99-93E1-ECF8E0FA0CBA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EnvironmentVariablesModuleInterface", "src\modules\EnvironmentVariables\EnvironmentVariablesModuleInterface\EnvironmentVariablesModuleInterface.vcxproj", "{B9420661-B0E4-4241-ABD4-4A27A1F64250}"
EndProject
@@ -568,6 +568,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileLocksmithContextMenu",
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileLocksmithLib", "src\modules\FileLocksmith\FileLocksmithLib\FileLocksmithLib.vcxproj", "{9D52FD25-EF90-4F9A-A015-91EFC5DAF54F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hosts", "src\modules\Hosts\Hosts\Hosts.csproj", "{02DD46D3-F761-47D9-8894-2D6DA0124650}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RegistryPreview", "src\modules\registrypreview\RegistryPreview\RegistryPreview.csproj", "{8E23E173-7127-4A5F-9F93-3049F2B68047}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvironmentVariables", "src\modules\EnvironmentVariables\EnvironmentVariables\EnvironmentVariables.csproj", "{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -2494,6 +2500,42 @@ Global
{9D52FD25-EF90-4F9A-A015-91EFC5DAF54F}.Release|x64.Build.0 = Release|x64
{9D52FD25-EF90-4F9A-A015-91EFC5DAF54F}.Release|x86.ActiveCfg = Release|x64
{9D52FD25-EF90-4F9A-A015-91EFC5DAF54F}.Release|x86.Build.0 = Release|x64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Debug|ARM64.ActiveCfg = Debug|ARM64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Debug|ARM64.Build.0 = Debug|ARM64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Debug|x64.ActiveCfg = Debug|x64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Debug|x64.Build.0 = Debug|x64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Debug|x86.ActiveCfg = Debug|x64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Debug|x86.Build.0 = Debug|x64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Release|ARM64.ActiveCfg = Release|ARM64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Release|ARM64.Build.0 = Release|ARM64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Release|x64.ActiveCfg = Release|x64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Release|x64.Build.0 = Release|x64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Release|x86.ActiveCfg = Release|x64
{02DD46D3-F761-47D9-8894-2D6DA0124650}.Release|x86.Build.0 = Release|x64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Debug|ARM64.Build.0 = Debug|ARM64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Debug|x64.ActiveCfg = Debug|x64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Debug|x64.Build.0 = Debug|x64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Debug|x86.ActiveCfg = Debug|x64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Debug|x86.Build.0 = Debug|x64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Release|ARM64.ActiveCfg = Release|ARM64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Release|ARM64.Build.0 = Release|ARM64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Release|x64.ActiveCfg = Release|x64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Release|x64.Build.0 = Release|x64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Release|x86.ActiveCfg = Release|x64
{8E23E173-7127-4A5F-9F93-3049F2B68047}.Release|x86.Build.0 = Release|x64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Debug|ARM64.ActiveCfg = Debug|ARM64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Debug|ARM64.Build.0 = Debug|ARM64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Debug|x64.ActiveCfg = Debug|x64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Debug|x64.Build.0 = Debug|x64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Debug|x86.ActiveCfg = Debug|x64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Debug|x86.Build.0 = Debug|x64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Release|ARM64.ActiveCfg = Release|ARM64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Release|ARM64.Build.0 = Release|ARM64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Release|x64.ActiveCfg = Release|x64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Release|x64.Build.0 = Release|x64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Release|x86.ActiveCfg = Release|x64
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8}.Release|x86.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2703,6 +2745,9 @@ Global
{0014D652-901F-4456-8D65-06FC5F997FB0} = {4C0D0746-BE5B-49EE-BD5D-A7811628AE8B}
{799A50D8-DE89-4ED1-8FF8-AD5A9ED8C0CA} = {AB82E5DD-C32D-4F28-9746-2C780846188E}
{9D52FD25-EF90-4F9A-A015-91EFC5DAF54F} = {AB82E5DD-C32D-4F28-9746-2C780846188E}
{02DD46D3-F761-47D9-8894-2D6DA0124650} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
{8E23E173-7127-4A5F-9F93-3049F2B68047} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
{DFF88D16-D36F-40A4-A955-CDCAA76EF7B8} = {538ED0BB-B863-4B20-98CC-BCDF7FA0B68A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />

View File

@@ -262,7 +262,7 @@ inline registry::ChangeSet getRegistryPreviewChangeSet(const std::wstring instal
changes.push_back({ scope, L"Software\\Classes\\regfile\\shell\\preview\\command", std::nullopt, command });
std::wstring icon_path = installationDir;
icon_path.append(L"\\WinUI3Apps\\Assets\\RegistryPreview\\app.ico");
icon_path.append(L"\\WinUI3Apps\\Assets\\RegistryPreview\\RegistryPreview.ico");
changes.push_back({ scope, L"Software\\Classes\\regfile\\shell\\preview", L"icon", icon_path });
return { changes };

View File

@@ -1,6 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
@@ -8,6 +6,7 @@
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<RootNamespace>EnvironmentVariables</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;ARM64</Platforms>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
@@ -16,21 +15,36 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<SelfContained>true</SelfContained>
<DefineConstants>DISABLE_XAML_GENERATED_MAIN,TRACE</DefineConstants>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
<AssemblyName>PowerToys.EnvironmentVariables</AssemblyName>
<DefineConstants>DISABLE_XAML_GENERATED_MAIN,TRACE</DefineConstants>
<ApplicationIcon>Assets/EnvironmentVariables/EnvironmentVariables.ico</ApplicationIcon>
<SelfContained>true</SelfContained>
<ApplicationIcon>Assets\EnvironmentVariables\EnvironmentVariables.ico</ApplicationIcon>
<!-- 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.EnvironmentVariables.pri</ProjectPriFileName>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Styles\**" />
<EmbeddedResource Remove="Styles\**" />
<None Remove="Styles\**" />
<Page Remove="Styles\**" />
<Page Remove="EnvironmentVariablesXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="EnvironmentVariablesXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<Folder Include="EnvironmentVariablesXAML\" />
</ItemGroup>
<Target Name="CopyPRIFileToOutputDir" AfterTargets="Build">
<Message Text="Executing CopyPRIFileToOutputDir task" Importance="High" />
<ItemGroup>
<PRIFile Include="$(OutDir)**\PowerToys.EnvironmentVariablesUILib.pri" />
</ItemGroup>
<Copy SourceFiles="@(PRIFile)" DestinationFolder="$(OutDir)" />
<Message Text="Copied CopyPRIFileToOutputDir files" Importance="High" />
</Target>
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
@@ -48,24 +62,9 @@
</PropertyGroup>
<ItemGroup>
<None Remove="EnvironmentVariablesXAML\Views\MainPage.xaml" />
</ItemGroup>
<ItemGroup>
<Page Remove="EnvironmentVariablesXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="EnvironmentVariablesXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\EnvironmentVariables\SplashScreen.scale-200.png" />
<Content Include="Assets\EnvironmentVariables\LockScreenLogo.scale-200.png" />
<Content Include="Assets\EnvironmentVariables\Square150x150Logo.scale-200.png" />
<Content Include="Assets\EnvironmentVariables\Square44x44Logo.scale-200.png" />
<Content Include="Assets\EnvironmentVariables\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\EnvironmentVariables\StoreLogo.png" />
<Content Include="Assets\EnvironmentVariables\Wide310x150Logo.scale-200.png" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\EnvironmentVariablesUILib\EnvironmentVariablesUILib.csproj" />
</ItemGroup>
<ItemGroup>
@@ -73,23 +72,10 @@
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Sizers" />
<PackageReference Include="WinUIEx" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<ItemGroup>
<!-- HACK: Common.UI is referenced, even if it is not used, to force dll versions to be the same as in other projects that use it. It's still unclear why this is the case, but this is need for flattening the install directory. -->
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
</ItemGroup>
<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
@@ -98,12 +84,13 @@
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<ItemGroup>
<Page Update="EnvironmentVariablesXAML\Views\MainPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<PRIResource Remove="Styles\**" />
</ItemGroup>
<!--
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
Explorer "Package and Publish" context menu entry to be enabled for this project even if
the Windows App SDK Nuget package has not yet been restored.
-->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
</Project>

View File

@@ -1,167 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<Application
x:Class="EnvironmentVariables.App"
<Application x:Class="EnvironmentVariables.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:EnvironmentVariables">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/EnvironmentVariablesXAML/Styles/TextBlock.xaml" />
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<Style x:Key="SubtleButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter
x:Name="ContentPresenter"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AnimatedIcon.State="Normal"
AutomationProperties.AccessibilityView="Raw"
Background="{TemplateBinding Background}"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
CornerRadius="{TemplateBinding CornerRadius}"
Foreground="{TemplateBinding Foreground}">
<ContentPresenter.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</ContentPresenter.BackgroundTransition>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -4,8 +4,11 @@
using System;
using System.IO.Abstractions;
using EnvironmentVariables.Helpers;
using EnvironmentVariables.ViewModels;
using EnvironmentVariables.Telemetry;
using EnvironmentVariablesUILib;
using EnvironmentVariablesUILib.Helpers;
using EnvironmentVariablesUILib.Telemetry;
using EnvironmentVariablesUILib.ViewModels;
using ManagedCommon;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -47,8 +50,11 @@ namespace EnvironmentVariables
services.AddSingleton<IFileSystem, FileSystem>();
services.AddSingleton<IElevationHelper, ElevationHelper>();
services.AddSingleton<IEnvironmentVariablesService, EnvironmentVariablesService>();
services.AddSingleton<ILogger, LoggerWrapper>();
services.AddSingleton<ITelemetry, TelemetryWrapper>();
services.AddSingleton<MainViewModel>();
services.AddSingleton<EnvironmentVariablesMainPage>();
}).Build();
UnhandledException += App_UnhandledException;
@@ -85,8 +91,7 @@ namespace EnvironmentVariables
Logger.LogInfo($"EnvironmentVariables started detached from PowerToys Runner.");
}
PowerToysTelemetry.Log.WriteEvent(new EnvironmentVariables.Telemetry.EnvironmentVariablesOpenedEvent());
PowerToysTelemetry.Log.WriteEvent(new Telemetry.EnvironmentVariablesOpenedEvent());
window = new MainWindow();
window.Activate();
}

View File

@@ -6,7 +6,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:EnvironmentVariables"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:EnvironmentVariables.Views"
xmlns:winuiex="using:WinUIEx"
x:Uid="Window"
MinWidth="700"
@@ -15,7 +14,7 @@
<Window.SystemBackdrop>
<MicaBackdrop />
</Window.SystemBackdrop>
<Grid>
<Grid x:Name="MainGrid" Loaded="Grid_Loaded">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
@@ -42,6 +41,5 @@
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}" />
</Grid>
<views:MainPage Grid.Row="1" />
</Grid>
</winuiex:WindowEx>

View File

@@ -4,11 +4,14 @@
using System;
using System.Runtime.InteropServices;
using EnvironmentVariables.Helpers;
using EnvironmentVariables.Helpers.Win32;
using EnvironmentVariables.ViewModels;
using EnvironmentVariables.Win32;
using EnvironmentVariablesUILib;
using EnvironmentVariablesUILib.Helpers;
using EnvironmentVariablesUILib.ViewModels;
using ManagedCommon;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using WinUIEx;
namespace EnvironmentVariables
@@ -18,6 +21,8 @@ namespace EnvironmentVariables
/// </summary>
public sealed partial class MainWindow : WindowEx
{
private EnvironmentVariablesMainPage MainPage { get; }
public MainWindow()
{
this.InitializeComponent();
@@ -35,6 +40,14 @@ namespace EnvironmentVariables
RegisterWindow(handle);
WindowHelpers.BringToForeground(handle);
MainPage = App.GetService<EnvironmentVariablesMainPage>();
}
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
MainGrid.Children.Add(MainPage);
Grid.SetRow(MainPage, 1);
}
private static readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
@@ -61,7 +74,7 @@ namespace EnvironmentVariables
if (wParam != (IntPtr)0x12345)
{
var viewModel = App.GetService<MainViewModel>();
viewModel.EnvironmentState = Models.EnvironmentState.EnvironmentMessageReceived;
viewModel.EnvironmentState = EnvironmentVariablesUILib.Models.EnvironmentState.EnvironmentMessageReceived;
}
}

View File

@@ -1,8 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="SecondaryTextFontSize">12</x:Double>
<Style x:Key="SecondaryTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource SecondaryTextFontSize}" />
<Setter Property="Foreground" Value="{ThemeResource TextFillColorSecondaryBrush}" />
</Style>
</ResourceDictionary>

View File

@@ -1,760 +0,0 @@
<Page
x:Class="EnvironmentVariables.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:EnvironmentVariables.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:EnvironmentVariables.Models"
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
xmlns:ui="using:CommunityToolkit.WinUI"
x:Name="RootPage"
mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<!-- These resource dictionaries are needed to reference styles part of SettingsControls -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.SettingsControls/SettingsCard/SettingsCard.xaml" />
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.SettingsControls/SettingsExpander/SettingsExpander.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="VariableTemplate" x:DataType="models:Variable">
<tkcontrols:SettingsCard
CommandParameter="{x:Bind (models:Variable)}"
IsActionIconVisible="False"
IsClickEnabled="False"
Style="{StaticResource DefaultSettingsExpanderItemStyle}">
<tkcontrols:SettingsCard.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Name, Mode=TwoWay}" />
<FontIcon
Margin="6,0,6,0"
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xE930;"
Visibility="{x:Bind IsAppliedFromProfile, Converter={StaticResource BoolToVisibilityConverter}}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="VariableIsAppliedByActiveProfileTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</FontIcon>
</StackPanel>
</tkcontrols:SettingsCard.Header>
<tkcontrols:SettingsCard.Description>
<StackPanel HorizontalAlignment="Left">
<ItemsControl
x:Name="VariableValuesList"
HorizontalAlignment="Left"
ItemsSource="{x:Bind ValuesList, Mode=TwoWay}"
Visibility="{x:Bind ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock
Margin="0,2,0,2"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
IsTextSelectionEnabled="True"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding Text}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock
IsTextSelectionEnabled="True"
Text="{x:Bind Values, Mode=TwoWay}"
Visibility="{x:Bind ShowAsList, Converter={StaticResource BoolToInvertedVisibilityConverter}}" />
</StackPanel>
</tkcontrols:SettingsCard.Description>
<Button
Content="{ui:FontIcon Glyph=&#xE712;}"
IsEnabled="{x:Bind IsEditable}"
Style="{StaticResource SubtleButtonStyle}">
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem
x:Uid="EditItem"
Click="EditVariable_Click"
CommandParameter="{x:Bind (models:Variable)}"
Icon="{ui:FontIcon Glyph=&#xE70F;}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem
x:Uid="RemoveItem"
Click="Delete_Variable_Click"
CommandParameter="{x:Bind (models:Variable)}"
Icon="{ui:FontIcon Glyph=&#xE74D;}" />
</MenuFlyout>
</Button.Flyout>
<ToolTipService.ToolTip>
<TextBlock x:Uid="More_Options_ButtonTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</Button>
</tkcontrols:SettingsCard>
</DataTemplate>
<converters:VariableTypeToGlyphConverter x:Key="VariableTypeToGlyphConverter" />
<converters:EnvironmentStateToBoolConverter x:Key="EnvironmentStateToBoolConverter" />
<converters:EnvironmentStateToMessageConverter x:Key="EnvironmentStateToMessageConverter" />
<converters:EnvironmentStateToTitleConverter x:Key="EnvironmentStateToTitleConverter" />
<converters:EnvironmentStateToVisibilityConverter x:Key="EnvironmentStateToVisibilityConverter" />
<tkconverters:BoolToVisibilityConverter
x:Key="BoolToInvertedVisibilityConverter"
FalseValue="Visible"
TrueValue="Collapsed" />
<tkconverters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<tkconverters:BoolNegationConverter x:Key="BoolNegationConverter" />
</ResourceDictionary>
</Page.Resources>
<i:Interaction.Behaviors>
<ic:EventTriggerBehavior EventName="Loaded">
<ic:InvokeCommandAction Command="{x:Bind ViewModel.LoadEnvironmentVariablesCommand}" />
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
<Grid Margin="16" RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<!-- buttons -->
<RowDefinition Height="Auto" />
<!-- Warning messages -->
<RowDefinition Height="*" />
<!-- content -->
<RowDefinition Height="Auto" />
<!-- content -->
</Grid.RowDefinitions>
<!-- buttons -->
<StackPanel Orientation="Horizontal">
<Button Command="{x:Bind NewProfileCommand}">
<StackPanel Orientation="Horizontal" Spacing="8">
<FontIcon
x:Name="Icon"
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xe710;" />
<TextBlock x:Uid="NewProfileBtn" />
</StackPanel>
<Button.KeyboardAccelerators>
<KeyboardAccelerator Key="N" Modifiers="Control" />
</Button.KeyboardAccelerators>
</Button>
</StackPanel>
<Grid Grid.Row="1">
<InfoBar
x:Name="InvalidStateInfoBar"
x:Uid="InvalidStateInfoBar"
Title="{x:Bind ViewModel.EnvironmentState, Mode=OneWay, Converter={StaticResource EnvironmentStateToTitleConverter}}"
CloseButtonClick="InvalidStateInfoBar_CloseButtonClick"
IsOpen="{x:Bind ViewModel.EnvironmentState, Mode=OneWay, Converter={StaticResource EnvironmentStateToBoolConverter}}"
Message="{x:Bind ViewModel.EnvironmentState, Mode=OneWay, Converter={StaticResource EnvironmentStateToMessageConverter}}"
Severity="Warning"
Visibility="{x:Bind ViewModel.EnvironmentState, Mode=OneWay, Converter={StaticResource EnvironmentStateToVisibilityConverter}}">
<InfoBar.ActionButton>
<Button
Click="ReloadButton_Click"
Content="{ui:FontIcon Glyph=&#xe72c;}"
Style="{StaticResource SubtleButtonStyle}"
Visibility="{x:Bind ViewModel.IsInfoBarButtonVisible, Mode=OneWay}" />
</InfoBar.ActionButton>
</InfoBar>
</Grid>
<Grid
Grid.Row="2"
Margin="0,24,0,0"
ColumnSpacing="12">
<Grid.ColumnDefinitions>
<!-- Left side -->
<ColumnDefinition Width="*" />
<!-- GridSplitter -->
<ColumnDefinition Width="Auto" />
<!-- Applied values -->
<ColumnDefinition Width="480" />
</Grid.ColumnDefinitions>
<ScrollViewer
Grid.Row="1"
Grid.Column="0"
VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="4">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock x:Uid="ProfilesLbl" Style="{StaticResource BodyStrongTextBlockStyle}" />
<FontIcon
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xE946;">
<ToolTipService.ToolTip>
<TextBlock x:Uid="ProfilesDescriptionLbl" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</FontIcon>
</StackPanel>
<ItemsControl Margin="0,4,0,0" ItemsSource="{x:Bind ViewModel.Profiles, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:ProfileVariablesSet">
<tkcontrols:SettingsExpander
Margin="0,0,0,4"
Header="{x:Bind Name, Mode=TwoWay}"
HeaderIcon="{ui:FontIcon Glyph=&#xEDE3;}">
<tkcontrols:SettingsExpander.ItemsHeader>
<ItemsRepeater
ItemTemplate="{StaticResource VariableTemplate}"
ItemsSource="{x:Bind Variables, Mode=OneWay}"
TabFocusNavigation="Local"
VerticalCacheLength="10" />
</tkcontrols:SettingsExpander.ItemsHeader>
<StackPanel Orientation="Horizontal" Spacing="12">
<ToggleSwitch
x:Uid="ToggleSwitch"
IsOn="{x:Bind IsEnabled, Mode=TwoWay}"
Style="{StaticResource RightAlignedCompactToggleSwitchStyle}" />
<Button Content="{ui:FontIcon Glyph=&#xE712;}" Style="{StaticResource SubtleButtonStyle}">
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem
x:Uid="EditItem"
Click="EditProfileBtn_Click"
CommandParameter="{x:Bind (models:ProfileVariablesSet)}"
Icon="{ui:FontIcon Glyph=&#xE70F;}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem
x:Uid="RemoveItem"
Click="RemoveProfileBtn_Click"
CommandParameter="{x:Bind (models:ProfileVariablesSet)}"
Icon="{ui:FontIcon Glyph=&#xE74D;}" />
</MenuFlyout>
</Button.Flyout>
<ToolTipService.ToolTip>
<TextBlock x:Uid="More_Options_ButtonTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</Button>
</StackPanel>
</tkcontrols:SettingsExpander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel
Margin="0,24,0,0"
Orientation="Horizontal"
Spacing="8">
<TextBlock x:Uid="DefaultVariablesLbl" Style="{StaticResource BodyStrongTextBlockStyle}" />
<FontIcon
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xE946;">
<ToolTipService.ToolTip>
<TextBlock x:Uid="DefaultVariablesDescriptionLbl" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</FontIcon>
</StackPanel>
<tkcontrols:SettingsExpander
Margin="0,4,0,0"
Header="{x:Bind ViewModel.UserDefaultSet.Name}"
HeaderIcon="{ui:FontIcon Glyph=&#xE77B;}">
<tkcontrols:SettingsExpander.ItemsHeader>
<ItemsRepeater
ItemTemplate="{StaticResource VariableTemplate}"
ItemsSource="{x:Bind ViewModel.UserDefaultSet.Variables, Mode=OneWay}"
TabFocusNavigation="Local"
VerticalCacheLength="10" />
</tkcontrols:SettingsExpander.ItemsHeader>
<StackPanel Orientation="Horizontal">
<Button
x:Name="AddDefaultVariableUserBtn"
x:Uid="AddVariableContent"
Click="AddDefaultVariableBtn_Click"
CommandParameter="{x:Bind ViewModel.UserDefaultSet}"
Content="Add variable"
Style="{StaticResource AccentButtonStyle}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="AddVariableTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</Button>
</StackPanel>
</tkcontrols:SettingsExpander>
<tkcontrols:SettingsExpander Header="{x:Bind ViewModel.SystemDefaultSet.Name}" HeaderIcon="{ui:FontIcon Glyph=&#xE977;}">
<tkcontrols:SettingsExpander.ItemsHeader>
<ItemsRepeater
ItemTemplate="{StaticResource VariableTemplate}"
ItemsSource="{x:Bind ViewModel.SystemDefaultSet.Variables, Mode=OneWay}"
TabFocusNavigation="Local"
VerticalCacheLength="10" />
</tkcontrols:SettingsExpander.ItemsHeader>
<tkcontrols:SettingsExpander.Description>
<StackPanel
Orientation="Horizontal"
Spacing="4"
Visibility="{x:Bind ViewModel.IsElevated, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
<Border
Width="12"
Height="12"
AutomationProperties.AccessibilityView="Raw"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="12">
<FontIcon
FontSize="8"
Foreground="{ThemeResource TextOnAccentFillColorPrimaryBrush}"
Glyph="&#xEA1F;" />
</Border>
<TextBlock x:Uid="EditSystemDefaultSetInfoBar" />
</StackPanel>
</tkcontrols:SettingsExpander.Description>
<StackPanel Orientation="Horizontal">
<Button
x:Name="AddDefaultVariableSystemBtn"
x:Uid="AddVariableContent"
Click="AddDefaultVariableBtn_Click"
CommandParameter="{x:Bind ViewModel.SystemDefaultSet}"
IsEnabled="{x:Bind ViewModel.IsElevated}"
Style="{StaticResource AccentButtonStyle}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="AddVariableTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</Button>
</StackPanel>
</tkcontrols:SettingsExpander>
</StackPanel>
</ScrollViewer>
<tkcontrols:GridSplitter
x:Name="Splitter"
Grid.Row="2"
Grid.Column="1"
Width="8"
Foreground="Transparent"
ResizeBehavior="BasedOnAlignment"
ResizeDirection="Auto" />
<Grid
x:Name="AppliedValuesPanel"
Grid.Row="2"
Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock x:Uid="AppliedVariablesLbl" Style="{StaticResource BodyStrongTextBlockStyle}" />
<FontIcon
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xE946;">
<ToolTipService.ToolTip>
<TextBlock x:Uid="AppliedVariablesDescriptionLbl" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</FontIcon>
</StackPanel>
<Grid
Grid.Row="1"
Margin="0,8,0,0"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{ThemeResource ControlCornerRadius}">
<ScrollViewer x:Name="AppliedVariablesScrollViewer" HorizontalScrollBarVisibility="Auto">
<ItemsControl Margin="12,8,12,0" ItemsSource="{x:Bind ViewModel.AppliedVariables, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:Variable">
<Grid Height="56" ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<FontIcon
Grid.Column="0"
VerticalAlignment="Center"
FontSize="14"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="{x:Bind ParentType, Mode=OneWay, Converter={StaticResource VariableTypeToGlyphConverter}}" />
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock
Text="{x:Bind Name}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
<TextBlock
Grid.Row="1"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Values}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap">
<ToolTipService.ToolTip>
<TextBlock Text="{x:Bind Values}" TextWrapping="WrapWholeWords" />
</ToolTipService.ToolTip>
</TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
</Grid>
<ContentDialog
x:Name="AddDefaultVariableDialog"
x:Uid="AddDefaultVariableDialog"
IsPrimaryButtonEnabled="{Binding Valid, Mode=OneWay}"
IsSecondaryButtonEnabled="True"
PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
<ContentDialog.DataContext>
<models:Variable />
</ContentDialog.DataContext>
<ScrollViewer>
<StackPanel
MinWidth="320"
HorizontalAlignment="Stretch"
Spacing="16">
<TextBox
x:Uid="AddNewVariableName"
IsSpellCheckEnabled="False"
Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="AddDefaultVariableNameTxtBox_TextChanged" />
<TextBox
x:Uid="AddNewVariableValue"
AcceptsReturn="False"
IsSpellCheckEnabled="False"
ScrollViewer.IsVerticalRailEnabled="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled"
Text="{Binding Values, Mode=TwoWay}"
TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
</ContentDialog>
<ContentDialog
x:Name="EditVariableDialog"
x:Uid="EditVariableDialog"
IsPrimaryButtonEnabled="{Binding Valid, Mode=OneWay}"
IsSecondaryButtonEnabled="True"
PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
<ContentDialog.DataContext>
<models:Variable />
</ContentDialog.DataContext>
<ScrollViewer>
<StackPanel
MinWidth="320"
HorizontalAlignment="Stretch"
Spacing="16">
<TextBox
x:Name="EditVariableDialogNameTxtBox"
x:Uid="AddNewVariableName"
IsSpellCheckEnabled="False"
Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="EditVariableDialogNameTxtBox_TextChanged" />
<TextBox
x:Name="EditVariableDialogValueTxtBox"
x:Uid="AddNewVariableValue"
AcceptsReturn="False"
IsSpellCheckEnabled="False"
ScrollViewer.IsVerticalRailEnabled="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled"
Text="{Binding Values, Mode=TwoWay}"
TextChanged="EditVariableDialogValueTxtBox_TextChanged"
TextWrapping="Wrap" />
<MenuFlyoutSeparator Visibility="{Binding ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}" />
<ItemsControl
x:Name="EditVariableValuesList"
Margin="0,-8,0,12"
HorizontalAlignment="Stretch"
ItemsSource="{Binding ValuesList, Mode=TwoWay}"
Visibility="{Binding ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<TextBox
Background="Transparent"
BorderBrush="Transparent"
LostFocus="EditVariableValuesListTextBox_LostFocus"
Text="{Binding Text}" />
<Button
x:Uid="More_Options_Button"
Grid.Column="1"
VerticalAlignment="Center"
Content="&#xE712;"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Style="{StaticResource SubtleButtonStyle}">
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem
x:Uid="MoveUp"
Click="ReorderButtonUp_Click"
Icon="{ui:FontIcon Glyph=&#xE74A;}" />
<MenuFlyoutItem
x:Uid="MoveDown"
Click="ReorderButtonDown_Click"
Icon="{ui:FontIcon Glyph=&#xE74B;}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem
x:Uid="RemoveListItem"
Click="RemoveListVariableButton_Click"
Icon="{ui:FontIcon Glyph=&#xE74D;}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem
x:Uid="InsertListEntryBefore"
Click="InsertListEntryBeforeButton_Click"
Icon="{ui:FontIcon Glyph=&#xECC8;}" />
<MenuFlyoutItem
x:Uid="InsertListEntryAfter"
Click="InsertListEntryAfterButton_Click"
Icon="{ui:FontIcon Glyph=&#xECC8;}" />
</MenuFlyout>
</Button.Flyout>
<ToolTipService.ToolTip>
<TextBlock x:Uid="More_Options_ButtonTooltip" />
</ToolTipService.ToolTip>
</Button>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</ContentDialog>
<ContentDialog
x:Name="AddProfileDialog"
x:Uid="AddProfileDialog"
IsPrimaryButtonEnabled="{Binding Valid, Mode=OneWay}"
IsSecondaryButtonEnabled="True"
PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
<ContentDialog.DataContext>
<models:ProfileVariablesSet />
</ContentDialog.DataContext>
<ScrollViewer>
<StackPanel
MinWidth="360"
HorizontalAlignment="Stretch"
Spacing="12">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox
x:Uid="NewProfileNameTxtBox"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
IsSpellCheckEnabled="False"
Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<ToggleSwitch
x:Uid="NewProfileEnabled"
Grid.Column="1"
MinWidth="0"
Margin="0,0,0,0"
VerticalAlignment="Center"
IsOn="{Binding IsEnabled, Mode=TwoWay}"
OffContent=""
OnContent="" />
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock x:Uid="NewProfileVariablesListViewHeader" Margin="0,12,0,8" />
<TextBlock
x:Uid="NewProfileVariablesListViewApplyToSystemHeader"
Grid.Column="1"
Margin="0,12,0,8"
HorizontalAlignment="Right"
Visibility="Collapsed" />
<ItemsControl
x:Name="NewProfileVariablesListView"
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="0,-8,0,12"
HorizontalAlignment="Stretch"
ItemsSource="{Binding Variables, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:Variable">
<Grid Height="48" ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<StackPanel VerticalAlignment="Center" Orientation="Vertical">
<TextBlock
Text="{x:Bind Name}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Values}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
</StackPanel>
<ToggleSwitch
x:Uid="ApplyAsSystemBtn"
Grid.Column="1"
IsOn="{x:Bind Path=ApplyToSystem, Mode=TwoWay}"
Visibility="Collapsed" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<Button>
<StackPanel Orientation="Horizontal" Spacing="8">
<FontIcon
x:Name="AddVariableIcon"
FontSize="16"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="&#xe710;" />
<TextBlock x:Uid="AddVariableBtn" />
</StackPanel>
<Button.Flyout>
<Flyout
x:Name="AddVariableFlyout"
Closed="AddVariableFlyout_Closed"
Placement="Right"
ShouldConstrainToRootBounds="False">
<Grid Width="320" Height="480">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<tkcontrols:Segmented
x:Name="SwitchViewsSegmentedView"
MaxWidth="500"
HorizontalAlignment="Stretch"
SelectionMode="Single">
<tkcontrols:SegmentedItem
x:Name="AddNewVariableSegmentedItem"
x:Uid="NewVariableSegmentedButton"
Tag="NewVariable" />
<tkcontrols:SegmentedItem
x:Name="AddExistingVariableSegmentedItem"
x:Uid="ExistingVariableSegmentedButton"
Tag="ExistingVariable" />
</tkcontrols:Segmented>
<tkcontrols:SwitchPresenter
x:Name="AddVariableSwitchPresenter"
Grid.Row="1"
Value="{Binding SelectedItem.Tag, ElementName=SwitchViewsSegmentedView}">
<tkcontrols:Case Value="NewVariable">
<StackPanel Grid.Row="1" Orientation="Vertical">
<!-- Adding new variable -->
<TextBox
x:Name="AddNewVariableName"
x:Uid="AddNewVariableName"
Margin="0,16,0,0"
TextChanged="AddNewVariableName_TextChanged" />
<TextBox
x:Name="AddNewVariableValue"
x:Uid="AddNewVariableValue"
Margin="0,16,0,0" />
</StackPanel>
</tkcontrols:Case>
<tkcontrols:Case Value="ExistingVariable">
<!-- Adding existing variables -->
<ListView
x:Name="ExistingVariablesListView"
Grid.Row="1"
Margin="-12,12,0,12"
HorizontalAlignment="Stretch"
ItemsSource="{x:Bind ViewModel.DefaultVariables.Variables, Mode=OneWay}"
Loaded="ExistingVariablesListView_Loaded"
SelectionChanged="ExistingVariablesListView_SelectionChanged"
SelectionMode="Multiple">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:Variable">
<Grid Height="48" ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<FontIcon
Grid.Column="0"
VerticalAlignment="Center"
FontSize="14"
Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}"
Glyph="{x:Bind ParentType, Mode=OneWay, Converter={StaticResource VariableTypeToGlyphConverter}}" />
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Orientation="Vertical">
<TextBlock
Text="{x:Bind Name}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind Values}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</tkcontrols:Case>
</tkcontrols:SwitchPresenter>
<Grid Grid.Row="2" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
x:Name="ConfirmAddVariableBtn"
x:Uid="ConfirmAddVariableBtn"
Margin="4,0,4,0"
HorizontalAlignment="Stretch"
Command="{x:Bind AddVariableCommand}"
IsEnabled="False"
Style="{StaticResource AccentButtonStyle}" />
<Button
x:Name="CancelAddVariableBtn"
x:Uid="CancelAddVariableBtn"
Grid.Column="1"
Margin="4,0,4,0"
HorizontalAlignment="Stretch"
Command="{x:Bind CancelAddVariableCommand}" />
</Grid>
</Grid>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
</ScrollViewer>
</ContentDialog>
</Grid>
</Page>

View File

@@ -0,0 +1,43 @@
// 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 EnvironmentVariablesUILib.Helpers;
using ManagedCommon;
namespace EnvironmentVariables
{
internal sealed class LoggerWrapper : ILogger
{
public void LogDebug(string message)
{
Logger.LogDebug(message);
}
public void LogError(string message)
{
Logger.LogError(message);
}
public void LogError(string message, Exception ex)
{
Logger.LogError(message, ex);
}
public void LogInfo(string message)
{
Logger.LogInfo(message);
}
public void LogTrace()
{
Logger.LogTrace();
}
public void LogWarning(string message)
{
Logger.LogWarning(message);
}
}
}

View File

@@ -5,7 +5,7 @@
using System;
using System.Runtime.InteropServices;
namespace EnvironmentVariables.Helpers.Win32
namespace EnvironmentVariables.Win32
{
public static class NativeMethods
{

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics.Tracing;
using EnvironmentVariables.Models;
using EnvironmentVariablesUILib.Models;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;

View File

@@ -0,0 +1,28 @@
// 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 EnvironmentVariablesUILib.Models;
using EnvironmentVariablesUILib.Telemetry;
using Microsoft.PowerToys.Telemetry;
namespace EnvironmentVariables.Telemetry
{
internal sealed class TelemetryWrapper : ITelemetry
{
public void LogEnvironmentVariablesProfileEnabledEvent(bool enabled)
{
var telemetryEnabled = new EnvironmentVariablesProfileEnabledEvent()
{
Enabled = enabled,
};
PowerToysTelemetry.Log.WriteEvent(telemetryEnabled);
}
public void LogEnvironmentVariablesVariableChangedEvent(VariablesSetType type)
{
PowerToysTelemetry.Log.WriteEvent(new Telemetry.EnvironmentVariablesVariableChangedEvent(type));
}
}
}

View File

@@ -4,12 +4,9 @@
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--The ID below informs the system that this application is compatible with OS features first introduced in Windows 8.
For more info see https://docs.microsoft.com/windows/win32/sysinfo/targeting-your-application-at-windows-8-1
It is also necessary to support features in unpackaged applications, for example the custom title bar implementation.-->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 10 -->
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB

View File

@@ -3,10 +3,10 @@
// See the LICENSE file in the project root for more information.
using System;
using EnvironmentVariables.Models;
using EnvironmentVariablesUILib.Models;
using Microsoft.UI.Xaml.Data;
namespace EnvironmentVariables.Converters;
namespace EnvironmentVariablesUILib.Converters;
public class EnvironmentStateToBoolConverter : IValueConverter
{

View File

@@ -3,11 +3,11 @@
// See the LICENSE file in the project root for more information.
using System;
using EnvironmentVariables.Helpers;
using EnvironmentVariables.Models;
using EnvironmentVariablesUILib.Helpers;
using EnvironmentVariablesUILib.Models;
using Microsoft.UI.Xaml.Data;
namespace EnvironmentVariables.Converters;
namespace EnvironmentVariablesUILib.Converters;
public class EnvironmentStateToMessageConverter : IValueConverter
{

View File

@@ -3,11 +3,11 @@
// See the LICENSE file in the project root for more information.
using System;
using EnvironmentVariables.Helpers;
using EnvironmentVariables.Models;
using EnvironmentVariablesUILib.Helpers;
using EnvironmentVariablesUILib.Models;
using Microsoft.UI.Xaml.Data;
namespace EnvironmentVariables.Converters;
namespace EnvironmentVariablesUILib.Converters;
public class EnvironmentStateToTitleConverter : IValueConverter
{

View File

@@ -3,11 +3,11 @@
// See the LICENSE file in the project root for more information.
using System;
using EnvironmentVariables.Models;
using EnvironmentVariablesUILib.Models;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
namespace EnvironmentVariables.Converters;
namespace EnvironmentVariablesUILib.Converters;
public class EnvironmentStateToVisibilityConverter : IValueConverter
{

View File

@@ -3,10 +3,10 @@
// See the LICENSE file in the project root for more information.
using System;
using EnvironmentVariables.Models;
using EnvironmentVariablesUILib.Models;
using Microsoft.UI.Xaml.Data;
namespace EnvironmentVariables.Converters;
namespace EnvironmentVariablesUILib.Converters;
public class VariableTypeToGlyphConverter : IValueConverter
{

View File

@@ -0,0 +1,561 @@
<Page x:Class="EnvironmentVariablesUILib.EnvironmentVariablesMainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:EnvironmentVariablesUILib.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:EnvironmentVariablesUILib.Models"
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
xmlns:ui="using:CommunityToolkit.WinUI" x:Name="RootPage" mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<!-- These resource dictionaries are needed to reference styles part of SettingsControls -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.SettingsControls/SettingsCard/SettingsCard.xaml" />
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Controls.SettingsControls/SettingsExpander/SettingsExpander.xaml" />
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<Style x:Key="SubtleButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter x:Name="ContentPresenter" Padding="{TemplateBinding Padding}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" AnimatedIcon.State="Normal" AutomationProperties.AccessibilityView="Raw" Background="{TemplateBinding Background}" BackgroundSizing="{TemplateBinding BackgroundSizing}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" CornerRadius="{TemplateBinding CornerRadius}" Foreground="{TemplateBinding Foreground}">
<ContentPresenter.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</ContentPresenter.BackgroundTransition>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<x:Double x:Key="SecondaryTextFontSize">12</x:Double>
<Style x:Key="SecondaryTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="{StaticResource SecondaryTextFontSize}" />
<Setter Property="Foreground" Value="{ThemeResource TextFillColorSecondaryBrush}" />
</Style>
<DataTemplate x:Key="VariableTemplate" x:DataType="models:Variable">
<tkcontrols:SettingsCard CommandParameter="{x:Bind (models:Variable)}" IsActionIconVisible="False" IsClickEnabled="False" Style="{StaticResource DefaultSettingsExpanderItemStyle}">
<tkcontrols:SettingsCard.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Name, Mode=TwoWay}" />
<FontIcon Margin="6,0,6,0" FontSize="16" Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="&#xE930;" Visibility="{x:Bind IsAppliedFromProfile, Converter={StaticResource BoolToVisibilityConverter}}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="VariableIsAppliedByActiveProfileTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</FontIcon>
</StackPanel>
</tkcontrols:SettingsCard.Header>
<tkcontrols:SettingsCard.Description>
<StackPanel HorizontalAlignment="Left">
<ItemsControl x:Name="VariableValuesList" HorizontalAlignment="Left" ItemsSource="{x:Bind ValuesList, Mode=TwoWay}" Visibility="{x:Bind ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Margin="0,2,0,2" Foreground="{ThemeResource TextFillColorSecondaryBrush}" IsTextSelectionEnabled="True" Style="{StaticResource CaptionTextBlockStyle}" Text="{Binding Text}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock IsTextSelectionEnabled="True" Text="{x:Bind Values, Mode=TwoWay}" Visibility="{x:Bind ShowAsList, Converter={StaticResource BoolToInvertedVisibilityConverter}}" />
</StackPanel>
</tkcontrols:SettingsCard.Description>
<Button Content="{ui:FontIcon Glyph=&#xE712;}" IsEnabled="{x:Bind IsEditable}" Style="{StaticResource SubtleButtonStyle}">
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="EditItem" Click="EditVariable_Click" CommandParameter="{x:Bind (models:Variable)}" Icon="{ui:FontIcon Glyph=&#xE70F;}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem x:Uid="RemoveItem" Click="Delete_Variable_Click" CommandParameter="{x:Bind (models:Variable)}" Icon="{ui:FontIcon Glyph=&#xE74D;}" />
</MenuFlyout>
</Button.Flyout>
<ToolTipService.ToolTip>
<TextBlock x:Uid="More_Options_ButtonTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</Button>
</tkcontrols:SettingsCard>
</DataTemplate>
<converters:VariableTypeToGlyphConverter x:Key="VariableTypeToGlyphConverter" />
<converters:EnvironmentStateToBoolConverter x:Key="EnvironmentStateToBoolConverter" />
<converters:EnvironmentStateToMessageConverter x:Key="EnvironmentStateToMessageConverter" />
<converters:EnvironmentStateToTitleConverter x:Key="EnvironmentStateToTitleConverter" />
<converters:EnvironmentStateToVisibilityConverter x:Key="EnvironmentStateToVisibilityConverter" />
<tkconverters:BoolToVisibilityConverter x:Key="BoolToInvertedVisibilityConverter" FalseValue="Visible" TrueValue="Collapsed" />
<tkconverters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<tkconverters:BoolNegationConverter x:Key="BoolNegationConverter" />
</ResourceDictionary>
</Page.Resources>
<Grid Margin="16" RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<!-- buttons -->
<RowDefinition Height="Auto" />
<!-- Warning messages -->
<RowDefinition Height="*" />
<!-- content -->
<RowDefinition Height="Auto" />
<!-- content -->
</Grid.RowDefinitions>
<!-- buttons -->
<StackPanel Orientation="Horizontal">
<Button Command="{x:Bind NewProfileCommand}">
<StackPanel Orientation="Horizontal" Spacing="8">
<FontIcon x:Name="Icon" FontSize="16" Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="&#xe710;" />
<TextBlock x:Uid="NewProfileBtn" />
</StackPanel>
<Button.KeyboardAccelerators>
<KeyboardAccelerator Key="N" Modifiers="Control" />
</Button.KeyboardAccelerators>
</Button>
</StackPanel>
<Grid Grid.Row="1">
<InfoBar x:Name="InvalidStateInfoBar" x:Uid="InvalidStateInfoBar" Title="{x:Bind ViewModel.EnvironmentState, Mode=OneWay, Converter={StaticResource EnvironmentStateToTitleConverter}}" CloseButtonClick="InvalidStateInfoBar_CloseButtonClick" IsOpen="{x:Bind ViewModel.EnvironmentState, Mode=OneWay, Converter={StaticResource EnvironmentStateToBoolConverter}}" Message="{x:Bind ViewModel.EnvironmentState, Mode=OneWay, Converter={StaticResource EnvironmentStateToMessageConverter}}" Severity="Warning" Visibility="{x:Bind ViewModel.EnvironmentState, Mode=OneWay, Converter={StaticResource EnvironmentStateToVisibilityConverter}}">
<InfoBar.ActionButton>
<Button Click="ReloadButton_Click" Content="{ui:FontIcon Glyph=&#xe72c;}" Style="{StaticResource SubtleButtonStyle}" Visibility="{x:Bind ViewModel.IsInfoBarButtonVisible, Mode=OneWay}" />
</InfoBar.ActionButton>
</InfoBar>
</Grid>
<Grid Grid.Row="2" Margin="0,24,0,0" ColumnSpacing="12">
<Grid.ColumnDefinitions>
<!-- Left side -->
<ColumnDefinition Width="*" />
<!-- GridSplitter -->
<ColumnDefinition Width="Auto" />
<!-- Applied values -->
<ColumnDefinition Width="480" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Row="1" Grid.Column="0" VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="4">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock x:Uid="ProfilesLbl" Style="{StaticResource BodyStrongTextBlockStyle}" />
<FontIcon FontSize="16" Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="&#xE946;">
<ToolTipService.ToolTip>
<TextBlock x:Uid="ProfilesDescriptionLbl" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</FontIcon>
</StackPanel>
<ItemsControl Margin="0,4,0,0" ItemsSource="{x:Bind ViewModel.Profiles, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:ProfileVariablesSet">
<tkcontrols:SettingsExpander Margin="0,0,0,4" Header="{x:Bind Name, Mode=TwoWay}" HeaderIcon="{ui:FontIcon Glyph=&#xEDE3;}">
<tkcontrols:SettingsExpander.ItemsHeader>
<ItemsRepeater ItemTemplate="{StaticResource VariableTemplate}" ItemsSource="{x:Bind Variables, Mode=OneWay}" TabFocusNavigation="Local" VerticalCacheLength="10" />
</tkcontrols:SettingsExpander.ItemsHeader>
<StackPanel Orientation="Horizontal" Spacing="12">
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind IsEnabled, Mode=TwoWay}" Style="{StaticResource RightAlignedCompactToggleSwitchStyle}" />
<Button Content="{ui:FontIcon Glyph=&#xE712;}" Style="{StaticResource SubtleButtonStyle}">
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="EditItem" Click="EditProfileBtn_Click" CommandParameter="{x:Bind (models:ProfileVariablesSet)}" Icon="{ui:FontIcon Glyph=&#xE70F;}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem x:Uid="RemoveItem" Click="RemoveProfileBtn_Click" CommandParameter="{x:Bind (models:ProfileVariablesSet)}" Icon="{ui:FontIcon Glyph=&#xE74D;}" />
</MenuFlyout>
</Button.Flyout>
<ToolTipService.ToolTip>
<TextBlock x:Uid="More_Options_ButtonTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</Button>
</StackPanel>
</tkcontrols:SettingsExpander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Margin="0,24,0,0" Orientation="Horizontal" Spacing="8">
<TextBlock x:Uid="DefaultVariablesLbl" Style="{StaticResource BodyStrongTextBlockStyle}" />
<FontIcon FontSize="16" Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="&#xE946;">
<ToolTipService.ToolTip>
<TextBlock x:Uid="DefaultVariablesDescriptionLbl" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</FontIcon>
</StackPanel>
<tkcontrols:SettingsExpander Margin="0,4,0,0" Header="{x:Bind ViewModel.UserDefaultSet.Name}" HeaderIcon="{ui:FontIcon Glyph=&#xE77B;}">
<tkcontrols:SettingsExpander.ItemsHeader>
<ItemsRepeater ItemTemplate="{StaticResource VariableTemplate}" ItemsSource="{x:Bind ViewModel.UserDefaultSet.Variables, Mode=OneWay}" TabFocusNavigation="Local" VerticalCacheLength="10" />
</tkcontrols:SettingsExpander.ItemsHeader>
<StackPanel Orientation="Horizontal">
<Button x:Name="AddDefaultVariableUserBtn" x:Uid="AddVariableContent" Click="AddDefaultVariableBtn_Click" CommandParameter="{x:Bind ViewModel.UserDefaultSet}" Content="Add variable" Style="{StaticResource AccentButtonStyle}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="AddVariableTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</Button>
</StackPanel>
</tkcontrols:SettingsExpander>
<tkcontrols:SettingsExpander Header="{x:Bind ViewModel.SystemDefaultSet.Name}" HeaderIcon="{ui:FontIcon Glyph=&#xE977;}">
<tkcontrols:SettingsExpander.ItemsHeader>
<ItemsRepeater ItemTemplate="{StaticResource VariableTemplate}" ItemsSource="{x:Bind ViewModel.SystemDefaultSet.Variables, Mode=OneWay}" TabFocusNavigation="Local" VerticalCacheLength="10" />
</tkcontrols:SettingsExpander.ItemsHeader>
<tkcontrols:SettingsExpander.Description>
<StackPanel Orientation="Horizontal" Spacing="4" Visibility="{x:Bind ViewModel.IsElevated, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
<Border Width="12" Height="12" AutomationProperties.AccessibilityView="Raw" Background="{ThemeResource AccentFillColorDefaultBrush}" CornerRadius="12">
<FontIcon FontSize="8" Foreground="{ThemeResource TextOnAccentFillColorPrimaryBrush}" Glyph="&#xEA1F;" />
</Border>
<TextBlock x:Uid="EditSystemDefaultSetInfoBar" />
</StackPanel>
</tkcontrols:SettingsExpander.Description>
<StackPanel Orientation="Horizontal">
<Button x:Name="AddDefaultVariableSystemBtn" x:Uid="AddVariableContent" Click="AddDefaultVariableBtn_Click" CommandParameter="{x:Bind ViewModel.SystemDefaultSet}" IsEnabled="{x:Bind ViewModel.IsElevated}" Style="{StaticResource AccentButtonStyle}">
<ToolTipService.ToolTip>
<TextBlock x:Uid="AddVariableTooltip" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</Button>
</StackPanel>
</tkcontrols:SettingsExpander>
</StackPanel>
</ScrollViewer>
<tkcontrols:GridSplitter x:Name="Splitter" Grid.Row="2" Grid.Column="1" Width="8" Foreground="Transparent" ResizeBehavior="BasedOnAlignment" ResizeDirection="Auto" />
<Grid x:Name="AppliedValuesPanel" Grid.Row="2" Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock x:Uid="AppliedVariablesLbl" Style="{StaticResource BodyStrongTextBlockStyle}" />
<FontIcon FontSize="16" Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="&#xE946;">
<ToolTipService.ToolTip>
<TextBlock x:Uid="AppliedVariablesDescriptionLbl" TextWrapping="Wrap" />
</ToolTipService.ToolTip>
</FontIcon>
</StackPanel>
<Grid Grid.Row="1" Margin="0,8,0,0" Background="{ThemeResource CardBackgroundFillColorDefaultBrush}" BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}" BorderThickness="1" CornerRadius="{ThemeResource ControlCornerRadius}">
<ScrollViewer x:Name="AppliedVariablesScrollViewer" HorizontalScrollBarVisibility="Auto">
<ItemsControl Margin="12,8,12,0" ItemsSource="{x:Bind ViewModel.AppliedVariables, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:Variable">
<Grid Height="56" ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<FontIcon Grid.Column="0" VerticalAlignment="Center" FontSize="14" Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="{x:Bind ParentType, Mode=OneWay, Converter={StaticResource VariableTypeToGlyphConverter}}" />
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock Text="{x:Bind Name}" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Grid.Row="1" Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" Text="{x:Bind Values}" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap">
<ToolTipService.ToolTip>
<TextBlock Text="{x:Bind Values}" TextWrapping="WrapWholeWords" />
</ToolTipService.ToolTip>
</TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
</Grid>
<ContentDialog x:Name="AddDefaultVariableDialog" x:Uid="AddDefaultVariableDialog" IsPrimaryButtonEnabled="{Binding Valid, Mode=OneWay}" IsSecondaryButtonEnabled="True" PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
<ContentDialog.DataContext>
<models:Variable />
</ContentDialog.DataContext>
<ScrollViewer>
<StackPanel MinWidth="320" HorizontalAlignment="Stretch" Spacing="16">
<TextBox x:Uid="AddNewVariableName" IsSpellCheckEnabled="False" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TextChanged="AddDefaultVariableNameTxtBox_TextChanged" />
<TextBox x:Uid="AddNewVariableValue" AcceptsReturn="False" IsSpellCheckEnabled="False" ScrollViewer.IsVerticalRailEnabled="True" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Enabled" Text="{Binding Values, Mode=TwoWay}" TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
</ContentDialog>
<ContentDialog x:Name="EditVariableDialog" x:Uid="EditVariableDialog" IsPrimaryButtonEnabled="{Binding Valid, Mode=OneWay}" IsSecondaryButtonEnabled="True" PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
<ContentDialog.DataContext>
<models:Variable />
</ContentDialog.DataContext>
<ScrollViewer>
<StackPanel MinWidth="320" HorizontalAlignment="Stretch" Spacing="16">
<TextBox x:Name="EditVariableDialogNameTxtBox" x:Uid="AddNewVariableName" IsSpellCheckEnabled="False" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TextChanged="EditVariableDialogNameTxtBox_TextChanged" />
<TextBox x:Name="EditVariableDialogValueTxtBox" x:Uid="AddNewVariableValue" AcceptsReturn="False" IsSpellCheckEnabled="False" ScrollViewer.IsVerticalRailEnabled="True" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Enabled" Text="{Binding Values, Mode=TwoWay}" TextChanged="EditVariableDialogValueTxtBox_TextChanged" TextWrapping="Wrap" />
<MenuFlyoutSeparator Visibility="{Binding ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}" />
<ItemsControl x:Name="EditVariableValuesList" Margin="0,-8,0,12" HorizontalAlignment="Stretch" ItemsSource="{Binding ValuesList, Mode=TwoWay}" Visibility="{Binding ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<TextBox Background="Transparent" BorderBrush="Transparent" LostFocus="EditVariableValuesListTextBox_LostFocus" Text="{Binding Text}" />
<Button x:Uid="More_Options_Button" Grid.Column="1" VerticalAlignment="Center" Content="&#xE712;" FontFamily="{ThemeResource SymbolThemeFontFamily}" Style="{StaticResource SubtleButtonStyle}">
<Button.Flyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="MoveUp" Click="ReorderButtonUp_Click" Icon="{ui:FontIcon Glyph=&#xE74A;}" />
<MenuFlyoutItem x:Uid="MoveDown" Click="ReorderButtonDown_Click" Icon="{ui:FontIcon Glyph=&#xE74B;}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem x:Uid="RemoveListItem" Click="RemoveListVariableButton_Click" Icon="{ui:FontIcon Glyph=&#xE74D;}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem x:Uid="InsertListEntryBefore" Click="InsertListEntryBeforeButton_Click" Icon="{ui:FontIcon Glyph=&#xECC8;}" />
<MenuFlyoutItem x:Uid="InsertListEntryAfter" Click="InsertListEntryAfterButton_Click" Icon="{ui:FontIcon Glyph=&#xECC8;}" />
</MenuFlyout>
</Button.Flyout>
<ToolTipService.ToolTip>
<TextBlock x:Uid="More_Options_ButtonTooltip" />
</ToolTipService.ToolTip>
</Button>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</ContentDialog>
<ContentDialog x:Name="AddProfileDialog" x:Uid="AddProfileDialog" IsPrimaryButtonEnabled="{Binding Valid, Mode=OneWay}" IsSecondaryButtonEnabled="True" PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
<ContentDialog.DataContext>
<models:ProfileVariablesSet />
</ContentDialog.DataContext>
<ScrollViewer>
<StackPanel MinWidth="360" HorizontalAlignment="Stretch" Spacing="12">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Uid="NewProfileNameTxtBox" HorizontalAlignment="Stretch" VerticalAlignment="Center" IsSpellCheckEnabled="False" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<ToggleSwitch x:Uid="NewProfileEnabled" Grid.Column="1" MinWidth="0" Margin="0,0,0,0" VerticalAlignment="Center" IsOn="{Binding IsEnabled, Mode=TwoWay}" OffContent="" OnContent="" />
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock x:Uid="NewProfileVariablesListViewHeader" Margin="0,12,0,8" />
<TextBlock x:Uid="NewProfileVariablesListViewApplyToSystemHeader" Grid.Column="1" Margin="0,12,0,8" HorizontalAlignment="Right" Visibility="Collapsed" />
<ItemsControl x:Name="NewProfileVariablesListView" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,-8,0,12" HorizontalAlignment="Stretch" ItemsSource="{Binding Variables, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:Variable">
<Grid Height="48" ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<StackPanel VerticalAlignment="Center" Orientation="Vertical">
<TextBlock Text="{x:Bind Name}" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" Text="{x:Bind Values}" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
</StackPanel>
<ToggleSwitch x:Uid="ApplyAsSystemBtn" Grid.Column="1" IsOn="{x:Bind Path=ApplyToSystem, Mode=TwoWay}" Visibility="Collapsed" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<Button>
<StackPanel Orientation="Horizontal" Spacing="8">
<FontIcon x:Name="AddVariableIcon" FontSize="16" Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="&#xe710;" />
<TextBlock x:Uid="AddVariableBtn" />
</StackPanel>
<Button.Flyout>
<Flyout x:Name="AddVariableFlyout" Closed="AddVariableFlyout_Closed" Placement="Right" ShouldConstrainToRootBounds="False">
<Grid Width="320" Height="480">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<tkcontrols:Segmented x:Name="SwitchViewsSegmentedView" MaxWidth="500" HorizontalAlignment="Stretch" SelectionMode="Single">
<tkcontrols:SegmentedItem x:Name="AddNewVariableSegmentedItem" x:Uid="NewVariableSegmentedButton" Tag="NewVariable" />
<tkcontrols:SegmentedItem x:Name="AddExistingVariableSegmentedItem" x:Uid="ExistingVariableSegmentedButton" Tag="ExistingVariable" />
</tkcontrols:Segmented>
<tkcontrols:SwitchPresenter x:Name="AddVariableSwitchPresenter" Grid.Row="1" Value="{Binding SelectedItem.Tag, ElementName=SwitchViewsSegmentedView}">
<tkcontrols:Case Value="NewVariable">
<StackPanel Grid.Row="1" Orientation="Vertical">
<!-- Adding new variable -->
<TextBox x:Name="AddNewVariableName" x:Uid="AddNewVariableName" Margin="0,16,0,0" TextChanged="AddNewVariableName_TextChanged" />
<TextBox x:Name="AddNewVariableValue" x:Uid="AddNewVariableValue" Margin="0,16,0,0" />
</StackPanel>
</tkcontrols:Case>
<tkcontrols:Case Value="ExistingVariable">
<!-- Adding existing variables -->
<ListView x:Name="ExistingVariablesListView" Grid.Row="1" Margin="-12,12,0,12" HorizontalAlignment="Stretch" ItemsSource="{x:Bind ViewModel.DefaultVariables.Variables, Mode=OneWay}" Loaded="ExistingVariablesListView_Loaded" SelectionChanged="ExistingVariablesListView_SelectionChanged" SelectionMode="Multiple">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:Variable">
<Grid Height="48" ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<FontIcon Grid.Column="0" VerticalAlignment="Center" FontSize="14" Foreground="{ThemeResource AccentTextFillColorPrimaryBrush}" Glyph="{x:Bind ParentType, Mode=OneWay, Converter={StaticResource VariableTypeToGlyphConverter}}" />
<StackPanel Grid.Column="1" VerticalAlignment="Center" Orientation="Vertical">
<TextBlock Text="{x:Bind Name}" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
<TextBlock Foreground="{ThemeResource TextFillColorSecondaryBrush}" Style="{StaticResource CaptionTextBlockStyle}" Text="{x:Bind Values}" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" />
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</tkcontrols:Case>
</tkcontrols:SwitchPresenter>
<Grid Grid.Row="2" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="ConfirmAddVariableBtn" x:Uid="ConfirmAddVariableBtn" Margin="4,0,4,0" HorizontalAlignment="Stretch" Command="{x:Bind AddVariableCommand}" IsEnabled="False" Style="{StaticResource AccentButtonStyle}" />
<Button x:Name="CancelAddVariableBtn" x:Uid="CancelAddVariableBtn" Grid.Column="1" Margin="4,0,4,0" HorizontalAlignment="Stretch" Command="{x:Bind CancelAddVariableCommand}" />
</Grid>
</Grid>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
</ScrollViewer>
</ContentDialog>
</Grid>
</Page>

View File

@@ -3,19 +3,17 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using EnvironmentVariables.Models;
using EnvironmentVariables.ViewModels;
using EnvironmentVariablesUILib.Models;
using EnvironmentVariablesUILib.ViewModels;
using Microsoft.UI.Xaml.Controls;
using Windows.Foundation.Collections;
namespace EnvironmentVariables.Views
namespace EnvironmentVariablesUILib
{
public sealed partial class MainPage : Page
public sealed partial class EnvironmentVariablesMainPage : Page
{
private sealed class RelayCommandParameter
{
@@ -46,11 +44,13 @@ namespace EnvironmentVariables.Views
public ICommand AddDefaultVariableCommand => new RelayCommand<DefaultVariablesSet>(AddDefaultVariable);
public MainPage()
public EnvironmentVariablesMainPage(MainViewModel viewModel)
{
this.InitializeComponent();
ViewModel = App.GetService<MainViewModel>();
ViewModel = viewModel;
DataContext = ViewModel;
ViewModel.LoadEnvironmentVariables();
}
private async Task ShowEditDialogAsync(Variable variable, VariablesSet parentSet)

View File

@@ -0,0 +1,69 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net8.0-windows10.0.20348</TargetFramework>
<RootNamespace>EnvironmentVariablesUILib</RootNamespace>
<UseWinUI>true</UseWinUI>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<AssemblyName>PowerToys.EnvironmentVariablesUILib</AssemblyName>
<!-- 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.EnvironmentVariablesUILib.pri</ProjectPriFileName>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
<IsPackable>true</IsPackable>
<Version>10.0.0</Version>
</PropertyGroup>
<ItemGroup>
<None Include="$(OutDir)\PowerToys.EnvironmentVariablesUILib.pri" Pack="True" PackageCopyToOutput="True" PackagePath="contentFiles\any\$(TargetFramework)" />
<XBFFile Include="$(OutDir)**\*.xbf" />
<None Include="@(XBFFile)" Pack="True" PackageCopyToOutput="True" PackagePath="contentFiles\any\$(TargetFramework)" />
<None Include="$(OutDir)\PowerToys.EnvironmentVariablesUILib.pdb" Pack="True" PackageCopyToOutput="true" PackagePath="lib/$(TargetFramework)" />
<None Include="Assets\**\*.png" Pack="true" PackageCopyToOutput="true" PackagePath="contentFiles\any\$(TargetFramework)\Assets"/>
<None Include="Assets\**\*.ico" Pack="true" PackageCopyToOutput="true" PackagePath="contentFiles\any\$(TargetFramework)\Assets"/>
</ItemGroup>
<ItemGroup>
<Content Remove="Assets\**\*.png" Pack="false" />
<Content Remove="Assets\**\*.ico" Pack="false" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Common" />
<PackageReference Include="Microsoft.Windows.CsWinRT" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Sizers" />
<PackageReference Include="System.IO.Abstractions" />
<PackageReference Include="WinUIEx" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
</Project>

View File

@@ -4,7 +4,7 @@
using System.Security.Principal;
namespace EnvironmentVariables.Helpers
namespace EnvironmentVariablesUILib.Helpers
{
public class ElevationHelper : IElevationHelper
{
@@ -16,5 +16,7 @@ namespace EnvironmentVariables.Helpers
{
_isElevated = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
}
public static IElevationHelper ElevationHelperInstance { get; set; }
}
}

View File

@@ -5,12 +5,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
using EnvironmentVariables.Helpers.Win32;
using EnvironmentVariables.Models;
using ManagedCommon;
using EnvironmentVariablesUILib.Helpers.Win32;
using EnvironmentVariablesUILib.Models;
using Microsoft.Win32;
namespace EnvironmentVariables.Helpers
namespace EnvironmentVariablesUILib.Helpers
{
internal sealed class EnvironmentVariablesHelper
{
@@ -73,7 +72,7 @@ namespace EnvironmentVariables.Helpers
const int MaxUserEnvVariableLength = 255; // User-wide env vars stored in the registry have names limited to 255 chars
if (!fromMachine && variable.Length >= MaxUserEnvVariableLength)
{
Logger.LogError("Can't apply variable - name too long.");
LoggerInstance.Logger.LogError("Can't apply variable - name too long.");
return;
}

View File

@@ -8,11 +8,11 @@ using System.IO;
using System.IO.Abstractions;
using System.Text.Json;
using System.Threading.Tasks;
using EnvironmentVariables.Models;
using EnvironmentVariablesUILib.Models;
namespace EnvironmentVariables.Helpers
namespace EnvironmentVariablesUILib.Helpers
{
internal sealed class EnvironmentVariablesService : IEnvironmentVariablesService
public sealed class EnvironmentVariablesService : IEnvironmentVariablesService
{
private const string ProfilesJsonFileSubPath = "Microsoft\\PowerToys\\EnvironmentVariables\\";

View File

@@ -2,7 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace EnvironmentVariables.Helpers
namespace EnvironmentVariablesUILib.Helpers
{
public interface IElevationHelper
{

View File

@@ -5,9 +5,9 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EnvironmentVariables.Models;
using EnvironmentVariablesUILib.Models;
namespace EnvironmentVariables.Helpers
namespace EnvironmentVariablesUILib.Helpers
{
public interface IEnvironmentVariablesService : IDisposable
{

View File

@@ -0,0 +1,23 @@
// 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 EnvironmentVariablesUILib.Helpers
{
public interface ILogger
{
public void LogError(string message);
public void LogError(string message, Exception ex);
public void LogWarning(string message);
public void LogInfo(string message);
public void LogDebug(string message);
public void LogTrace();
}
}

View File

@@ -0,0 +1,10 @@
// 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.
namespace EnvironmentVariablesUILib.Helpers
{
public static class LoggerInstance
{
public static ILogger Logger { get; set; }
}
}

View File

@@ -0,0 +1,54 @@
// 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.Runtime.InteropServices;
namespace EnvironmentVariablesUILib.Helpers.Win32
{
public static class NativeMethods
{
internal const int HWND_BROADCAST = 0xffff;
internal delegate IntPtr WinProc(IntPtr hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern int SendNotifyMessage(IntPtr hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll")]
internal static extern int GetDpiForWindow(IntPtr hwnd);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
internal static extern int SetWindowLong32(IntPtr hWnd, WindowLongIndexFlags nIndex, WinProc newProc);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
internal static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, WindowLongIndexFlags nIndex, WinProc newProc);
[DllImport("user32.dll")]
internal static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam);
[Flags]
internal enum WindowLongIndexFlags : int
{
GWL_WNDPROC = -4,
}
internal enum WindowMessage : int
{
WM_SETTINGSCHANGED = 0x001A,
}
internal static IntPtr SetWindowLongPtr(IntPtr hWnd, WindowLongIndexFlags nIndex, WinProc newProc)
{
if (IntPtr.Size == 8)
{
return SetWindowLongPtr64(hWnd, nIndex, newProc);
}
else
{
return new IntPtr(SetWindowLong32(hWnd, nIndex, newProc));
}
}
}
}

View File

@@ -3,15 +3,15 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Windows.ApplicationModel.Resources;
namespace EnvironmentVariables.Helpers
namespace EnvironmentVariablesUILib.Helpers
{
internal static class ResourceLoaderInstance
public static class ResourceLoaderInstance
{
internal static ResourceLoader ResourceLoader { get; private set; }
public static ResourceLoader ResourceLoader { get; private set; }
static ResourceLoaderInstance()
{
ResourceLoader = new ResourceLoader("PowerToys.EnvironmentVariables.pri");
ResourceLoader = new ResourceLoader("PowerToys.EnvironmentVariablesUILib.pri", "PowerToys.EnvironmentVariablesUILib/Resources");
}
}
}

View File

@@ -4,7 +4,7 @@
using System;
namespace EnvironmentVariables.Models
namespace EnvironmentVariablesUILib.Models
{
public class DefaultVariablesSet : VariablesSet
{

View File

@@ -2,7 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace EnvironmentVariables.Models
namespace EnvironmentVariablesUILib.Models
{
public enum EnvironmentState
{

View File

@@ -6,10 +6,9 @@ using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using EnvironmentVariables.Helpers;
using ManagedCommon;
using EnvironmentVariablesUILib.Helpers;
namespace EnvironmentVariables.Models
namespace EnvironmentVariablesUILib.Models
{
public partial class ProfileVariablesSet : VariablesSet
{
@@ -48,13 +47,13 @@ namespace EnvironmentVariables.Models
// Backup the variable
if (!EnvironmentVariablesHelper.SetVariableWithoutNotify(variableToOverride))
{
Logger.LogError("Failed to set backup variable.");
LoggerInstance.Logger.LogError("Failed to set backup variable.");
}
}
if (!EnvironmentVariablesHelper.SetVariableWithoutNotify(variable))
{
Logger.LogError("Failed to set profile variable.");
LoggerInstance.Logger.LogError("Failed to set profile variable.");
}
}
@@ -80,7 +79,7 @@ namespace EnvironmentVariables.Models
// Unset the variable
if (!EnvironmentVariablesHelper.UnsetVariableWithoutNotify(variable))
{
Logger.LogError("Failed to unset variable.");
LoggerInstance.Logger.LogError("Failed to unset variable.");
}
var originalName = variable.Name;
@@ -95,12 +94,12 @@ namespace EnvironmentVariables.Models
if (!EnvironmentVariablesHelper.UnsetVariableWithoutNotify(backupVariable))
{
Logger.LogError("Failed to unset backup variable.");
LoggerInstance.Logger.LogError("Failed to unset backup variable.");
}
if (!EnvironmentVariablesHelper.SetVariableWithoutNotify(variableToRestore))
{
Logger.LogError("Failed to restore backup variable.");
LoggerInstance.Logger.LogError("Failed to restore backup variable.");
}
}
}

View File

@@ -10,10 +10,9 @@ using System.Linq;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using EnvironmentVariables.Helpers;
using ManagedCommon;
using EnvironmentVariablesUILib.Helpers;
namespace EnvironmentVariables.Models
namespace EnvironmentVariablesUILib.Models
{
public partial class Variable : ObservableObject, IJsonOnDeserialized
{
@@ -38,7 +37,7 @@ namespace EnvironmentVariables.Models
{
get
{
return (ParentType != VariablesSetType.System || App.GetService<IElevationHelper>().IsElevated) && !IsAppliedFromProfile;
return (ParentType != VariablesSetType.System || ElevationHelper.ElevationHelperInstance.IsElevated) && !IsAppliedFromProfile;
}
}
@@ -122,7 +121,7 @@ namespace EnvironmentVariables.Models
{
if (!EnvironmentVariablesHelper.UnsetVariable(clone))
{
Logger.LogError("Failed to unset original variable.");
LoggerInstance.Logger.LogError("Failed to unset original variable.");
}
if (parentProfile != null)
@@ -137,12 +136,12 @@ namespace EnvironmentVariables.Models
if (!EnvironmentVariablesHelper.UnsetVariableWithoutNotify(backupVariable))
{
Logger.LogError("Failed to unset backup variable.");
LoggerInstance.Logger.LogError("Failed to unset backup variable.");
}
if (!EnvironmentVariablesHelper.SetVariableWithoutNotify(variableToRestore))
{
Logger.LogError("Failed to restore backup variable.");
LoggerInstance.Logger.LogError("Failed to restore backup variable.");
}
}
}
@@ -163,14 +162,14 @@ namespace EnvironmentVariables.Models
// Backup the variable
if (!EnvironmentVariablesHelper.SetVariableWithoutNotify(variableToOverride))
{
Logger.LogError("Failed to set backup variable.");
LoggerInstance.Logger.LogError("Failed to set backup variable.");
}
}
}
if (!EnvironmentVariablesHelper.SetVariable(this))
{
Logger.LogError("Failed to set new variable.");
LoggerInstance.Logger.LogError("Failed to set new variable.");
}
}
});
@@ -197,7 +196,7 @@ namespace EnvironmentVariables.Models
const int MaxUserEnvVariableLength = 255; // User-wide env vars stored in the registry have names limited to 255 chars
if (ParentType != VariablesSetType.System && Name.Length >= MaxUserEnvVariableLength)
{
Logger.LogError("Variable name too long.");
LoggerInstance.Logger.LogError("Variable name too long.");
return false;
}

View File

@@ -7,9 +7,9 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Text.Json.Serialization;
using CommunityToolkit.Mvvm.ComponentModel;
using EnvironmentVariables.ViewModels;
using EnvironmentVariablesUILib.ViewModels;
namespace EnvironmentVariables.Models
namespace EnvironmentVariablesUILib.Models
{
public partial class VariablesSet : ObservableObject
{

View File

@@ -2,7 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace EnvironmentVariables.Models
namespace EnvironmentVariablesUILib.Models
{
public enum VariablesSetType
{

View File

@@ -0,0 +1,15 @@
// 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 EnvironmentVariablesUILib.Models;
namespace EnvironmentVariablesUILib.Telemetry
{
public interface ITelemetry
{
abstract void LogEnvironmentVariablesProfileEnabledEvent(bool enabled);
abstract void LogEnvironmentVariablesVariableChangedEvent(VariablesSetType type);
}
}

View File

@@ -0,0 +1,12 @@
// 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 EnvironmentVariablesUILib.Telemetry;
namespace EnvironmentVariablesUILib.Helpers
{
public static class TelemetryInstance
{
public static ITelemetry Telemetry { get; set; }
}
}

View File

@@ -10,14 +10,12 @@ using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using EnvironmentVariables.Helpers;
using EnvironmentVariables.Models;
using ManagedCommon;
using Microsoft.PowerToys.Telemetry;
using EnvironmentVariablesUILib.Helpers;
using EnvironmentVariablesUILib.Models;
using EnvironmentVariablesUILib.Telemetry;
using Microsoft.UI.Dispatching;
namespace EnvironmentVariables.ViewModels
namespace EnvironmentVariablesUILib.ViewModels
{
public partial class MainViewModel : ObservableObject
{
@@ -48,10 +46,15 @@ namespace EnvironmentVariables.ViewModels
public ProfileVariablesSet AppliedProfile { get; set; }
public MainViewModel(IEnvironmentVariablesService environmentVariablesService)
public MainViewModel(IElevationHelper elevationHelper, IEnvironmentVariablesService environmentVariablesService, ILogger logger, ITelemetry telemetry)
{
_environmentVariablesService = environmentVariablesService;
var isElevated = App.GetService<IElevationHelper>().IsElevated;
ElevationHelper.ElevationHelperInstance = elevationHelper;
LoggerInstance.Logger = logger;
TelemetryInstance.Telemetry = telemetry;
var isElevated = ElevationHelper.ElevationHelperInstance.IsElevated;
IsElevated = isElevated;
}
@@ -85,7 +88,6 @@ namespace EnvironmentVariables.ViewModels
}
}
[RelayCommand]
public void LoadEnvironmentVariables()
{
LoadDefaultVariables();
@@ -129,7 +131,7 @@ namespace EnvironmentVariables.ViewModels
catch (Exception ex)
{
// Show some error
Logger.LogError("Failed to load profiles.json file", ex);
LoggerInstance.Logger.LogError("Failed to load profiles.json file", ex);
Profiles = new ObservableCollection<ProfileVariablesSet>();
}
@@ -228,8 +230,7 @@ namespace EnvironmentVariables.ViewModels
});
});
PowerToysTelemetry.Log.WriteEvent(new Telemetry.EnvironmentVariablesVariableChangedEvent(original.ParentType));
TelemetryInstance.Telemetry.LogEnvironmentVariablesVariableChangedEvent(original.ParentType);
_ = Task.Run(SaveAsync);
}
}
@@ -276,7 +277,7 @@ namespace EnvironmentVariables.ViewModels
catch (Exception ex)
{
// Show some error
Logger.LogError("Failed to save to profiles.json file", ex);
LoggerInstance.Logger.LogError("Failed to save to profiles.json file", ex);
}
}
@@ -293,23 +294,13 @@ namespace EnvironmentVariables.ViewModels
UnsetAppliedProfile();
SetAppliedProfile(profile);
var telemetryEnabled = new Telemetry.EnvironmentVariablesProfileEnabledEvent()
{
Enabled = true,
};
PowerToysTelemetry.Log.WriteEvent(telemetryEnabled);
TelemetryInstance.Telemetry.LogEnvironmentVariablesProfileEnabledEvent(true);
}
else
{
UnsetAppliedProfile();
var telemetryEnabled = new Telemetry.EnvironmentVariablesProfileEnabledEvent()
{
Enabled = false,
};
PowerToysTelemetry.Log.WriteEvent(telemetryEnabled);
TelemetryInstance.Telemetry.LogEnvironmentVariablesProfileEnabledEvent(false);
}
}
}

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="EnvironmentVariables.app"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--The ID below informs the system that this application is compatible with OS features first introduced in Windows 8.
For more info see https://docs.microsoft.com/windows/win32/sysinfo/targeting-your-application-at-windows-8-1
It is also necessary to support features in unpackaged applications, for example the custom title bar implementation.-->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
</assembly>

View File

@@ -2,7 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Hosts.Models;
using HostsUILib.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Hosts.Tests

View File

@@ -33,7 +33,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Hosts\Hosts.csproj" />
<ProjectReference Include="..\HostsUILib\HostsUILib.csproj" />
</ItemGroup>
</Project>

View File

@@ -5,14 +5,13 @@
using System.IO.Abstractions.TestingHelpers;
using System.Linq;
using System.Threading.Tasks;
using Hosts.Exceptions;
using Hosts.Helpers;
using Hosts.Models;
using Hosts.Settings;
using Hosts.Tests.Mocks;
using HostsUILib.Exceptions;
using HostsUILib.Helpers;
using HostsUILib.Models;
using HostsUILib.Settings;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Settings.UI.Library.Enumerations;
namespace Hosts.Tests
{

View File

@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.Extensions.Hosting;
namespace Hosts.Helpers
{
public static class Host
{
public static IHost HostInstance
{
get; set;
}
public static T GetService<T>()
where T : class
{
if (HostInstance!.Services.GetService(typeof(T)) is not T service)
{
throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices within App.xaml.cs.");
}
return service;
}
}
}

View File

@@ -0,0 +1,43 @@
// 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 HostsUILib.Helpers;
using ManagedCommon;
namespace Hosts
{
internal sealed class LoggerWrapper : ILogger
{
public void LogDebug(string message)
{
Logger.LogDebug(message);
}
public void LogError(string message)
{
Logger.LogError(message);
}
public void LogError(string message, Exception ex)
{
Logger.LogError(message, ex);
}
public void LogInfo(string message)
{
Logger.LogInfo(message);
}
public void LogTrace()
{
Logger.LogTrace();
}
public void LogWarning(string message)
{
Logger.LogWarning(message);
}
}
}

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
@@ -16,15 +16,34 @@
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
<RootNamespace>Hosts</RootNamespace>
<AssemblyName>PowerToys.Hosts</AssemblyName>
<DefineConstants>DISABLE_XAML_GENERATED_MAIN,TRACE</DefineConstants>
<ApplicationIcon>Assets/Hosts/Hosts.ico</ApplicationIcon>
<SelfContained>true</SelfContained>
<ApplicationIcon>Assets/Hosts/Hosts.ico</ApplicationIcon>
<!-- 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.Hosts.pri</ProjectPriFileName>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\Hosts\AppList.scale-100.png" />
<None Remove="Assets\Hosts\AppList.scale-125.png" />
<None Remove="Assets\Hosts\AppList.scale-150.png" />
<None Remove="Assets\Hosts\AppList.scale-200.png" />
<None Remove="Assets\Hosts\AppList.scale-400.png" />
</ItemGroup>
<Target Name="CopyPRIFileToOutputDir" AfterTargets="Build">
<Message Text="Executing CopyPRIFileToOutputDir task" Importance="High" />
<ItemGroup>
<PRIFile Include="$(OutDir)**\PowerToys.Hosts.pri" />
</ItemGroup>
<Copy SourceFiles="@(PRIFile)" DestinationFolder="$(OutDir)" />
<Message Text="Copied CopyPRIFileToOutputDir files" Importance="High" />
</Target>
<ItemGroup>
<Page Remove="HostsXAML\App.xaml" />
</ItemGroup>
@@ -32,6 +51,10 @@
<ApplicationDefinition Include="HostsXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\Hosts\Hosts.ico" />
</ItemGroup>
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
@@ -46,38 +69,38 @@
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\Hosts\AppList.scale-100.png" />
<None Remove="Assets\Hosts\AppList.scale-125.png" />
<None Remove="Assets\Hosts\AppList.scale-150.png" />
<None Remove="Assets\Hosts\AppList.scale-200.png" />
<None Remove="Assets\Hosts\AppList.scale-400.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWinRT" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
<PackageReference Include="CommunityToolkit.WinUI.Extensions" />
<PackageReference Include="CommunityToolkit.WinUI.Collections" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
<PackageReference Include="Microsoft.Windows.CsWinRT" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" />
<PackageReference Include="System.IO.Abstractions" />
<PackageReference Include="WinUIEx" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnablePreviewMsixTooling)'=='true'">
<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
package has not yet been restored.
-->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
<ProjectReference Include="..\HostsUILib\HostsUILib.csproj" />
</ItemGroup>
<!--
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
Explorer "Package and Publish" context menu entry to be enabled for this project even if
the Windows App SDK Nuget package has not yet been restored.
-->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
</Project>

View File

@@ -1,4 +1,5 @@
<Application
<?xml version="1.0" encoding="utf-8" ?>
<Application
x:Class="Hosts.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -9,158 +10,7 @@
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<Style x:Key="SubtleButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter
x:Name="ContentPresenter"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AnimatedIcon.State="Normal"
AutomationProperties.AccessibilityView="Raw"
Background="{TemplateBinding Background}"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
CornerRadius="{TemplateBinding CornerRadius}"
Foreground="{TemplateBinding Foreground}">
<ContentPresenter.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</ContentPresenter.BackgroundTransition>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Other app resources here -->
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -1,48 +1,43 @@
// Copyright (c) Microsoft Corporation
// 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.IO.Abstractions;
using System.Threading;
using Hosts.Helpers;
using Hosts.Settings;
using Hosts.ViewModels;
using Hosts.Views;
using Common.UI;
using HostsUILib.Helpers;
using HostsUILib.Settings;
using HostsUILib.ViewModels;
using HostsUILib.Views;
using ManagedCommon;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using static HostsUILib.Settings.IUserSettings;
using Host = Hosts.Helpers.Host;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace Hosts
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
private Window _window;
public IHost Host
{
get;
}
public static T GetService<T>()
where T : class
{
if ((App.Current as App)!.Host.Services.GetService(typeof(T)) is not T service)
{
throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices within App.xaml.cs.");
}
return service;
}
/// <summary>
/// Initializes a new instance of the <see cref="App"/> class.
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
InitializeComponent();
Host = Microsoft.Extensions.Hosting.Host.
Host.HostInstance = Microsoft.Extensions.Hosting.Host.
CreateDefaultBuilder().
UseContentRoot(AppContext.BaseDirectory).
ConfigureServices((context, services) =>
@@ -50,28 +45,33 @@ namespace Hosts
// Core Services
services.AddSingleton<IFileSystem, FileSystem>();
services.AddSingleton<IHostsService, HostsService>();
services.AddSingleton<IUserSettings, UserSettings>();
services.AddSingleton<IUserSettings, Hosts.Settings.UserSettings>();
services.AddSingleton<IElevationHelper, ElevationHelper>();
// Views and ViewModels
services.AddTransient<MainPage>();
services.AddTransient<MainViewModel>();
services.AddSingleton<ILogger, LoggerWrapper>();
services.AddSingleton<IElevationHelper, ElevationHelper>();
services.AddSingleton<OpenSettingsFunction>(() =>
{
SettingsDeepLink.OpenSettings(SettingsDeepLink.SettingsWindow.Hosts, true);
});
services.AddSingleton<MainViewModel, MainViewModel>();
services.AddSingleton<HostsMainPage, HostsMainPage>();
}).
Build();
UnhandledException += App_UnhandledException;
var cleanupBackupThread = new Thread(() =>
{
// Delete old backups only if running elevated
if (!GetService<IElevationHelper>().IsElevated)
if (!Host.GetService<IElevationHelper>().IsElevated)
{
return;
}
try
{
GetService<IHostsService>().CleanupBackup();
Host.GetService<IHostsService>().CleanupBackup();
}
catch (Exception ex)
{
@@ -81,8 +81,14 @@ namespace Hosts
cleanupBackupThread.IsBackground = true;
cleanupBackupThread.Start();
UnhandledException += App_UnhandledException;
}
/// <summary>
/// Invoked when the application is launched.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
var cmdArgs = Environment.GetCommandLineArgs();
@@ -105,15 +111,17 @@ namespace Hosts
Logger.LogInfo($"Hosts started detached from PowerToys Runner.");
}
PowerToysTelemetry.Log.WriteEvent(new Hosts.Telemetry.HostsFileEditorOpenedEvent());
PowerToysTelemetry.Log.WriteEvent(new Telemetry.HostsFileEditorOpenedEvent());
_window = new MainWindow();
_window.Activate();
window = new MainWindow();
window.Activate();
}
private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
{
Logger.LogError("Unhandled exception", e.Exception);
}
private Window window;
}
}

View File

@@ -1,9 +1,8 @@
<winuiex:WindowEx
<winuiex:WindowEx
x:Class="Hosts.MainWindow"
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:Hosts"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:Hosts.Views"
xmlns:winuiex="using:WinUIEx"
@@ -15,7 +14,7 @@
<Window.SystemBackdrop>
<MicaBackdrop />
</Window.SystemBackdrop>
<Grid>
<Grid x:Name="MainGrid" Loaded="Grid_Loaded">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
@@ -42,7 +41,5 @@
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}" />
</Grid>
<views:MainPage Grid.Row="1" />
</Grid>
</winuiex:WindowEx>

View File

@@ -1,17 +1,28 @@
// Copyright (c) Microsoft Corporation
// 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 Hosts.Helpers;
using HostsUILib.Helpers;
using HostsUILib.Views;
using ManagedCommon;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.Windows.ApplicationModel.Resources;
using WinUIEx;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace Hosts
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : WindowEx
{
private HostsMainPage MainPage { get; }
public MainWindow()
{
InitializeComponent();
@@ -20,15 +31,18 @@ namespace Hosts
SetTitleBar(titleBar);
AppWindow.SetIcon("Assets/Hosts/Hosts.ico");
var loader = ResourceLoaderInstance.ResourceLoader;
var title = App.GetService<IElevationHelper>().IsElevated ? loader.GetString("WindowAdminTitle") : loader.GetString("WindowTitle");
var loader = new ResourceLoader("PowerToys.HostsUILib.pri", "PowerToys.HostsUILib/Resources");
var title = Host.GetService<IElevationHelper>().IsElevated ? loader.GetString("WindowAdminTitle") : loader.GetString("WindowTitle");
Title = title;
AppTitleTextBlock.Text = title;
var handle = this.GetWindowHandle();
WindowHelpers.BringToForeground(handle);
WindowHelpers.BringToForeground(handle);
Activated += MainWindow_Activated;
MainPage = Host.GetService<HostsMainPage>();
}
private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
@@ -42,5 +56,11 @@ namespace Hosts
AppTitleTextBlock.Foreground = (SolidColorBrush)App.Current.Resources["WindowCaptionForeground"];
}
}
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
MainGrid.Children.Add(MainPage);
Grid.SetRow(MainPage, 1);
}
}
}

View File

@@ -16,7 +16,6 @@ namespace Hosts
public static void Main(string[] args)
{
Logger.InitializeLogger("\\Hosts\\Logs");
WinRT.ComWrappersSupport.InitializeComWrappers();
if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredHostsFileEditorEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)

View File

@@ -5,10 +5,11 @@
using System;
using System.IO.Abstractions;
using System.Threading;
using HostsUILib.Helpers;
using HostsUILib.Settings;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Settings.UI.Library.Enumerations;
namespace Hosts.Settings
{
@@ -38,8 +39,10 @@ namespace Hosts.Settings
}
}
// Moved from Settings.UI.Library
public HostsAdditionalLinesPosition AdditionalLinesPosition { get; private set; }
// Moved from Settings.UI.Library
public HostsEncoding Encoding { get; set; }
public UserSettings()
@@ -72,6 +75,7 @@ namespace Hosts.Settings
if (!_settingsUtils.SettingsExists(HostsModuleName))
{
// Logger needs to be abstracted
Logger.LogInfo("Hosts settings.json was missing, creating a new one");
var defaultSettings = new HostsSettings();
defaultSettings.Save(_settingsUtils);
@@ -81,8 +85,8 @@ namespace Hosts.Settings
if (settings != null)
{
ShowStartupWarning = settings.Properties.ShowStartupWarning;
AdditionalLinesPosition = settings.Properties.AdditionalLinesPosition;
Encoding = settings.Properties.Encoding;
AdditionalLinesPosition = (HostsAdditionalLinesPosition)settings.Properties.AdditionalLinesPosition;
Encoding = (HostsEncoding)settings.Properties.Encoding;
LoopbackDuplicates = settings.Properties.LoopbackDuplicates;
}

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assembly manifestVersion="1.0"
xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="Hosts.app"/>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
@@ -18,4 +19,4 @@
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>
</assembly>

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

View File

@@ -2,7 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Hosts
namespace HostsUILib
{
public static class Consts
{

View File

@@ -4,7 +4,7 @@
using System;
namespace Hosts.Exceptions
namespace HostsUILib.Exceptions
{
public class NotRunningElevatedException : Exception
{

View File

@@ -4,7 +4,7 @@
using System;
namespace Hosts.Exceptions
namespace HostsUILib.Exceptions
{
public class ReadOnlyHostsException : Exception
{

View File

@@ -4,7 +4,7 @@
using System.Security.Principal;
namespace Hosts.Helpers
namespace HostsUILib.Helpers
{
public class ElevationHelper : IElevationHelper
{

View File

@@ -5,7 +5,7 @@
using System;
using System.Linq.Expressions;
namespace Hosts.Helpers
namespace HostsUILib.Helpers
{
// https://stackoverflow.com/a/22569086
public static class ExpressionExtensions

View File

@@ -13,14 +13,12 @@ using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Hosts.Exceptions;
using Hosts.Models;
using Hosts.Settings;
using ManagedCommon;
using HostsUILib.Exceptions;
using HostsUILib.Models;
using HostsUILib.Settings;
using Microsoft.Win32;
using Settings.UI.Library.Enumerations;
namespace Hosts.Helpers
namespace HostsUILib.Helpers
{
public class HostsService : IHostsService, IDisposable
{
@@ -277,7 +275,7 @@ namespace Hosts.Helpers
}
catch (Exception ex)
{
Logger.LogError("Failed to open default editor", ex);
LoggerInstance.Logger.LogError("Failed to open default editor", ex);
notepadFallback = true;
}
@@ -289,7 +287,7 @@ namespace Hosts.Helpers
}
catch (Exception ex)
{
Logger.LogError("Failed to open notepad", ex);
LoggerInstance.Logger.LogError("Failed to open notepad", ex);
}
}
}

View File

@@ -2,7 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Hosts.Helpers
namespace HostsUILib.Helpers
{
public interface IElevationHelper
{

View File

@@ -5,9 +5,9 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Hosts.Models;
using HostsUILib.Models;
namespace Hosts.Helpers
namespace HostsUILib.Helpers
{
public interface IHostsService : IDisposable
{

View File

@@ -0,0 +1,23 @@
// 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 HostsUILib.Helpers
{
public interface ILogger
{
public void LogError(string message);
public void LogError(string message, Exception ex);
public void LogWarning(string message);
public void LogInfo(string message);
public void LogDebug(string message);
public void LogTrace();
}
}

View File

@@ -0,0 +1,10 @@
// 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.
namespace HostsUILib.Helpers
{
public static class LoggerInstance
{
public static ILogger Logger { get; set; }
}
}

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Windows.ApplicationModel.Resources;
namespace RegistryPreview
namespace HostsUILib.Helpers
{
internal static class ResourceLoaderInstance
{
@@ -11,7 +11,7 @@ namespace RegistryPreview
static ResourceLoaderInstance()
{
ResourceLoader = new Microsoft.Windows.ApplicationModel.Resources.ResourceLoader("PowerToys.RegistryPreview.pri");
ResourceLoader = new Microsoft.Windows.ApplicationModel.Resources.ResourceLoader("PowerToys.HostsUILib.pri", "PowerToys.HostsUILib/Resources");
}
}
}

View File

@@ -2,7 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Hosts.Helpers
namespace HostsUILib.Helpers
{
public static class StringHelper
{

View File

@@ -5,7 +5,7 @@
using System;
using System.Text.RegularExpressions;
namespace Hosts.Helpers
namespace HostsUILib.Helpers
{
public static class ValidationHelper
{

View File

@@ -5,7 +5,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
namespace Hosts.Helpers
namespace HostsUILib.Helpers
{
// Taken from https://github.com/microsoft/microsoft-ui-xaml/blob/main/test/MUXControlsTestApp/Utilities/VisualTreeUtils.cs
// Original copyright header:

View File

@@ -1,14 +1,14 @@
<Page
x:Class="Hosts.Views.MainPage"
x:Class="HostsUILib.Views.HostsMainPage"
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:helpers="using:Hosts.Helpers"
xmlns:helpers="using:HostsUILib.Helpers"
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
xmlns:local="using:Hosts.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:Hosts.Models"
xmlns:models="using:HostsUILib.Models"
xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters"
xmlns:ui="using:CommunityToolkit.WinUI"
x:Name="Page"
@@ -21,21 +21,182 @@
</i:Interaction.Behaviors>
<Page.Resources>
<tkconverters:StringVisibilityConverter
x:Key="StringVisibilityConverter"
EmptyValue="Collapsed"
NotEmptyValue="Visible" />
<tkconverters:BoolNegationConverter x:Key="BoolNegationConverter" />
<tkconverters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<tkconverters:BoolToVisibilityConverter
x:Key="BoolToInvertedVisibilityConverter"
FalseValue="Visible"
TrueValue="Collapsed" />
<tkconverters:DoubleToVisibilityConverter
x:Key="DoubleToVisibilityConverter"
FalseValue="Visible"
GreaterThan="0"
TrueValue="Collapsed" />
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SubtleFillColorSecondary" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SubtleFillColorTertiary" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SubtleFillColorTransparent" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="TextFillColorPrimary" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="TextFillColorSecondary" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="TextFillColorDisabled" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="SubtleButtonBackground" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundPointerOver" ResourceKey="SystemColorHighlightTextColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundPressed" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBackgroundDisabled" ResourceKey="SystemControlBackgroundBaseLowBrush" />
<StaticResource x:Key="SubtleButtonBorderBrush" ResourceKey="SystemColorWindowColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushPointerOver" ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushPressed" ResourceKey="SystemColorHighlightColorBrush" />
<StaticResource x:Key="SubtleButtonBorderBrushDisabled" ResourceKey="SystemColorGrayTextColor" />
<StaticResource x:Key="SubtleButtonForeground" ResourceKey="SystemColorButtonTextColorBrush" />
<StaticResource x:Key="SubtleButtonForegroundPointerOver" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="SubtleButtonForegroundPressed" ResourceKey="SystemControlHighlightBaseHighBrush" />
<StaticResource x:Key="SubtleButtonForegroundDisabled" ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<Style x:Key="SubtleButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter
x:Name="ContentPresenter"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AnimatedIcon.State="Normal"
AutomationProperties.AccessibilityView="Raw"
Background="{TemplateBinding Background}"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
CornerRadius="{TemplateBinding CornerRadius}"
Foreground="{TemplateBinding Foreground}">
<ContentPresenter.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</ContentPresenter.BackgroundTransition>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="PointerOver" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Pressed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
<Setter Target="ContentPresenter.(AnimatedIcon.State)" Value="Normal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<tkconverters:StringVisibilityConverter
x:Key="StringVisibilityConverter"
EmptyValue="Collapsed"
NotEmptyValue="Visible" />
<tkconverters:BoolNegationConverter x:Key="BoolNegationConverter" />
<tkconverters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<tkconverters:BoolToVisibilityConverter
x:Key="BoolToInvertedVisibilityConverter"
FalseValue="Visible"
TrueValue="Collapsed" />
<tkconverters:DoubleToVisibilityConverter
x:Key="DoubleToVisibilityConverter"
FalseValue="Visible"
GreaterThan="0"
TrueValue="Collapsed" />
</ResourceDictionary>
</Page.Resources>
<Grid Margin="16" RowSpacing="8">

View File

@@ -6,18 +6,16 @@ using System;
using System.Threading.Tasks;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using Hosts.Helpers;
using Hosts.Models;
using Hosts.Settings;
using Hosts.ViewModels;
using ManagedCommon;
using HostsUILib.Helpers;
using HostsUILib.Models;
using HostsUILib.ViewModels;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
namespace Hosts.Views
namespace HostsUILib.Views
{
public sealed partial class MainPage : Page
public partial class HostsMainPage : Page
{
public MainViewModel ViewModel { get; private set; }
@@ -35,10 +33,11 @@ namespace Hosts.Views
public ICommand ExitCommand => new RelayCommand(() => { Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread().TryEnqueue(Application.Current.Exit); });
public MainPage()
public HostsMainPage(MainViewModel viewModel)
{
InitializeComponent();
ViewModel = App.GetService<MainViewModel>();
ViewModel = viewModel;
DataContext = ViewModel;
}
@@ -128,7 +127,9 @@ namespace Hosts.Views
private async void Page_Loaded(object sender, RoutedEventArgs e)
{
var userSettings = App.GetService<IUserSettings>();
ViewModel.ReadHosts();
var userSettings = ViewModel.UserSettings;
if (userSettings.ShowStartupWarning)
{
var resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
@@ -219,11 +220,14 @@ namespace Hosts.Views
{
// Based on the template from dev/CommonStyles/ContentDialog_themeresources.xaml in https://github.com/microsoft/microsoft-ui-xaml
var border = VisualTreeUtils.FindVisualChildByName(sender as ContentDialog, "BackgroundElement") as Border;
border.Margin = new Thickness(0, 32, 0, 0); // Should be the size reserved for the title bar as in MainWindow.xaml
if (border is not null)
{
border.Margin = new Thickness(0, 32, 0, 0); // Should be the size reserved for the title bar as in MainWindow.
}
}
catch (Exception ex)
{
Logger.LogError("Couldn't set the margin for a content dialog. It will appear on top of the title bar.", ex);
LoggerInstance.Logger.LogError("Couldn't set the margin for a content dialog. It will appear on top of the title bar.", ex);
}
}
}

View File

@@ -0,0 +1,69 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\Version.props" />
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net8.0-windows10.0.20348</TargetFramework>
<RootNamespace>HostsUILib</RootNamespace>
<UseWinUI>true</UseWinUI>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<AssemblyName>PowerToys.HostsUILib</AssemblyName>
<!-- 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.HostsUILib.pri</ProjectPriFileName>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
<IsPackable>true</IsPackable>
<Version>10.0.1</Version>
</PropertyGroup>
<ItemGroup>
<None Include="$(OutDir)\PowerToys.HostsUILib.pri" Pack="True" PackageCopyToOutput="True" PackagePath="contentFiles\any\$(TargetFramework)" />
<XBFFile Include="$(OutDir)**\*.xbf" />
<None Include="@(XBFFile)" Pack="True" PackageCopyToOutput="True" PackagePath="contentFiles\any\$(TargetFramework)" />
<None Include="$(OutDir)\PowerToys.HostsUILib.pdb" Pack="True" PackageCopyToOutput="true" PackagePath="lib/$(TargetFramework)" />
<None Include="Assets\**\*.png" Pack="true" PackageCopyToOutput="true" PackagePath="contentFiles\any\$(TargetFramework)\Assets" />
<None Include="Assets\**\*.ico" Pack="true" PackageCopyToOutput="true" PackagePath="contentFiles\any\$(TargetFramework)\Assets" />
</ItemGroup>
<ItemGroup>
<Content Remove="Assets\**\*.png" Pack="false" />
<Content Remove="Assets\**\*.ico" Pack="false" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" />
<PackageReference Include="CommunityToolkit.WinUI.Converters" />
<PackageReference Include="CommunityToolkit.WinUI.Collections" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" />
<PackageReference Include="System.IO.Abstractions" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnablePreviewMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Hosts.Models
namespace HostsUILib.Models
{
public enum AddressType
{

View File

@@ -6,9 +6,9 @@ using System;
using System.Net;
using System.Text;
using CommunityToolkit.Mvvm.ComponentModel;
using Hosts.Helpers;
using HostsUILib.Helpers;
namespace Hosts.Models
namespace HostsUILib.Models
{
public partial class Entry : ObservableObject
{

View File

@@ -5,7 +5,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Hosts.Models
namespace HostsUILib.Models
{
/// <summary>
/// Represents the parsed hosts file

View File

@@ -0,0 +1,12 @@
// 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.
namespace HostsUILib.Settings
{
public enum HostsAdditionalLinesPosition
{
Top = 0,
Bottom = 1,
}
}

View File

@@ -0,0 +1,12 @@
// 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.
namespace HostsUILib.Settings
{
public enum HostsEncoding
{
Utf8 = 0,
Utf8Bom = 1,
}
}

View File

@@ -3,9 +3,9 @@
// See the LICENSE file in the project root for more information.
using System;
using Settings.UI.Library.Enumerations;
using System.Net;
namespace Hosts.Settings
namespace HostsUILib.Settings
{
public interface IUserSettings
{
@@ -18,5 +18,7 @@ namespace Hosts.Settings
public HostsEncoding Encoding { get; }
event EventHandler LoopbackDuplicatesChanged;
public delegate void OpenSettingsFunction();
}
}

View File

@@ -10,19 +10,18 @@ using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Common.UI;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.WinUI;
using CommunityToolkit.WinUI.Collections;
using Hosts.Exceptions;
using Hosts.Helpers;
using Hosts.Models;
using Hosts.Settings;
using ManagedCommon;
using HostsUILib.Exceptions;
using HostsUILib.Helpers;
using HostsUILib.Models;
using HostsUILib.Settings;
using Microsoft.UI.Dispatching;
using static HostsUILib.Settings.IUserSettings;
namespace Hosts.ViewModels
namespace HostsUILib.ViewModels
{
public partial class MainViewModel : ObservableObject, IDisposable
{
@@ -90,13 +89,22 @@ namespace Hosts.ViewModels
public int NextId => _entries?.Count > 0 ? _entries.Max(e => e.Id) + 1 : 0;
public MainViewModel(IHostsService hostService, IUserSettings userSettings)
public IUserSettings UserSettings => _userSettings;
public static MainViewModel Instance { get; set; }
private OpenSettingsFunction _openSettingsFunction;
public MainViewModel(IHostsService hostService, IUserSettings userSettings, ILogger logger, OpenSettingsFunction openSettingsFunction)
{
_hostsService = hostService;
_userSettings = userSettings;
_hostsService.FileChanged += (s, e) => _dispatcherQueue.TryEnqueue(() => FileChanged = true);
_userSettings.LoopbackDuplicatesChanged += (s, e) => ReadHosts();
LoggerInstance.Logger = logger;
_openSettingsFunction = openSettingsFunction;
}
public void Add(Entry entry)
@@ -270,7 +278,7 @@ namespace Hosts.ViewModels
[RelayCommand]
public void OpenSettings()
{
SettingsDeepLink.OpenSettings(SettingsDeepLink.SettingsWindow.Hosts, true);
_openSettingsFunction();
}
[RelayCommand]
@@ -335,7 +343,7 @@ namespace Hosts.ViewModels
}
catch (OperationCanceledException)
{
Logger.LogInfo("FindDuplicates cancelled");
LoggerInstance.Logger.LogInfo("FindDuplicates cancelled");
return;
}
}
@@ -424,7 +432,7 @@ namespace Hosts.ViewModels
}
catch (Exception ex)
{
Logger.LogError("Failed to save hosts file", ex);
LoggerInstance.Logger.LogError("Failed to save hosts file", ex);
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
errorMessage = resourceLoader.GetString("FileSaveError_Generic");
}

View File

@@ -0,0 +1,33 @@
// 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 Microsoft.UI.Xaml;
using Windows.Data.Json;
using WinUIEx;
namespace RegistryPreview
{
public sealed partial class MainWindow : WindowEx
{
/// <summary>
/// Event handler to grab the main window's size and position before it closes
/// </summary>
private void AppWindow_Closing(Microsoft.UI.Windowing.AppWindow sender, Microsoft.UI.Windowing.AppWindowClosingEventArgs args)
{
jsonWindowPlacement.SetNamedValue("appWindow.Position.X", JsonValue.CreateNumberValue(appWindow.Position.X));
jsonWindowPlacement.SetNamedValue("appWindow.Position.Y", JsonValue.CreateNumberValue(appWindow.Position.Y));
jsonWindowPlacement.SetNamedValue("appWindow.Size.Width", JsonValue.CreateNumberValue(appWindow.Size.Width));
jsonWindowPlacement.SetNamedValue("appWindow.Size.Height", JsonValue.CreateNumberValue(appWindow.Size.Height));
}
/// <summary>
/// Event that is will prevent the app from closing if the "save file" flag is active
/// </summary>
public void Window_Closed(object sender, WindowEventArgs args)
{
// Save window placement
SaveWindowPlacementFile(settingsFolder, windowPlacementFile);
}
}
}

View File

@@ -0,0 +1,95 @@
// 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.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Windows.Storage;
using WinUIEx;
namespace RegistryPreview
{
public sealed partial class MainWindow : WindowEx
{
private void OpenWindowPlacementFile(string path, string filename)
{
string fileContents = string.Empty;
string storageFile = Path.Combine(path, filename);
if (File.Exists(storageFile))
{
try
{
StreamReader reader = new StreamReader(storageFile);
fileContents = reader.ReadToEnd();
reader.Close();
}
catch
{
// set up default JSON blob
fileContents = "{ }";
}
}
else
{
Task.Run(() => SaveWindowPlacementFile(path, filename)).GetAwaiter().GetResult();
}
try
{
jsonWindowPlacement = Windows.Data.Json.JsonObject.Parse(fileContents);
}
catch
{
// set up default JSON blob
fileContents = "{ }";
jsonWindowPlacement = Windows.Data.Json.JsonObject.Parse(fileContents);
}
}
/// <summary>
/// Save the window placement JSON blob out to a local file
/// </summary>
private async void SaveWindowPlacementFile(string path, string filename)
{
StorageFolder storageFolder = null;
StorageFile storageFile = null;
string fileContents = string.Empty;
try
{
storageFolder = await StorageFolder.GetFolderFromPathAsync(path);
}
catch (FileNotFoundException ex)
{
Debug.WriteLine(ex.Message);
Directory.CreateDirectory(path);
storageFolder = await StorageFolder.GetFolderFromPathAsync(path);
}
try
{
storageFile = await storageFolder.CreateFileAsync(filename, CreationCollisionOption.OpenIfExists);
}
catch (FileNotFoundException ex)
{
Debug.WriteLine(ex.Message);
storageFile = await storageFolder.CreateFileAsync(filename);
}
try
{
if (jsonWindowPlacement != null)
{
fileContents = jsonWindowPlacement.Stringify();
await Windows.Storage.FileIO.WriteTextAsync(storageFile, fileContents);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
}

View File

@@ -0,0 +1,88 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<RootNamespace>RegistryPreview</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;ARM64</Platforms>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<WindowsPackageType>None</WindowsPackageType>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<SelfContained>true</SelfContained>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps</OutputPath>
<AssemblyName>PowerToys.RegistryPreview</AssemblyName>
<ApplicationIcon>Assets\RegistryPreview\RegistryPreview.ico</ApplicationIcon>
<!-- 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.RegistryPreview.pri</ProjectPriFileName>
</PropertyGroup>
<ItemGroup>
<Page Remove="RegistryPreviewXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="RegistryPreviewXAML\App.xaml" />
</ItemGroup>
<ItemGroup>
<Folder Include="RegistryPreviewXAML\" />
</ItemGroup>
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls.DataGrid" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.Sizers" />
<PackageReference Include="CommunityToolkit.WinUI.Extensions" />
<PackageReference Include="Microsoft.WindowsAppSDK" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
<PackageReference Include="WinUIEx" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
package has not yet been restored.
-->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
<ProjectReference Include="..\RegistryPreviewUILib\RegistryPreviewUILib.csproj" />
</ItemGroup>
<Target Name="CopyPRIFileToOutputDir" AfterTargets="Build">
<Message Text="Executing CopyDLLs task" Importance="High" />
<ItemGroup>
<PRIFile Include="$(OutDir)**\PowerToys.RegistryPreviewUILib.pri" />
</ItemGroup>
<Copy SourceFiles="@(PRIFile)" DestinationFolder="$(OutDir)" />
<Message Text="Copied build files" Importance="High" />
</Target>
<!--
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
Explorer "Package and Publish" context menu entry to be enabled for this project even if
the Windows App SDK Nuget package has not yet been restored.
-->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
</Project>

View File

@@ -1,4 +1,5 @@
<Application
<?xml version="1.0" encoding="utf-8"?>
<Application
x:Class="RegistryPreview.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -7,9 +8,9 @@
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
<!-- Other app resources here -->
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -3,14 +3,13 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Web;
using Microsoft.UI.Xaml;
using Microsoft.Windows.AppLifecycle;
using Windows.ApplicationModel.Activation;
using LaunchActivatedEventArgs = Windows.ApplicationModel.Activation.LaunchActivatedEventArgs;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace RegistryPreview
{
/// <summary>
@@ -20,6 +19,8 @@ namespace RegistryPreview
{
/// <summary>
/// Initializes a new instance of the <see cref="App"/> class.
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
@@ -27,8 +28,7 @@ namespace RegistryPreview
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// Invoked when the application is launched.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)

View File

@@ -0,0 +1,52 @@
<winuiex:WindowEx
x:Class="RegistryPreview.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tk7controls="using:CommunityToolkit.WinUI.UI.Controls"
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
xmlns:ui="using:CommunityToolkit.WinUI"
xmlns:winuiex="using:WinUIEx"
MinWidth="480"
MinHeight="320"
Closed="Window_Closed"
mc:Ignorable="d">
<Window.SystemBackdrop>
<MicaBackdrop />
</Window.SystemBackdrop>
<Grid x:Name="MainGrid" Loaded="Grid_Loaded">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid
x:Name="titleBar"
Grid.Row="0"
Height="32"
Margin="16,0"
ColumnSpacing="16"
IsHitTestVisible="True">
<Grid.ColumnDefinitions>
<!--<ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>-->
<ColumnDefinition x:Name="IconColumn" Width="Auto" />
<ColumnDefinition x:Name="TitleColumn" Width="Auto" />
<!--<ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>-->
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
Width="16"
Height="16"
VerticalAlignment="Center"
Source="../Assets/RegistryPreview/RegistryPreview.ico" />
<TextBlock
x:Name="titleBarText"
Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding ApplicationTitle}" />
</Grid>
</Grid>
</winuiex:WindowEx>

Some files were not shown because too many files have changed in this diff Show More