mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 19:27:56 +01:00
[OOBE]Add What's New page - SCOOBE (#16478)
* [Oobe]Add a What's New page * Show What's New when version changes * Add link to GitHub * Use generic icon for now * Get only the latest 5 releases * fix spellchecker * rename last_version_run.json * Remove UserControl_Loaded * Remove installer hash from the release notes * constexpr some strings * Add check your internet connection message
This commit is contained in:
2
.github/actions/spell-check/expect.txt
vendored
2
.github/actions/spell-check/expect.txt
vendored
@@ -1780,7 +1780,7 @@ scancode
|
||||
scanled
|
||||
schedtasks
|
||||
scm
|
||||
SCOOBE
|
||||
scoobe
|
||||
SCOPEID
|
||||
screenshot
|
||||
scrollable
|
||||
|
||||
@@ -5,6 +5,9 @@ namespace PTSettingsHelper
|
||||
{
|
||||
constexpr inline const wchar_t* settings_filename = L"\\settings.json";
|
||||
constexpr inline const wchar_t* oobe_filename = L"oobe_settings.json";
|
||||
constexpr inline const wchar_t* last_version_run_filename = L"last_version_run.json";
|
||||
constexpr inline const wchar_t* opened_at_first_launch_json_field_name = L"openedAtFirstLaunch";
|
||||
constexpr inline const wchar_t* last_version_json_field_name = L"last_version";
|
||||
|
||||
std::wstring get_root_save_folder_location()
|
||||
{
|
||||
@@ -90,7 +93,7 @@ namespace PTSettingsHelper
|
||||
return false;
|
||||
}
|
||||
|
||||
bool opened = saved_settings->GetNamedBoolean(L"openedAtFirstLaunch", false);
|
||||
bool opened = saved_settings->GetNamedBoolean(opened_at_first_launch_json_field_name, false);
|
||||
return opened;
|
||||
}
|
||||
|
||||
@@ -103,8 +106,39 @@ namespace PTSettingsHelper
|
||||
oobePath = oobePath.append(oobe_filename);
|
||||
|
||||
json::JsonObject obj;
|
||||
obj.SetNamedValue(L"openedAtFirstLaunch", json::value(true));
|
||||
obj.SetNamedValue(opened_at_first_launch_json_field_name, json::value(true));
|
||||
|
||||
json::to_file(oobePath.c_str(), obj);
|
||||
}
|
||||
|
||||
std::wstring get_last_version_run()
|
||||
{
|
||||
|
||||
std::filesystem::path lastVersionRunPath(PTSettingsHelper::get_root_save_folder_location());
|
||||
lastVersionRunPath = lastVersionRunPath.append(last_version_run_filename);
|
||||
if (std::filesystem::exists(lastVersionRunPath))
|
||||
{
|
||||
auto saved_settings = json::from_file(lastVersionRunPath.c_str());
|
||||
if (!saved_settings.has_value())
|
||||
{
|
||||
return L"";
|
||||
}
|
||||
|
||||
std::wstring last_version = saved_settings->GetNamedString(last_version_json_field_name, L"").c_str();
|
||||
return last_version;
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
void save_last_version_run(const std::wstring& version)
|
||||
{
|
||||
std::filesystem::path lastVersionRunPath(PTSettingsHelper::get_root_save_folder_location());
|
||||
lastVersionRunPath = lastVersionRunPath.append(last_version_run_filename);
|
||||
|
||||
json::JsonObject obj;
|
||||
obj.SetNamedValue(last_version_json_field_name, json::value(version));
|
||||
|
||||
json::to_file(lastVersionRunPath.c_str(), obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,4 +21,6 @@ namespace PTSettingsHelper
|
||||
|
||||
bool get_oobe_opened_state();
|
||||
void save_oobe_opened_state();
|
||||
std::wstring get_last_version_run();
|
||||
void save_last_version_run(const std::wstring& version);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ void debug_verify_launcher_assets()
|
||||
}
|
||||
}
|
||||
|
||||
int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow, bool openOobe)
|
||||
int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow, bool openOobe, bool openScoobe)
|
||||
{
|
||||
Logger::info("Runner is starting. Elevated={}", isProcessElevated);
|
||||
DPIAware::EnableDPIAwarenessForThisProcess();
|
||||
@@ -179,8 +179,9 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
||||
}
|
||||
// Start initial powertoys
|
||||
start_enabled_powertoys();
|
||||
|
||||
Trace::EventLaunch(get_product_version(), isProcessElevated);
|
||||
std::wstring product_version = get_product_version();
|
||||
Trace::EventLaunch(product_version, isProcessElevated);
|
||||
PTSettingsHelper::save_last_version_run(product_version);
|
||||
|
||||
if (openSettings)
|
||||
{
|
||||
@@ -196,6 +197,10 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
|
||||
{
|
||||
open_oobe_window();
|
||||
}
|
||||
else if (openScoobe)
|
||||
{
|
||||
open_scoobe_window();
|
||||
}
|
||||
|
||||
settings_telemetry::init();
|
||||
result = run_message_loop();
|
||||
@@ -373,6 +378,17 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
Logger::error("Failed to get or save OOBE state with an exception: {}", e.what());
|
||||
}
|
||||
|
||||
bool openScoobe = false;
|
||||
try
|
||||
{
|
||||
std::wstring last_version_run = PTSettingsHelper::get_last_version_run();
|
||||
openScoobe = last_version_run != get_product_version();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Logger::error("Failed to get last version with an exception: {}", e.what());
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
try
|
||||
{
|
||||
@@ -398,7 +414,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
else if (elevated || !run_elevated_setting || with_dont_elevate_arg)
|
||||
|
||||
{
|
||||
result = runner(elevated, open_settings, settings_window, openOobe);
|
||||
result = runner(elevated, open_settings, settings_window, openOobe, openScoobe);
|
||||
|
||||
// Save settings on closing
|
||||
auto general_settings = get_general_settings();
|
||||
|
||||
@@ -260,7 +260,7 @@ BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args,
|
||||
|
||||
DWORD g_settings_process_id = 0;
|
||||
|
||||
void run_settings_window(bool show_oobe_window, std::optional<std::wstring> settings_window)
|
||||
void run_settings_window(bool show_oobe_window, bool show_scoobe_window, std::optional<std::wstring> settings_window)
|
||||
{
|
||||
g_isLaunchInProgress = true;
|
||||
|
||||
@@ -327,6 +327,9 @@ void run_settings_window(bool show_oobe_window, std::optional<std::wstring> sett
|
||||
// Arg 8: should oobe window be shown
|
||||
std::wstring settings_showOobe = show_oobe_window ? L"true" : L"false";
|
||||
|
||||
// Arg 9: should scoobe window be shown
|
||||
std::wstring settings_showScoobe = show_scoobe_window ? L"true" : L"false";
|
||||
|
||||
// create general settings file to initialize the settings file with installation configurations like :
|
||||
// 1. Run on start up.
|
||||
PTSettingsHelper::save_general_settings(save_settings.to_json());
|
||||
@@ -347,6 +350,8 @@ void run_settings_window(bool show_oobe_window, std::optional<std::wstring> sett
|
||||
executable_args.append(settings_isUserAnAdmin);
|
||||
executable_args.append(L" ");
|
||||
executable_args.append(settings_showOobe);
|
||||
executable_args.append(L" ");
|
||||
executable_args.append(settings_showScoobe);
|
||||
|
||||
if (settings_window.has_value())
|
||||
{
|
||||
@@ -490,7 +495,7 @@ void open_settings_window(std::optional<std::wstring> settings_window)
|
||||
if (!g_isLaunchInProgress)
|
||||
{
|
||||
std::thread([settings_window]() {
|
||||
run_settings_window(false, settings_window);
|
||||
run_settings_window(false, false, settings_window);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
@@ -511,7 +516,14 @@ void close_settings_window()
|
||||
void open_oobe_window()
|
||||
{
|
||||
std::thread([]() {
|
||||
run_settings_window(true, std::nullopt);
|
||||
run_settings_window(true, false, std::nullopt);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
void open_scoobe_window()
|
||||
{
|
||||
std::thread([]() {
|
||||
run_settings_window(false, true, std::nullopt);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,4 +24,5 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value);
|
||||
void open_settings_window(std::optional<std::wstring> settings_window);
|
||||
void close_settings_window();
|
||||
|
||||
void open_oobe_window();
|
||||
void open_oobe_window();
|
||||
void open_scoobe_window();
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace PowerToys.Settings
|
||||
|
||||
public bool ShowOobe { get; set; }
|
||||
|
||||
public bool ShowScoobe { get; set; }
|
||||
|
||||
public Type StartupPage { get; set; } = typeof(Microsoft.PowerToys.Settings.UI.Views.GeneralPage);
|
||||
|
||||
public void OpenSettingsWindow(Type type)
|
||||
@@ -45,7 +47,7 @@ namespace PowerToys.Settings
|
||||
|
||||
private void Application_Startup(object sender, StartupEventArgs e)
|
||||
{
|
||||
if (!ShowOobe)
|
||||
if (!ShowOobe && !ShowScoobe)
|
||||
{
|
||||
settingsWindow = new MainWindow();
|
||||
settingsWindow.Show();
|
||||
@@ -53,15 +55,22 @@ namespace PowerToys.Settings
|
||||
}
|
||||
else
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new OobeStartedEvent());
|
||||
|
||||
// Create the Settings window so that it's fully initialized and
|
||||
// it will be ready to receive the notification if the user opens
|
||||
// the Settings from the tray icon.
|
||||
InitHiddenSettingsWindow();
|
||||
|
||||
OobeWindow oobeWindow = new OobeWindow();
|
||||
oobeWindow.Show();
|
||||
if (ShowOobe)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new OobeStartedEvent());
|
||||
OobeWindow oobeWindow = new OobeWindow((int)Microsoft.PowerToys.Settings.UI.OOBE.Enums.PowerToysModulesEnum.Overview);
|
||||
oobeWindow.Show();
|
||||
}
|
||||
else if (ShowScoobe)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new ScoobeStartedEvent());
|
||||
OobeWindow scoobeWindow = new OobeWindow((int)Microsoft.PowerToys.Settings.UI.OOBE.Enums.PowerToysModulesEnum.WhatsNew);
|
||||
scoobeWindow.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace PowerToys.Settings
|
||||
// open oobe
|
||||
ShellPage.SetOpenOobeCallback(() =>
|
||||
{
|
||||
var oobe = new OobeWindow();
|
||||
var oobe = new OobeWindow((int)Microsoft.PowerToys.Settings.UI.OOBE.Enums.PowerToysModulesEnum.Overview);
|
||||
oobe.Show();
|
||||
});
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace PowerToys.Settings
|
||||
{
|
||||
private static Window inst;
|
||||
private OobeShellPage shellPage;
|
||||
private int initialModule;
|
||||
|
||||
public static bool IsOpened
|
||||
{
|
||||
@@ -29,10 +30,11 @@ namespace PowerToys.Settings
|
||||
}
|
||||
}
|
||||
|
||||
public OobeWindow()
|
||||
public OobeWindow(int initialModule)
|
||||
{
|
||||
InitializeComponent();
|
||||
Utils.FitToScreen(this);
|
||||
this.initialModule = initialModule;
|
||||
|
||||
ResourceLoader loader = ResourceLoader.GetForViewIndependentUse();
|
||||
Title = loader.GetString("OobeWindow_Title");
|
||||
@@ -69,6 +71,11 @@ namespace PowerToys.Settings
|
||||
WindowsXamlHost windowsXamlHost = sender as WindowsXamlHost;
|
||||
shellPage = windowsXamlHost.GetUwpInternalObject() as OobeShellPage;
|
||||
|
||||
if (shellPage != null)
|
||||
{
|
||||
shellPage.NavigateToModule(initialModule);
|
||||
}
|
||||
|
||||
OobeShellPage.SetRunSharedEventCallback(() =>
|
||||
{
|
||||
return Constants.PowerLauncherSharedEvent();
|
||||
|
||||
@@ -21,12 +21,13 @@ namespace PowerToys.Settings
|
||||
ElevatedStatus,
|
||||
IsUserAdmin,
|
||||
ShowOobeWindow,
|
||||
ShowScoobeWindow,
|
||||
SettingsWindow,
|
||||
}
|
||||
|
||||
// Quantity of arguments
|
||||
private const int RequiredArgumentsQty = 7;
|
||||
private const int RequiredAndOptionalArgumentsQty = 8;
|
||||
private const int RequiredArgumentsQty = 8;
|
||||
private const int RequiredAndOptionalArgumentsQty = 9;
|
||||
|
||||
// Create an instance of the IPC wrapper.
|
||||
private static TwoWayPipeMessageIPCManaged ipcmanager;
|
||||
@@ -55,6 +56,7 @@ namespace PowerToys.Settings
|
||||
IsElevated = args[(int)Arguments.ElevatedStatus] == "true";
|
||||
IsUserAnAdmin = args[(int)Arguments.IsUserAdmin] == "true";
|
||||
app.ShowOobe = args[(int)Arguments.ShowOobeWindow] == "true";
|
||||
app.ShowScoobe = args[(int)Arguments.ShowScoobeWindow] == "true";
|
||||
|
||||
if (args.Length == RequiredAndOptionalArgumentsQty)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
using System.Diagnostics.Tracing;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events
|
||||
{
|
||||
[EventData]
|
||||
public class ScoobeStartedEvent : EventBase, IEvent
|
||||
{
|
||||
public bool ScoobeStarted { get; set; } = true;
|
||||
|
||||
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Enums
|
||||
public enum PowerToysModulesEnum
|
||||
{
|
||||
Overview = 0,
|
||||
WhatsNew,
|
||||
AlwaysOnTop,
|
||||
Awake,
|
||||
ColorPicker,
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
winui:BackdropMaterial.ApplyToRootOrPageBackground="True"
|
||||
mc:Ignorable="d"
|
||||
HighContrastAdjustment="None"
|
||||
Loaded="UserControl_Loaded">
|
||||
HighContrastAdjustment="None">
|
||||
|
||||
<UserControl.Resources>
|
||||
<DataTemplate x:Key="NavigationViewMenuItem" x:DataType="localModels:OobePowerToysModule">
|
||||
|
||||
@@ -71,6 +71,14 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
DescriptionLink = "https://aka.ms/PowerToysOverview",
|
||||
Link = "https://github.com/microsoft/PowerToys/releases/",
|
||||
});
|
||||
Modules.Insert((int)PowerToysModulesEnum.WhatsNew, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = loader.GetString("Oobe_WhatsNew"),
|
||||
Tag = "WhatsNew",
|
||||
IsNew = false,
|
||||
Icon = "\uEF3C",
|
||||
FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsSettings.png",
|
||||
});
|
||||
Modules.Insert((int)PowerToysModulesEnum.AlwaysOnTop, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = loader.GetString("Oobe_AlwaysOnTop"),
|
||||
@@ -226,11 +234,11 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
}
|
||||
}
|
||||
|
||||
private void UserControl_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
|
||||
public void NavigateToModule(int moduleIndex)
|
||||
{
|
||||
if (Modules.Count > 0)
|
||||
{
|
||||
NavigationView.SelectedItem = Modules[(int)PowerToysModulesEnum.Overview];
|
||||
NavigationView.SelectedItem = Modules[moduleIndex];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,6 +250,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
switch (selectedItem.Tag)
|
||||
{
|
||||
case "Overview": 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;
|
||||
case "ColorPicker": NavigationFrame.Navigate(typeof(OobeColorPicker)); break;
|
||||
|
||||
52
src/settings-ui/Settings.UI/OOBE/Views/OobeWhatsNew.xaml
Normal file
52
src/settings-ui/Settings.UI/OOBE/Views/OobeWhatsNew.xaml
Normal file
@@ -0,0 +1,52 @@
|
||||
<Page x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobeWhatsNew"
|
||||
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"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:toolkitcontrols="using:Microsoft.Toolkit.Uwp.UI.Controls"
|
||||
mc:Ignorable="d"
|
||||
Loaded="Page_Loaded">
|
||||
<ScrollViewer
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Padding="32,24,32,24">
|
||||
|
||||
<StackPanel
|
||||
Orientation="Vertical"
|
||||
VerticalAlignment="Top">
|
||||
|
||||
<TextBlock
|
||||
x:Name="TitleTxt"
|
||||
Text=""
|
||||
AutomationProperties.HeadingLevel="Level1"
|
||||
Style="{StaticResource TitleTextBlockStyle}" />
|
||||
<HyperlinkButton
|
||||
NavigateUri="https://github.com/microsoft/PowerToys/releases"
|
||||
Margin="0,0,0,16"
|
||||
Style="{StaticResource TextButtonStyle}">
|
||||
<TextBlock
|
||||
x:Uid="Oobe_WhatsNew_DetailedReleaseNotesLink"
|
||||
TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
<muxc:ProgressRing
|
||||
x:Name="LoadingProgressRing"
|
||||
IsIndeterminate="True"
|
||||
Visibility="Visible"/>
|
||||
<muxc:InfoBar
|
||||
Severity="Error"
|
||||
x:Name="ErrorInfoBar"
|
||||
x:Uid="Oobe_WhatsNew_LoadingError"
|
||||
Visibility="Collapsed"
|
||||
IsClosable="False"
|
||||
IsOpen="True"
|
||||
IsTabStop="True" />
|
||||
<toolkitcontrols:MarkdownTextBlock
|
||||
x:Name="ReleaseNotesMarkdown"
|
||||
Visibility="Collapsed"
|
||||
Background="Transparent"
|
||||
LinkClicked="ReleaseNotesMarkdown_LinkClicked"/>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Page>
|
||||
118
src/settings-ui/Settings.UI/OOBE/Views/OobeWhatsNew.xaml.cs
Normal file
118
src/settings-ui/Settings.UI/OOBE/Views/OobeWhatsNew.xaml.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
public sealed partial class OobeWhatsNew : Page
|
||||
{
|
||||
// Contains information for a release. Used to deserialize release JSON info from GitHub.
|
||||
private class PowerToysReleaseInfo
|
||||
{
|
||||
[JsonPropertyName("published_at")]
|
||||
public DateTimeOffset PublishedDate { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("tag_name")]
|
||||
public string TagName { get; set; }
|
||||
|
||||
[JsonPropertyName("body")]
|
||||
public string ReleaseNotes { get; set; }
|
||||
}
|
||||
|
||||
public OobePowerToysModule ViewModel { get; set; }
|
||||
|
||||
public OobeWhatsNew()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.WhatsNew]);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private async Task<string> GetReleaseNotesMarkdown()
|
||||
{
|
||||
string releaseNotesJSON = string.Empty;
|
||||
using (HttpClient getReleaseInfoClient = new HttpClient())
|
||||
{
|
||||
// GitHub APIs require sending an user agent
|
||||
// https://docs.github.com/en/rest/overview/resources-in-the-rest-api#user-agent-required
|
||||
getReleaseInfoClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "PowerToys");
|
||||
releaseNotesJSON = await getReleaseInfoClient.GetStringAsync("https://api.github.com/repos/microsoft/PowerToys/releases");
|
||||
}
|
||||
|
||||
IList<PowerToysReleaseInfo> releases = JsonSerializer.Deserialize<IList<PowerToysReleaseInfo>>(releaseNotesJSON);
|
||||
|
||||
// Get the latest releases
|
||||
var latestReleases = releases.OrderByDescending(release => release.PublishedDate).Take(5);
|
||||
|
||||
StringBuilder releaseNotesHtmlBuilder = new StringBuilder(string.Empty);
|
||||
|
||||
// Regex to remove installer hash sections from the release notes.
|
||||
Regex removeHashRegex = new Regex(@"(\r\n)+#+ installer( SHA256)? hash(\r\n)+[0-9A-F]{64}", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
|
||||
foreach (var release in latestReleases)
|
||||
{
|
||||
releaseNotesHtmlBuilder.AppendLine("# " + release.Name);
|
||||
releaseNotesHtmlBuilder.AppendLine(removeHashRegex.Replace(release.ReleaseNotes, string.Empty));
|
||||
}
|
||||
|
||||
return releaseNotesHtmlBuilder.ToString();
|
||||
}
|
||||
|
||||
private async void Page_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
ResourceLoader loader = ResourceLoader.GetForViewIndependentUse();
|
||||
TitleTxt.Text = loader.GetString("Oobe_WhatsNew");
|
||||
try
|
||||
{
|
||||
ReleaseNotesMarkdown.Text = await GetReleaseNotesMarkdown();
|
||||
ReleaseNotesMarkdown.Visibility = Windows.UI.Xaml.Visibility.Visible;
|
||||
LoadingProgressRing.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Exception when loading the release notes", ex);
|
||||
LoadingProgressRing.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
|
||||
ErrorInfoBar.Visibility = Windows.UI.Xaml.Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogClosingModuleEvent();
|
||||
}
|
||||
|
||||
private void ReleaseNotesMarkdown_LinkClicked(object sender, Toolkit.Uwp.UI.Controls.LinkClickedEventArgs e)
|
||||
{
|
||||
if (Uri.TryCreate(e.Link, UriKind.Absolute, out Uri link))
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(link.ToString()) { UseShellExecute = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,6 +167,9 @@
|
||||
<Compile Include="OOBE\Views\OobeMouseUtils.xaml.cs">
|
||||
<DependentUpon>OobeMouseUtils.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="OOBE\Views\OobeWhatsNew.xaml.cs">
|
||||
<DependentUpon>OobeWhatsNew.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="OOBE\Views\OobeOverview.xaml.cs">
|
||||
<DependentUpon>OobeOverview.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -409,6 +412,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="OOBE\Views\OobeWhatsNew.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="OOBE\Views\OobeOverview.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -1438,6 +1438,16 @@ From there, simply click on a Markdown file, PDF file or SVG icon in the File Ex
|
||||
<data name="Oobe_Welcome" xml:space="preserve">
|
||||
<value>Welcome</value>
|
||||
</data>
|
||||
<data name="Oobe_WhatsNew" xml:space="preserve">
|
||||
<value>What's new?</value>
|
||||
</data>
|
||||
<data name="Oobe_WhatsNew_LoadingError.Title" xml:space="preserve">
|
||||
<value>Couldn't load the release notes. Please check your internet connection.</value>
|
||||
</data>
|
||||
<data name="Oobe_WhatsNew_DetailedReleaseNotesLink.Text" xml:space="preserve">
|
||||
<value>See more detailed release notes on the GitHub repository</value>
|
||||
<comment>Don't loc "GitHub", it's the name of a product</comment>
|
||||
</data>
|
||||
<data name="OOBE_Settings.Content" xml:space="preserve">
|
||||
<value>Open Settings</value>
|
||||
</data>
|
||||
|
||||
Reference in New Issue
Block a user