mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-27 14:59:16 +08:00
[Settings]New Landing Page Experimentation (#22365)
Co-authored-by: Sophia Chen <sophia.six.chen@gmail.com> Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: Sophia Chen <sophchen@microsoft.com>
This commit is contained in:
parent
44e28886d7
commit
df521b4c9b
6
.github/actions/spell-check/expect.txt
vendored
6
.github/actions/spell-check/expect.txt
vendored
@ -163,6 +163,7 @@ bricelam
|
||||
BRIGHTGREEN
|
||||
Browsable
|
||||
bsd
|
||||
Bson
|
||||
bstr
|
||||
bthprops
|
||||
bti
|
||||
@ -221,6 +222,7 @@ CLASSNOTAVAILABLE
|
||||
clickable
|
||||
clickonce
|
||||
CLIENTEDGE
|
||||
clientid
|
||||
clientside
|
||||
CLIPCHILDREN
|
||||
Clipperton
|
||||
@ -347,6 +349,7 @@ DARKYELLOW
|
||||
datareader
|
||||
datatemplate
|
||||
Datavalue
|
||||
dataversion
|
||||
DATAW
|
||||
davidegiacometti
|
||||
Dayof
|
||||
@ -1859,6 +1862,7 @@ TRAYMOUSEMESSAGE
|
||||
triaging
|
||||
TRK
|
||||
trl
|
||||
TServer
|
||||
Tshuapa
|
||||
TStr
|
||||
Tuva
|
||||
@ -1911,6 +1915,7 @@ unmute
|
||||
UNORM
|
||||
unregistering
|
||||
unremapped
|
||||
Unstub
|
||||
unsubscribe
|
||||
unvirtualized
|
||||
Updatelayout
|
||||
@ -1936,6 +1941,7 @@ UYVY
|
||||
vabdq
|
||||
validmodulename
|
||||
Vanara
|
||||
variantassignment
|
||||
vcamp
|
||||
vccorlib
|
||||
vcdl
|
||||
|
3
.github/actions/spell-check/patterns.txt
vendored
3
.github/actions/spell-check/patterns.txt
vendored
@ -62,6 +62,9 @@ https?://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
|
||||
link\.medium\.com/[a-zA-Z0-9]+
|
||||
\bmedium\.com/\@[^/]+/[-\w]+
|
||||
|
||||
# experimentation urls
|
||||
https?://default\.exp-tas\.com/[-_a-zA-Z0-9/]*
|
||||
|
||||
publicKeyToken=(['"]|)[0-9a-f]+\g{-1}
|
||||
\@sha256:[0-9a-f]{64}\b
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
"PowerToys.Settings.UI.Lib.dll",
|
||||
"PowerToys.GPOWrapper.dll",
|
||||
"PowerToys.GPOWrapperProjection.dll",
|
||||
"PowerToys.AllExperiments.dll",
|
||||
|
||||
"modules\\AlwaysOnTop\\PowerToys.AlwaysOnTop.exe",
|
||||
"modules\\AlwaysOnTop\\PowerToys.AlwaysOnTopModuleInterface.dll",
|
||||
@ -202,6 +203,8 @@
|
||||
"Mono.Cecil.Mdb.dll",
|
||||
"Mono.Cecil.Pdb.dll",
|
||||
"Mono.Cecil.Rocks.dll",
|
||||
"Newtonsoft.Json.dll",
|
||||
"Newtonsoft.Json.Bson.dll",
|
||||
"NLog.dll",
|
||||
"HtmlAgilityPack.dll",
|
||||
"Markdig.Signed.dll",
|
||||
|
@ -228,6 +228,13 @@ steps:
|
||||
**\UnitTests-FancyZones.dll
|
||||
!**\obj\**
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: Trigger dotnet welcome message so that it does not cause errors on other scripts
|
||||
inputs:
|
||||
targetType: 'inline'
|
||||
script: |
|
||||
dotnet list $(build.sourcesdirectory)\src\common\Common.UI\Common.UI.csproj package
|
||||
|
||||
- task: PowerShell@2
|
||||
displayName: Verifying Notice.md and Nuget packages match
|
||||
inputs:
|
||||
|
@ -23,6 +23,7 @@ parameters:
|
||||
variables:
|
||||
IsPipeline: 1 # The installer uses this to detect whether it should pick up localizations
|
||||
SkipCppCodeAnalysis: 1 # Skip the code analysis to speed up release CI. It runs on PR CI, anyway
|
||||
IsExperimentationLive: 1 # The build and installer use this to turn on experimentation
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
resources:
|
||||
|
@ -38,6 +38,8 @@ $totalList = $projFiles | ForEach-Object -Parallel {
|
||||
|
||||
if($nugetTemp -is [array] -and $nugetTemp.count -gt 3)
|
||||
{
|
||||
# Need to debug this script? Uncomment this line.
|
||||
# Write-Host $csproj "`r`n" $nugetTemp "`r`n"
|
||||
$temp = New-Object System.Collections.ArrayList
|
||||
$temp.AddRange($nugetTemp)
|
||||
$temp.RemoveRange(0, 3)
|
||||
|
@ -57,4 +57,9 @@
|
||||
<PackageVersion Include="Vanara.PInvoke.Shell32" Version="3.4.11" />
|
||||
<PackageVersion Include="WinUIEx" Version="1.8.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(IsExperimentationLive)'!=''">
|
||||
<!-- Additional dependencies used by experimentation -->
|
||||
<PackageVersion Include="Microsoft.VariantAssignment.Client" Version="2.4.17140001" />
|
||||
<PackageVersion Include="Microsoft.VariantAssignment.Contract" Version="3.0.16990001" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -487,6 +487,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StlThumbnailProviderCpp", "
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SvgThumbnailProviderCpp", "src\modules\previewpane\SvgThumbnailProviderCpp\SvgThumbnailProviderCpp.vcxproj", "{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AllExperiments", "src\common\AllExperiments\AllExperiments.csproj", "{9CE59ED5-7087-4353-88EB-788038A73CEC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
@ -2022,6 +2024,18 @@ Global
|
||||
{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x64.Build.0 = Release|x64
|
||||
{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x86.ActiveCfg = Release|x64
|
||||
{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x86.Build.0 = Release|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Debug|x64.Build.0 = Debug|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Debug|x86.Build.0 = Debug|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Release|x64.ActiveCfg = Release|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Release|x64.Build.0 = Release|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Release|x86.ActiveCfg = Release|x64
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -2192,6 +2206,7 @@ Global
|
||||
{CA5518ED-0458-4B09-8F53-4122B9888655} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA} = {2F305555-C296-497E-AC20-5FA1B237996A}
|
||||
{9CE59ED5-7087-4353-88EB-788038A73CEC} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
@ -4,12 +4,15 @@
|
||||
|
||||
<?include $(sys.CURRENTDIR)\Common.wxi?>
|
||||
|
||||
<?define SettingsV2Files=WinUIEx.dll;backup_restore_settings.json;Ijwhost.dll;ColorCode.Core.dll;ColorCode.WinUI.dll;CommunityToolkit.Common.dll;CommunityToolkit.Labs.WinUI.SettingsControls.dll;CommunityToolkit.WinUI.dll;CommunityToolkit.WinUI.UI.Controls.Core.dll;CommunityToolkit.WinUI.UI.Controls.DataGrid.dll;CommunityToolkit.WinUI.UI.Controls.Input.dll;CommunityToolkit.WinUI.UI.Controls.Layout.dll;CommunityToolkit.WinUI.UI.Controls.Markdown.dll;CommunityToolkit.WinUI.UI.Controls.Media.dll;CommunityToolkit.WinUI.UI.Controls.Primitives.dll;CommunityToolkit.WinUI.UI.dll;icon.ico;Microsoft.Graphics.Canvas.Interop.dll;Microsoft.InteractiveExperiences.Projection.dll;Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll;Microsoft.Windows.ApplicationModel.Resources.Projection.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.System.Power.Projection.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.WinUI.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.Settings.deps.json;PowerToys.Settings.dll;PowerToys.Settings.exe;PowerToys.Settings.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;resources.pri;System.CodeDom.dll;System.IO.Abstractions.dll;WinRT.Runtime.dll;Microsoft.Graphics.Canvas.dll;System.Management.dll;PowerToys.GPOWrapper.dll;System.Text.Json.dll;WindowsBase.dll?>
|
||||
<?define SettingsV2Files=WinUIEx.dll;backup_restore_settings.json;Ijwhost.dll;ColorCode.Core.dll;ColorCode.WinUI.dll;CommunityToolkit.Common.dll;CommunityToolkit.Labs.WinUI.SettingsControls.dll;CommunityToolkit.WinUI.dll;CommunityToolkit.WinUI.UI.Controls.Core.dll;CommunityToolkit.WinUI.UI.Controls.DataGrid.dll;CommunityToolkit.WinUI.UI.Controls.Input.dll;CommunityToolkit.WinUI.UI.Controls.Layout.dll;CommunityToolkit.WinUI.UI.Controls.Markdown.dll;CommunityToolkit.WinUI.UI.Controls.Media.dll;CommunityToolkit.WinUI.UI.Controls.Primitives.dll;CommunityToolkit.WinUI.UI.dll;icon.ico;Microsoft.Graphics.Canvas.Interop.dll;Microsoft.InteractiveExperiences.Projection.dll;Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll;Microsoft.Windows.ApplicationModel.Resources.Projection.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.System.Power.Projection.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.WinUI.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.Settings.deps.json;PowerToys.Settings.dll;PowerToys.Settings.exe;PowerToys.Settings.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;resources.pri;System.CodeDom.dll;System.IO.Abstractions.dll;WinRT.Runtime.dll;Microsoft.Graphics.Canvas.dll;System.Management.dll;PowerToys.GPOWrapper.dll;System.Text.Json.dll;WindowsBase.dll;PowerToys.AllExperiments.dll?>
|
||||
<?define SettingsV2AssetsModulesFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PowerAccent.png;PowerOCR.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ScreenRuler.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<?define SettingsV2OOBEAssetsModulesFiles=ColorPicker.gif;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;FancyZones.gif;FileExplorer.png;FileLocksmith.gif;ImageResizer.gif;KBM.gif;MouseUtils.gif;PowerAccent.gif;PowerOCR.gif;PowerRename.gif;Run.gif;ScreenRuler.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
|
||||
<?define SettingsV2OOBEAssetsFluentIconsFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;Awake.png;FileExplorerPreview.png;FindMyMouse.png;Hosts.png;ImageResizer.png;KeyboardManager.png;MouseHighlighter.png;MouseCrosshairs.png;MouseUtils.png;PowerAccent.png;PowerOcr.png;PowerRename.png;PowerToys.png;PowerToysRun.png;ScreenRuler.png;Settings.png;ShortcutGuide.png;VideoConferenceMute.png?>
|
||||
<?define SettingsV2MicrosoftUIXamlAssetsInstallFiles=NoiseAsset_256x256_PNG.png?>
|
||||
|
||||
<!-- These files are needed for release builds to contain the experimentation DLLs -->
|
||||
<?define PowerToysExperimentsFiles=Microsoft.VariantAssignment.Client.dll;Microsoft.VariantAssignment.Contract.dll;System.Net.Http.Formatting.dll;Microsoft.Extensions.Configuration.dll;Microsoft.Extensions.Configuration.Abstractions.dll;Microsoft.Extensions.Configuration.Binder.dll;Microsoft.Extensions.DependencyInjection.Abstractions.dll;Microsoft.Extensions.Http.dll;Microsoft.Extensions.Logging.dll;Microsoft.Extensions.Logging.Abstractions.dll;Microsoft.Extensions.Options.dll;Microsoft.Extensions.Primitives.dll;Newtonsoft.Json.dll;Newtonsoft.Json.Bson.dll?>
|
||||
|
||||
<Fragment>
|
||||
<!-- SettingsV2 components -->
|
||||
<DirectoryRef Id="SettingsV2InstallFolder" FileSource="$(var.BinDir)Settings\">
|
||||
@ -18,6 +21,13 @@
|
||||
<File Id="SV2_$(var.File)" Source="$(var.BinDir)Settings\$(var.File)" />
|
||||
</Component>
|
||||
<?endforeach?>
|
||||
<?ifdef env.IsExperimentationLive?>
|
||||
<?foreach File in $(var.PowerToysExperimentsFiles)?>
|
||||
<Component Id="SV2CE_$(var.File)" Win64="yes">
|
||||
<File Id="SV2E_$(var.File)" Source="$(var.BinDir)Settings\$(var.File)" />
|
||||
</Component>
|
||||
<?endforeach?>
|
||||
<?endif?>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2AssetsInstallFolder" FileSource="$(var.BinDir)Settings\Assets">
|
||||
<Component Id="SettingsV2Assets_LogoScale200" Win64="yes">
|
||||
@ -78,6 +88,11 @@
|
||||
<?foreach File in $(var.SettingsV2Files)?>
|
||||
<ComponentRef Id="SV2C_$(var.File)" />
|
||||
<?endforeach?>
|
||||
<?ifdef env.IsExperimentationLive?>
|
||||
<?foreach File in $(var.PowerToysExperimentsFiles)?>
|
||||
<ComponentRef Id="SV2CE_$(var.File)" />
|
||||
<?endforeach?>
|
||||
<?endif?>
|
||||
<ComponentRef Id="SettingsV2Assets_LogoScale200" />
|
||||
<ComponentRef Id="SettingsV2Assets_SplashScreen" />
|
||||
<ComponentRef Id="SettingsV2Assets_StoreLogo_Scale100" />
|
||||
|
27
src/common/AllExperiments/AllExperiments.csproj
Normal file
27
src/common/AllExperiments/AllExperiments.csproj
Normal file
@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TargetName>PowerToys.AllExperiments</TargetName>
|
||||
<MockDirectory>.\Microsoft.VariantAssignment\</MockDirectory>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Experimentation is live, forcing inclusion -->
|
||||
<ItemGroup Condition="'$(IsExperimentationLive)'!=''">
|
||||
<!-- Newtonsoft.Json is included and a version specified in Directory.Packages.props to avoid a vulnerability from older versions. -->
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
<PackageReference Include="Microsoft.VariantAssignment.Client" />
|
||||
<PackageReference Include="Microsoft.VariantAssignment.Contract" />
|
||||
<Compile Remove=".\$(MockDirectory)\Client\*.cs" />
|
||||
<Compile Remove=".\$(MockDirectory)\Contract\*.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
211
src/common/AllExperiments/Experiments.cs
Normal file
211
src/common/AllExperiments/Experiments.cs
Normal file
@ -0,0 +1,211 @@
|
||||
// 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.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.VariantAssignment.Client;
|
||||
using Microsoft.VariantAssignment.Contract;
|
||||
using Windows.System.Profile;
|
||||
|
||||
namespace AllExperiments
|
||||
{
|
||||
// The dependencies required to build this project are only available in the official build pipeline and are internal to Microsoft.
|
||||
// However, this project is not required to build a test version of the application.
|
||||
public class Experiments
|
||||
{
|
||||
public enum ExperimentState
|
||||
{
|
||||
Enabled,
|
||||
Disabled,
|
||||
NotLoaded,
|
||||
}
|
||||
|
||||
#pragma warning disable SA1401 // Need to use LandingPageExperiment as a static property in OobeShellPage.xaml.cs
|
||||
public static ExperimentState LandingPageExperiment = ExperimentState.NotLoaded;
|
||||
#pragma warning restore SA1401
|
||||
|
||||
public async Task<bool> EnableLandingPageExperimentAsync()
|
||||
{
|
||||
if (Experiments.LandingPageExperiment != ExperimentState.NotLoaded)
|
||||
{
|
||||
return Experiments.LandingPageExperiment == ExperimentState.Enabled;
|
||||
}
|
||||
|
||||
Experiments varServ = new Experiments();
|
||||
await varServ.VariantAssignmentProvider_Initialize();
|
||||
var landingPageExperiment = varServ.IsExperiment;
|
||||
|
||||
Experiments.LandingPageExperiment = landingPageExperiment ? ExperimentState.Enabled : ExperimentState.Disabled;
|
||||
|
||||
return landingPageExperiment;
|
||||
}
|
||||
|
||||
private async Task VariantAssignmentProvider_Initialize()
|
||||
{
|
||||
IsExperiment = false;
|
||||
string jsonFilePath = CreateFilePath();
|
||||
|
||||
var vaSettings = new VariantAssignmentClientSettings
|
||||
{
|
||||
Endpoint = new Uri("https://default.exp-tas.com/exptas77/a7a397e7-6fbe-4f21-a4e9-3f542e4b000e-exppowertoys/api/v1/tas"),
|
||||
EnableCaching = true,
|
||||
ResponseCacheTime = TimeSpan.FromMinutes(5),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var vaClient = vaSettings.GetTreatmentAssignmentServiceClient();
|
||||
var vaRequest = GetVariantAssignmentRequest();
|
||||
using var variantAssignments = await vaClient.GetVariantAssignmentsAsync(vaRequest).ConfigureAwait(false);
|
||||
|
||||
if (variantAssignments.AssignedVariants.Count != 0)
|
||||
{
|
||||
var dataVersion = variantAssignments.DataVersion;
|
||||
var featureVariables = variantAssignments.GetFeatureVariables();
|
||||
var assignmentContext = variantAssignments.GetAssignmentContext();
|
||||
var featureFlagValue = featureVariables[0].GetStringValue();
|
||||
|
||||
var experimentGroup = string.Empty;
|
||||
string json = File.ReadAllText(jsonFilePath);
|
||||
var jsonDictionary = JsonSerializer.Deserialize<Dictionary<string, object>>(json);
|
||||
|
||||
if (jsonDictionary != null)
|
||||
{
|
||||
if (!jsonDictionary.ContainsKey("dataversion"))
|
||||
{
|
||||
jsonDictionary.Add("dataversion", dataVersion);
|
||||
}
|
||||
|
||||
if (!jsonDictionary.ContainsKey("variantassignment"))
|
||||
{
|
||||
jsonDictionary.Add("variantassignment", featureFlagValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var jsonDataVersion = jsonDictionary["dataversion"].ToString();
|
||||
if (jsonDataVersion != null && int.Parse(jsonDataVersion) < dataVersion)
|
||||
{
|
||||
jsonDictionary["dataversion"] = dataVersion;
|
||||
jsonDictionary["variantassignment"] = featureFlagValue;
|
||||
}
|
||||
}
|
||||
|
||||
experimentGroup = jsonDictionary["variantassignment"].ToString();
|
||||
|
||||
string output = JsonSerializer.Serialize(jsonDictionary);
|
||||
File.WriteAllText(jsonFilePath, output);
|
||||
}
|
||||
|
||||
if (experimentGroup == "alternate" && AssignmentUnit != string.Empty)
|
||||
{
|
||||
IsExperiment = true;
|
||||
}
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new OobeVariantAssignmentEvent() { AssignmentContext = assignmentContext, ClientID = AssignmentUnit });
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
string json = File.ReadAllText(jsonFilePath);
|
||||
var jsonDictionary = JsonSerializer.Deserialize<Dictionary<string, object>>(json);
|
||||
|
||||
if (jsonDictionary != null)
|
||||
{
|
||||
if (jsonDictionary.ContainsKey("variantassignment"))
|
||||
{
|
||||
if (jsonDictionary["variantassignment"].ToString() == "alternate" && AssignmentUnit != string.Empty)
|
||||
{
|
||||
IsExperiment = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonDictionary["variantassignment"] = "current";
|
||||
}
|
||||
}
|
||||
|
||||
string output = JsonSerializer.Serialize(jsonDictionary);
|
||||
File.WriteAllText(jsonFilePath, output);
|
||||
|
||||
Logger.LogError("Error getting to TAS endpoint", ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Error getting variant assignments for experiment", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsExperiment { get; set; }
|
||||
|
||||
private string? AssignmentUnit { get; set; }
|
||||
|
||||
private IVariantAssignmentRequest GetVariantAssignmentRequest()
|
||||
{
|
||||
var jsonFilePath = CreateFilePath();
|
||||
try
|
||||
{
|
||||
if (!File.Exists(jsonFilePath))
|
||||
{
|
||||
AssignmentUnit = Guid.NewGuid().ToString();
|
||||
var data = new Dictionary<string, string>()
|
||||
{
|
||||
["clientid"] = AssignmentUnit,
|
||||
};
|
||||
string jsonData = JsonSerializer.Serialize(data);
|
||||
File.WriteAllText(jsonFilePath, jsonData);
|
||||
}
|
||||
else
|
||||
{
|
||||
string json = File.ReadAllText(jsonFilePath);
|
||||
var jsonDictionary = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(json);
|
||||
if (jsonDictionary != null)
|
||||
{
|
||||
AssignmentUnit = jsonDictionary["clientid"]?.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Error creating/getting AssignmentUnit", ex);
|
||||
}
|
||||
|
||||
var attrNames = new List<string> { "FlightRing", "c:InstallLanguage" };
|
||||
var attrData = AnalyticsInfo.GetSystemPropertiesAsync(attrNames).AsTask().GetAwaiter().GetResult();
|
||||
|
||||
var flightRing = string.Empty;
|
||||
var installLanguage = string.Empty;
|
||||
|
||||
if (attrData.ContainsKey("FlightRing"))
|
||||
{
|
||||
flightRing = attrData["FlightRing"];
|
||||
}
|
||||
|
||||
if (attrData.ContainsKey("InstallLanguage"))
|
||||
{
|
||||
installLanguage = attrData["InstallLanguage"];
|
||||
}
|
||||
|
||||
return new VariantAssignmentRequest
|
||||
{
|
||||
Parameters =
|
||||
{
|
||||
{ "installLanguage", installLanguage },
|
||||
{ "flightRing", flightRing },
|
||||
{ "clientid", AssignmentUnit },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private string CreateFilePath()
|
||||
{
|
||||
var exeDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var settingsPath = @"Microsoft\PowerToys\experimentation.json";
|
||||
var filePath = Path.Combine(exeDir, settingsPath);
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
}
|
81
src/common/AllExperiments/Logger.cs
Normal file
81
src/common/AllExperiments/Logger.cs
Normal file
@ -0,0 +1,81 @@
|
||||
// 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.Globalization;
|
||||
using System.IO.Abstractions;
|
||||
|
||||
namespace AllExperiments
|
||||
{
|
||||
public static class Logger
|
||||
{
|
||||
private static readonly IFileSystem FileSystem = new FileSystem();
|
||||
private static readonly IPath Path = FileSystem.Path;
|
||||
private static readonly IDirectory Directory = FileSystem.Directory;
|
||||
|
||||
private static readonly string ApplicationLogPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\PowerToys\\Settings Logs\\Experimentation");
|
||||
|
||||
static Logger()
|
||||
{
|
||||
if (!Directory.Exists(ApplicationLogPath))
|
||||
{
|
||||
Directory.CreateDirectory(ApplicationLogPath);
|
||||
}
|
||||
|
||||
// Using InvariantCulture since this is used for a log file name
|
||||
var logFilePath = Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".txt");
|
||||
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));
|
||||
|
||||
Trace.AutoFlush = true;
|
||||
}
|
||||
|
||||
public static void LogInfo(string message)
|
||||
{
|
||||
Log(message, "INFO");
|
||||
}
|
||||
|
||||
public static void LogError(string message)
|
||||
{
|
||||
Log(message, "ERROR");
|
||||
#if DEBUG
|
||||
Debugger.Break();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void LogError(string message, Exception e)
|
||||
{
|
||||
Log(
|
||||
message + Environment.NewLine +
|
||||
e?.Message + Environment.NewLine +
|
||||
"Inner exception: " + Environment.NewLine +
|
||||
e?.InnerException?.Message + Environment.NewLine +
|
||||
"Stack trace: " + Environment.NewLine +
|
||||
e?.StackTrace,
|
||||
"ERROR");
|
||||
#if DEBUG
|
||||
Debugger.Break();
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void Log(string message, string type)
|
||||
{
|
||||
Trace.WriteLine(type + ": " + DateTime.Now.TimeOfDay);
|
||||
Trace.Indent();
|
||||
Trace.WriteLine(GetCallerInfo());
|
||||
Trace.WriteLine(message);
|
||||
Trace.Unindent();
|
||||
}
|
||||
|
||||
private static string GetCallerInfo()
|
||||
{
|
||||
StackTrace stackTrace = new StackTrace();
|
||||
|
||||
var methodName = stackTrace.GetFrame(3)?.GetMethod();
|
||||
var className = methodName?.DeclaringType?.Name;
|
||||
return "[Method]: " + methodName?.Name + " [Class]: " + className;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
// 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.VariantAssignment.Contract;
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Client
|
||||
{
|
||||
#pragma warning disable SA1200 // Using directives should be placed correctly
|
||||
using TreatmentAssignmentServiceClient = VariantAssignmentServiceClient<TreatmentAssignmentServiceResponse>;
|
||||
#pragma warning restore SA1200 // Using directives should be placed correctly
|
||||
|
||||
public static class VariantAssignmentClientExtensionMethods
|
||||
{
|
||||
public static IVariantAssignmentProvider GetTreatmentAssignmentServiceClient(this VariantAssignmentClientSettings settings)
|
||||
{
|
||||
return new TreatmentAssignmentServiceClient();
|
||||
}
|
||||
}
|
||||
}
|
@ -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 Microsoft.VariantAssignment.Contract;
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Client
|
||||
{
|
||||
internal partial class VariantAssignmentServiceClient<TServerResponse> : IVariantAssignmentProvider, IDisposable
|
||||
where TServerResponse : VariantAssignmentServiceResponse
|
||||
{
|
||||
public void Dispose()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IVariantAssignmentResponse> GetVariantAssignmentsAsync(IVariantAssignmentRequest request, CancellationToken ct = default)
|
||||
{
|
||||
return Task.FromResult(EmptyVariantAssignmentResponse.Instance);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
public class EmptyVariantAssignmentResponse : IVariantAssignmentResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton instance of <see cref="EmptyVariantAssignmentResponse"/>.
|
||||
/// </summary>
|
||||
public static readonly IVariantAssignmentResponse Instance = new EmptyVariantAssignmentResponse();
|
||||
|
||||
public EmptyVariantAssignmentResponse()
|
||||
{
|
||||
}
|
||||
|
||||
public long DataVersion => 0;
|
||||
|
||||
public string Thumbprint => string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReadOnlyCollection<IAssignedVariant> AssignedVariants => Array.Empty<IAssignedVariant>();
|
||||
|
||||
/// <inheritdoc/>
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
public IFeatureVariable GetFeatureVariable(IReadOnlyList<string> path) => null;
|
||||
#pragma warning restore CS8603 // Possible null reference return.
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IReadOnlyList<IFeatureVariable> GetFeatureVariables(IReadOnlyList<string> prefix) => Array.Empty<IFeatureVariable>();
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
string IVariantAssignmentResponse.GetAssignmentContext()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
IReadOnlyList<IFeatureVariable> IVariantAssignmentResponse.GetFeatureVariables()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
// 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.
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
public interface IAssignedVariant
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
// 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.
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
public interface IFeatureVariable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the variable's value as a string.
|
||||
/// </summary>
|
||||
/// <returns>String value of the variable.</returns>
|
||||
string GetStringValue();
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
// 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.
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
public interface IVariantAssignmentProvider : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes variant assignments based on <paramref name="request"/> data.
|
||||
/// </summary>
|
||||
/// <param name="request">Variant assignment parameters.</param>
|
||||
/// <param name="ct">Propagates notification that operations should be canceled.</param>
|
||||
/// <returns>An awaitable task that returns a <see cref="IVariantAssignmentResponse"/>.</returns>
|
||||
Task<IVariantAssignmentResponse> GetVariantAssignmentsAsync(IVariantAssignmentRequest request, CancellationToken ct = default);
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
public interface IVariantAssignmentRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets inputs used for evaluating filters, assignment units, etc.
|
||||
/// </summary>
|
||||
IReadOnlyCollection<(string Key, string Value)> Parameters { get; }
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
/// <summary>
|
||||
/// Snapshot of variant assignments.
|
||||
/// </summary>
|
||||
public interface IVariantAssignmentResponse : IDisposable
|
||||
{
|
||||
///// <summary>
|
||||
///// Gets the serial number of variant assignment configuration snapshot used when assigning variants.
|
||||
///// </summary>
|
||||
long DataVersion { get; }
|
||||
|
||||
///// <summary>
|
||||
///// Get a hash of the response suitable for caching.
|
||||
///// </summary>
|
||||
// string Thumbprint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the variants assigned based on request parameters and a variant configuration snapshot.
|
||||
/// </summary>
|
||||
IReadOnlyCollection<IAssignedVariant> AssignedVariants { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets feature variables assigned by variants in this response.
|
||||
/// </summary>
|
||||
/// <param name="prefix">(Optional) Filter feature variables where <see cref="IFeatureVariable.KeySegments"/> contains the <paramref name="prefix"/>.</param>
|
||||
/// <returns>Range of matching feature variables.</returns>
|
||||
IReadOnlyList<IFeatureVariable> GetFeatureVariables(IReadOnlyList<string> prefix);
|
||||
|
||||
// this actually part of the interface but gets the job done
|
||||
IReadOnlyList<IFeatureVariable> GetFeatureVariables();
|
||||
|
||||
// this actually part of the interface but gets the job done
|
||||
string GetAssignmentContext();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single feature variable assigned by variants in this response.
|
||||
/// </summary>
|
||||
/// <param name="path">Exact feature variable path.</param>
|
||||
/// <returns>Matching feature variable or null.</returns>
|
||||
IFeatureVariable GetFeatureVariable(IReadOnlyList<string> path);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
// 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.
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
internal class TreatmentAssignmentServiceResponse : VariantAssignmentServiceResponse
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
// 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.ComponentModel.DataAnnotations;
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration for variant assignment service client.
|
||||
/// </summary>
|
||||
public class VariantAssignmentClientSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the variant assignment service endpoint URL.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Uri? Endpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether gets or sets a value whether client side request caching should be enabled.
|
||||
/// </summary>
|
||||
public bool EnableCaching { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the the maximum time a cached variant assignment response may be used without re-validating.
|
||||
/// </summary>
|
||||
public TimeSpan ResponseCacheTime { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
// 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.Collections.Specialized;
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
public class VariantAssignmentRequest : IVariantAssignmentRequest
|
||||
{
|
||||
private NameValueCollection _parameters = new NameValueCollection();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets mutable <see cref="IVariantAssignmentRequest.Parameters"/>.
|
||||
/// </summary>
|
||||
public NameValueCollection Parameters { get => _parameters; set => _parameters = value; }
|
||||
|
||||
IReadOnlyCollection<(string Key, string Value)> IVariantAssignmentRequest.Parameters => (IReadOnlyCollection<(string Key, string Value)>)_parameters;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
// The goal of this class is to just mock out the Microsoft.VariantAssignment close source objects
|
||||
namespace Microsoft.VariantAssignment.Contract
|
||||
{
|
||||
/// <summary>
|
||||
/// Mutable implementation of <see cref="IVariantAssignmentResponse"/> for (de)serialization.
|
||||
/// </summary>
|
||||
internal class VariantAssignmentServiceResponse : IVariantAssignmentResponse, IDisposable
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public virtual long DataVersion { get; set; }
|
||||
|
||||
public virtual IReadOnlyCollection<IAssignedVariant> AssignedVariants { get; set; } = Array.Empty<IAssignedVariant>();
|
||||
|
||||
public IFeatureVariable GetFeatureVariable(IReadOnlyList<string> path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IReadOnlyList<IFeatureVariable> GetFeatureVariables(IReadOnlyList<string> prefix)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public IReadOnlyList<IFeatureVariable> GetFeatureVariables()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string GetAssignmentContext()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
static std::wstring settings_theme = L"system";
|
||||
static bool run_as_elevated = false;
|
||||
static bool download_updates_automatically = true;
|
||||
static bool enable_experimentation = true;
|
||||
|
||||
json::JsonObject GeneralSettings::to_json()
|
||||
{
|
||||
@ -37,6 +38,7 @@ json::JsonObject GeneralSettings::to_json()
|
||||
result.SetNamedValue(L"is_elevated", json::value(isElevated));
|
||||
result.SetNamedValue(L"run_elevated", json::value(isRunElevated));
|
||||
result.SetNamedValue(L"download_updates_automatically", json::value(downloadUpdatesAutomatically));
|
||||
result.SetNamedValue(L"enable_experimentation", json::value(enableExperimentation));
|
||||
result.SetNamedValue(L"is_admin", json::value(isAdmin));
|
||||
result.SetNamedValue(L"theme", json::value(theme));
|
||||
result.SetNamedValue(L"system_theme", json::value(systemTheme));
|
||||
@ -55,6 +57,7 @@ json::JsonObject load_general_settings()
|
||||
}
|
||||
run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false);
|
||||
download_updates_automatically = loaded.GetNamedBoolean(L"download_updates_automatically", true) && check_user_is_admin();
|
||||
enable_experimentation = loaded.GetNamedBoolean(L"enable_experimentation",true);
|
||||
|
||||
return loaded;
|
||||
}
|
||||
@ -67,6 +70,7 @@ GeneralSettings get_general_settings()
|
||||
.isRunElevated = run_as_elevated,
|
||||
.isAdmin = is_user_admin,
|
||||
.downloadUpdatesAutomatically = download_updates_automatically && is_user_admin,
|
||||
.enableExperimentation = enable_experimentation,
|
||||
.theme = settings_theme,
|
||||
.systemTheme = WindowsColors::is_dark_mode() ? L"dark" : L"light",
|
||||
.powerToysVersion = get_product_version()
|
||||
@ -89,6 +93,8 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
|
||||
|
||||
download_updates_automatically = general_configs.GetNamedBoolean(L"download_updates_automatically", true);
|
||||
|
||||
enable_experimentation = general_configs.GetNamedBoolean(L"enable_experimentation", true);
|
||||
|
||||
if (json::has(general_configs, L"startup", json::JsonValueType::Boolean))
|
||||
{
|
||||
const bool startup = general_configs.GetNamedBoolean(L"startup");
|
||||
|
@ -11,6 +11,7 @@ struct GeneralSettings
|
||||
bool isRunElevated;
|
||||
bool isAdmin;
|
||||
bool downloadUpdatesAutomatically;
|
||||
bool enableExperimentation;
|
||||
std::wstring theme;
|
||||
std::wstring systemTheme;
|
||||
std::wstring powerToysVersion;
|
||||
|
@ -56,6 +56,7 @@ void Trace::SettingsChanged(const GeneralSettings& settings)
|
||||
TraceLoggingWideString(enabledModules.c_str(), "ModulesEnabled"),
|
||||
TraceLoggingBoolean(settings.isRunElevated, "AlwaysRunElevated"),
|
||||
TraceLoggingBoolean(settings.downloadUpdatesAutomatically, "DownloadUpdatesAutomatically"),
|
||||
TraceLoggingBoolean(settings.enableExperimentation, "EnableExperimentation"),
|
||||
TraceLoggingWideString(settings.theme.c_str(), "Theme"),
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||
|
@ -49,12 +49,16 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
[JsonPropertyName("download_updates_automatically")]
|
||||
public bool AutoDownloadUpdates { get; set; }
|
||||
|
||||
[JsonPropertyName("enable_experimentation")]
|
||||
public bool EnableExperimentation { get; set; }
|
||||
|
||||
public GeneralSettings()
|
||||
{
|
||||
Startup = false;
|
||||
IsAdmin = false;
|
||||
IsElevated = false;
|
||||
AutoDownloadUpdates = false;
|
||||
EnableExperimentation = true;
|
||||
Theme = "system";
|
||||
SystemTheme = "light";
|
||||
try
|
||||
|
@ -0,0 +1,21 @@
|
||||
// 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.Tracing;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events
|
||||
{
|
||||
[EventData]
|
||||
public class OobeVariantAssignmentEvent : EventBase, IEvent
|
||||
{
|
||||
public string AssignmentContext { get; set; }
|
||||
|
||||
public string ClientID { get; set; }
|
||||
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<RuntimeIdentifiers>win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<Version>$(Version).0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 931 B |
@ -10,12 +10,13 @@
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="280" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Image
|
||||
x:Name="HeaderImage"
|
||||
Height="{x:Bind HeroImageHeight}"
|
||||
Source="{x:Bind HeroImage}"
|
||||
Stretch="UniformToFill" />
|
||||
|
||||
@ -23,9 +24,7 @@
|
||||
Grid.Row="1"
|
||||
Padding="32,24,32,24"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel
|
||||
VerticalAlignment="Top"
|
||||
Orientation="Vertical">
|
||||
<StackPanel VerticalAlignment="Top" Orientation="Vertical">
|
||||
|
||||
<TextBlock
|
||||
x:Name="TitleTxt"
|
||||
|
@ -32,6 +32,12 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||
set => SetValue(HeroImageProperty, value);
|
||||
}
|
||||
|
||||
public double HeroImageHeight
|
||||
{
|
||||
get { return (double)GetValue(HeroImageHeightProperty); }
|
||||
set { SetValue(HeroImageHeightProperty, value); }
|
||||
}
|
||||
|
||||
public object PageContent
|
||||
{
|
||||
get { return (object)GetValue(PageContentProperty); }
|
||||
@ -42,5 +48,6 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
|
||||
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(SettingsPageControl), new PropertyMetadata(default(string)));
|
||||
public static readonly DependencyProperty HeroImageProperty = DependencyProperty.Register("HeroImage", typeof(string), typeof(SettingsPageControl), new PropertyMetadata(default(string)));
|
||||
public static readonly DependencyProperty PageContentProperty = DependencyProperty.Register("PageContent", typeof(object), typeof(SettingsPageControl), new PropertyMetadata(new Grid()));
|
||||
public static readonly DependencyProperty HeroImageHeightProperty = DependencyProperty.Register("HeroImageHeight", typeof(double), typeof(SettingsPageControl), new PropertyMetadata(280.0));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,193 @@
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobeOverviewAlternate"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.OOBE.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<controls:OOBEPageControl
|
||||
x:Uid="Oobe_Overview"
|
||||
HeroImage="ms-appx:///Assets/Modules/OOBE/OOBEPTHero.png"
|
||||
HeroImageHeight="120">
|
||||
|
||||
<controls:OOBEPageControl.PageContent>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock
|
||||
x:Uid="Alternate_OOBE_Description"
|
||||
Margin="0,24,0,12"
|
||||
FontWeight="SemiBold" />
|
||||
<GridView Margin="-8,0,0,0" SelectionMode="None">
|
||||
<GridViewItem>
|
||||
<Grid
|
||||
Width="280"
|
||||
Margin="8"
|
||||
Padding="16,16,16,10"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
RowSpacing="0">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Width="36"
|
||||
HorizontalAlignment="Left"
|
||||
Source="ms-appx:///Assets/FluentIcons/FluentIconsFancyZones.png" />
|
||||
<TextBlock
|
||||
x:Uid="Alternate_OOBE_FancyZones_Title"
|
||||
Grid.Row="1"
|
||||
Margin="0,12,0,6"
|
||||
HorizontalAlignment="Left"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
x:Uid="Alternate_OOBE_FancyZones_Description"
|
||||
Grid.Row="2"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap" />
|
||||
<controls:ShortcutWithTextLabelControl
|
||||
x:Name="FancyZonesHotkeyControl"
|
||||
Grid.Row="3"
|
||||
Margin="0,8,0,0" />
|
||||
</Grid>
|
||||
</GridViewItem>
|
||||
|
||||
<GridViewItem>
|
||||
<Grid
|
||||
Width="280"
|
||||
Padding="16,16,16,10"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
RowSpacing="0">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Width="36"
|
||||
HorizontalAlignment="Left"
|
||||
Source="ms-appx:///Assets/FluentIcons/FluentIconsPowerToysRun.png" />
|
||||
<TextBlock
|
||||
x:Uid="Alternate_OOBE_Run_Title"
|
||||
Grid.Row="1"
|
||||
Margin="0,12,0,6"
|
||||
HorizontalAlignment="Left"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
x:Uid="Alternate_OOBE_Run_Description"
|
||||
Grid.Row="2"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap" />
|
||||
<controls:ShortcutWithTextLabelControl
|
||||
x:Name="RunHotkeyControl"
|
||||
Grid.Row="3"
|
||||
Margin="0,8,0,0" />
|
||||
</Grid>
|
||||
</GridViewItem>
|
||||
|
||||
<GridViewItem>
|
||||
<Grid
|
||||
Width="280"
|
||||
Padding="16,16,16,10"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
RowSpacing="0">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Width="36"
|
||||
HorizontalAlignment="Left"
|
||||
Source="ms-appx:///Assets/FluentIcons/FluentIconsColorPicker.png" />
|
||||
<TextBlock
|
||||
x:Uid="Alternate_OOBE_ColorPicker_Title"
|
||||
Grid.Row="1"
|
||||
Margin="0,12,0,6"
|
||||
HorizontalAlignment="Left"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
x:Uid="Alternate_OOBE_ColorPicker_Description"
|
||||
Grid.Row="2"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="To pick a color:"
|
||||
TextWrapping="Wrap" />
|
||||
<controls:ShortcutWithTextLabelControl
|
||||
x:Name="ColorPickerHotkeyControl"
|
||||
Grid.Row="3"
|
||||
Margin="0,8,0,0" />
|
||||
</Grid>
|
||||
</GridViewItem>
|
||||
|
||||
<GridViewItem>
|
||||
<Grid
|
||||
Width="280"
|
||||
Padding="16,16,16,10"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
RowSpacing="0">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Width="36"
|
||||
HorizontalAlignment="Left"
|
||||
Source="ms-appx:///Assets/FluentIcons/FluentIconsAlwaysOnTop.png" />
|
||||
<TextBlock
|
||||
x:Uid="Alternate_OOBE_AlwaysOnTop_Title"
|
||||
Grid.Row="1"
|
||||
Margin="0,12,0,6"
|
||||
HorizontalAlignment="Left"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
x:Uid="Alternate_OOBE_AlwaysOnTop_Description"
|
||||
Grid.Row="2"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap" />
|
||||
<controls:ShortcutWithTextLabelControl
|
||||
x:Name="AlwaysOnTopHotkeyControl"
|
||||
Grid.Row="3"
|
||||
Margin="0,8,0,0" />
|
||||
</Grid>
|
||||
</GridViewItem>
|
||||
|
||||
</GridView>
|
||||
</StackPanel>
|
||||
</controls:OOBEPageControl.PageContent>
|
||||
</controls:OOBEPageControl>
|
||||
</Page>
|
@ -0,0 +1,50 @@
|
||||
// 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.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
public sealed partial class OobeOverviewAlternate : Page
|
||||
{
|
||||
public OobePowerToysModule ViewModel { get; set; }
|
||||
|
||||
public OobeOverviewAlternate()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.Overview]);
|
||||
DataContext = ViewModel;
|
||||
|
||||
FancyZonesHotkeyControl.Keys = SettingsRepository<FancyZonesSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.FancyzonesEditorHotkey.Value.GetKeysList();
|
||||
RunHotkeyControl.Keys = SettingsRepository<PowerLauncherSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.OpenPowerLauncher.GetKeysList();
|
||||
ColorPickerHotkeyControl.Keys = SettingsRepository<ColorPickerSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
AlwaysOnTopHotkeyControl.Keys = SettingsRepository<AlwaysOnTopSettings>.GetInstance(new SettingsUtils()).SettingsConfig.Properties.Hotkey.Value.GetKeysList();
|
||||
}
|
||||
|
||||
private void SettingsLaunchButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (OobeShellPage.OpenMainWindowCallback != null)
|
||||
{
|
||||
OobeShellPage.OpenMainWindowCallback(typeof(GeneralPage));
|
||||
}
|
||||
|
||||
ViewModel.LogOpeningSettingsEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogClosingModuleEvent();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. -->
|
||||
<!-- Licensed under the MIT License. See LICENSE in the project root for license information. -->
|
||||
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobeOverviewPlaceholder"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.OOBE.Views"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Loaded="Page_Loaded"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid Margin="0,24,0,0">
|
||||
<ProgressRing
|
||||
x:Name="LoadingProgressRing"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsIndeterminate="True"
|
||||
Visibility="Visible" />
|
||||
</Grid>
|
||||
</Page>
|
@ -0,0 +1,73 @@
|
||||
// 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.Threading.Tasks;
|
||||
using AllExperiments;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
using Microsoft.PowerToys.Settings.UI.Services;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
public sealed partial class OobeOverviewPlaceholder : Page
|
||||
{
|
||||
public OobePowerToysModule ViewModel { get; set; }
|
||||
|
||||
public OobeOverviewPlaceholder()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.Overview]);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private static async Task<bool> GetIsExperiment()
|
||||
{
|
||||
Experiments landingPageExp = new Experiments();
|
||||
var experimentEnabled = await landingPageExp.EnableLandingPageExperimentAsync();
|
||||
return experimentEnabled;
|
||||
}
|
||||
|
||||
private async void Reload()
|
||||
{
|
||||
var isExperiment = await GetIsExperiment();
|
||||
|
||||
if (isExperiment)
|
||||
{
|
||||
this.Frame.Navigate(typeof(OobeOverviewAlternate));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Frame.Navigate(typeof(OobeOverview));
|
||||
}
|
||||
}
|
||||
|
||||
private void Page_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
|
||||
private void SettingsLaunchButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (OobeShellPage.OpenMainWindowCallback != null)
|
||||
{
|
||||
OobeShellPage.OpenMainWindowCallback(typeof(GeneralPage));
|
||||
}
|
||||
|
||||
ViewModel.LogOpeningSettingsEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogClosingModuleEvent();
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using AllExperiments;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
@ -47,10 +49,16 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
|
||||
public ObservableCollection<OobePowerToysModule> Modules { get; }
|
||||
|
||||
private static ISettingsUtils settingsUtils = new SettingsUtils();
|
||||
|
||||
private bool ExperimentationToggleSwitchEnabled { get; set; } = true;
|
||||
|
||||
public OobeShellPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
ExperimentationToggleSwitchEnabled = SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.EnableExperimentation;
|
||||
|
||||
DataContext = ViewModel;
|
||||
OobeShellHandler = this;
|
||||
UpdateUITheme();
|
||||
@ -186,7 +194,27 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
switch (selectedItem.Tag)
|
||||
{
|
||||
case "Overview": NavigationFrame.Navigate(typeof(OobeOverview)); break;
|
||||
case "Overview":
|
||||
if (ExperimentationToggleSwitchEnabled)
|
||||
{
|
||||
switch (AllExperiments.Experiments.LandingPageExperiment)
|
||||
{
|
||||
case Experiments.ExperimentState.Enabled:
|
||||
NavigationFrame.Navigate(typeof(OobeOverviewAlternate)); break;
|
||||
case Experiments.ExperimentState.Disabled:
|
||||
NavigationFrame.Navigate(typeof(OobeOverview)); break;
|
||||
case Experiments.ExperimentState.NotLoaded:
|
||||
NavigationFrame.Navigate(typeof(OobeOverviewPlaceholder)); break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationFrame.Navigate(typeof(OobeOverview));
|
||||
break;
|
||||
}
|
||||
|
||||
case "WhatsNew": NavigationFrame.Navigate(typeof(OobeWhatsNew)); break;
|
||||
case "AlwaysOnTop": NavigationFrame.Navigate(typeof(OobeAlwaysOnTop)); break;
|
||||
case "Awake": NavigationFrame.Navigate(typeof(OobeAwake)); break;
|
||||
|
@ -55,6 +55,9 @@
|
||||
<PropertyGroup>
|
||||
<RestoreAdditionalProjectSources>https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-Labs/nuget/v3/index.json</RestoreAdditionalProjectSources>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="OOBE\Views\OobeOverviewPlaceholder.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Controls\ColorFormatEditor.xaml" />
|
||||
</ItemGroup>
|
||||
@ -91,15 +94,19 @@
|
||||
<!-- 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 '$(EnablePreviewMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\common\AllExperiments\AllExperiments.csproj" />
|
||||
<ProjectReference Include="..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="FlyoutWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@ -122,10 +129,17 @@
|
||||
<None Update="icon.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<Page Update="OOBE\Views\OobeOverviewPlaceholder.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="OOBE\Views\OobeHosts.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Update="OOBE\Views\OobeOverviewAlternate.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="OOBE\Views\OobePowerOCR.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
|
@ -2830,6 +2830,10 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Launch Host File Editor</value>
|
||||
<comment>"Host File Editor" is a product name</comment>
|
||||
</data>
|
||||
<data name="Hosts_LaunchButton_Accessible.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Launch Host File Editor</value>
|
||||
<comment>"Host File Editor" is a product name</comment>
|
||||
</data>
|
||||
<data name="Hosts_AdditionalLinesPosition.Header" xml:space="preserve">
|
||||
<value>Position of additional content</value>
|
||||
</data>
|
||||
@ -2891,6 +2895,39 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<data name="TextExtractor_Languages.Header" xml:space="preserve">
|
||||
<value>Preferred language</value>
|
||||
</data>
|
||||
<data name="Alternate_OOBE_AlwaysOnTop_Description.Text" xml:space="preserve">
|
||||
<value>Pin a window so that:</value>
|
||||
</data>
|
||||
<data name="Alternate_OOBE_AlwaysOnTop_Title.Text" xml:space="preserve">
|
||||
<value>Always On Top</value>
|
||||
</data>
|
||||
<data name="Alternate_OOBE_ColorPicker_Description.Text" xml:space="preserve">
|
||||
<value>To pick a color:</value>
|
||||
</data>
|
||||
<data name="Alternate_OOBE_ColorPicker_Title.Text" xml:space="preserve">
|
||||
<value>Color Picker</value>
|
||||
</data>
|
||||
<data name="Alternate_OOBE_Description.Text" xml:space="preserve">
|
||||
<value>Here are a few shortcuts to get you started:</value>
|
||||
</data>
|
||||
<data name="Alternate_OOBE_FancyZones_Description.Text" xml:space="preserve">
|
||||
<value>To open the FancyZones editor, press:</value>
|
||||
</data>
|
||||
<data name="Alternate_OOBE_FancyZones_Title.Text" xml:space="preserve">
|
||||
<value>FancyZones</value>
|
||||
</data>
|
||||
<data name="Alternate_OOBE_Run_Description.Text" xml:space="preserve">
|
||||
<value>Get access to your files and more:</value>
|
||||
</data>
|
||||
<data name="Alternate_OOBE_Run_Title.Text" xml:space="preserve">
|
||||
<value>PowerToys Run</value>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableExperimentation.Description" xml:space="preserve">
|
||||
<value>Only affects Windows Insider builds</value>
|
||||
</data>
|
||||
<data name="GeneralPage_EnableExperimentation.Header" xml:space="preserve">
|
||||
<value>Enable experimentation</value>
|
||||
</data>
|
||||
<data name="AllAppsTxt.Text" xml:space="preserve">
|
||||
<value>All apps</value>
|
||||
</data>
|
||||
|
@ -125,6 +125,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
|
||||
_startup = GeneralSettingsConfig.Startup;
|
||||
_autoDownloadUpdates = GeneralSettingsConfig.AutoDownloadUpdates;
|
||||
_enableExperimentation = GeneralSettingsConfig.EnableExperimentation;
|
||||
|
||||
_isElevated = isElevated;
|
||||
_runElevated = GeneralSettingsConfig.RunElevated;
|
||||
@ -152,6 +153,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
private int _themeIndex;
|
||||
|
||||
private bool _autoDownloadUpdates;
|
||||
private bool _enableExperimentation;
|
||||
|
||||
private UpdatingSettings.UpdatingState _updatingState = UpdatingSettings.UpdatingState.UpToDate;
|
||||
private string _newAvailableVersion = string.Empty;
|
||||
@ -284,6 +286,24 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool EnableExperimentation
|
||||
{
|
||||
get
|
||||
{
|
||||
return _enableExperimentation;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_enableExperimentation != value)
|
||||
{
|
||||
_enableExperimentation = value;
|
||||
GeneralSettingsConfig.EnableExperimentation = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AutoUpdatesEnabled
|
||||
{
|
||||
get
|
||||
|
@ -369,8 +369,13 @@
|
||||
</labs:SettingsCard>
|
||||
</labs:SettingsExpander.Items>
|
||||
</labs:SettingsExpander>
|
||||
<labs:SettingsCard x:Uid="GeneralPage_EnableExperimentation"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/FluentIcons/FluentIconsExperimentation.png}">
|
||||
<ToggleSwitch
|
||||
x:Uid="ToggleSwitch"
|
||||
IsOn="{Binding Mode=TwoWay, Path=EnableExperimentation}" />
|
||||
</labs:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<InfoBar
|
||||
x:Uid="General_SettingsBackupMessageResults"
|
||||
Title="{Binding SettingsBackupMessage}"
|
||||
|
Loading…
Reference in New Issue
Block a user