[Auto-update] Auto-update improvements (#11356)

* [Updating] Refactor autoupdate mechanism to use Settings window buttons

* [Updating] Don't use underscores in update_state (#11029)

* [Updating] Rename action_runner to be consisent with accepted format

* [Updating] Make UpdateState values explicit

* [Setup] Set default bootstrapper log severity to debug

* [BugReport] Include all found bootstrapper logs

* [Setup] Use capital letter for ActionRunner

* [Updating] Simple UI to test UpdateState

* [Action Runner]  cleanup and coding style

* [BugReportTool] fix coding convension

* [Auto-update][PT Settings] Updated general page in the Settings (#11227)

* [Auto-update][PT Settings] File watcher monitoring UpdateState.json (#11282)

* Handle button clicks (#11288)

* [Updating] Document ActionRunner cmd flags

* [Auto-update][PT Settings] Updated UI (#11335)

* [Updating] Do not reset update state when msi cancellation detected

* [Updating] Directly launch update_now PT action instead of using custom URI scheme

* Checking for updates UI (#11354)

* [Updating] Fix cannotDownload state in action runner

* [Updating] Reset update state to CannotDownload if action runner encountered an error

* [Updating][PT Settings] downloading label, disable button in error state

* Changed error message

* [Updating rename CannotDownload to ErrorDownloading

* [Updating] Add trace logging for Check for updates callback

* [Updating][PT Settings] simplify downloading checks

* [Updating][PT Settings] Updated text labels

* [Updating][PT Settings] Retry to load settings if failed

* [Updating][PT Settings] Text fix

* [Updating][PT Settings] Installed version links removed

* [Updating][PT Settings] Error text updated

* [Updating][PT Settings] Show label after version checked

* [Updating][PT Settings] Text foreground fix

* [Updating][PT Settings] Clean up

* [Updating] Do not reset releasePageUrl in case of error/cancellation

* [Updating][PT Settings] fixed missing string

* [Updating][PT Settings] checked for updates state fix

Co-authored-by: yuyoyuppe <a.yuyoyuppe@gmail.com>
Co-authored-by: Andrey Nekrasov <yuyoyuppe@users.noreply.github.com>
Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com>
This commit is contained in:
Seraphima Zykova
2021-05-21 13:32:34 +03:00
committed by GitHub
parent d55badf14a
commit b96b4fcb0f
68 changed files with 1065 additions and 761 deletions

View File

@@ -0,0 +1,126 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Globalization;
using System.IO;
using System.IO.Abstractions;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Microsoft.PowerToys.Settings.UI.Library
{
public class UpdatingSettings
{
public enum UpdatingState
{
UpToDate = 0,
ErrorDownloading,
ReadyToDownload,
ReadyToInstall,
}
// Gets or sets a value of the updating state
[JsonPropertyName("state")]
public UpdatingState State { get; set; }
// Gets or sets a value of the release page url
[JsonPropertyName("releasePageUrl")]
public string ReleasePageLink { get; set; }
// Gets or sets a value of the github last checked date
[JsonPropertyName("githubUpdateLastCheckedDate")]
public string LastCheckedDate { get; set; }
// Gets or sets a value of the updating state
[JsonPropertyName("downloadedInstallerFilename")]
public string DownloadedInstallerFilename { get; set; }
// Non-localizable strings: Files
public const string SettingsFilePath = "\\Microsoft\\PowerToys\\";
public const string SettingsFile = "UpdateState.json";
public string NewVersion
{
get
{
if (ReleasePageLink == null)
{
return string.Empty;
}
try
{
string version = ReleasePageLink.Substring(ReleasePageLink.LastIndexOf('/') + 1);
return version.Trim();
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception)
#pragma warning restore CA1031 // Do not catch general exception types
{
}
return string.Empty;
}
}
public string LastCheckedDateLocalized
{
get
{
try
{
long seconds = long.Parse(LastCheckedDate, CultureInfo.CurrentCulture);
var date = DateTimeOffset.FromUnixTimeSeconds(seconds).UtcDateTime;
return date.ToLocalTime().ToString(CultureInfo.CurrentCulture);
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception)
#pragma warning restore CA1031 // Do not catch general exception types
{
}
return string.Empty;
}
}
public UpdatingSettings()
{
State = UpdatingState.UpToDate;
}
public static UpdatingSettings LoadSettings()
{
FileSystem fileSystem = new FileSystem();
var localAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var file = localAppDataDir + SettingsFilePath + SettingsFile;
if (fileSystem.File.Exists(file))
{
try
{
Stream inputStream = fileSystem.File.Open(file, FileMode.Open);
StreamReader reader = new StreamReader(inputStream);
string data = reader.ReadToEnd();
inputStream.Close();
reader.Dispose();
return JsonSerializer.Deserialize<UpdatingSettings>(data);
}
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception)
#pragma warning restore CA1031 // Do not catch general exception types
{
}
}
return null;
}
public string ToJsonString()
{
return JsonSerializer.Serialize(this);
}
}
}

View File

@@ -75,6 +75,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
}
public static string GetPowerToysInstallationFolder()
{
var settingsPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
return Directory.GetParent(settingsPath).FullName;
}
private static readonly interop.LayoutMapManaged LayoutMap = new interop.LayoutMapManaged();
public static string GetKeyName(uint key)

View File

@@ -1,9 +1,11 @@
// 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.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO.Abstractions;
using System.Runtime.CompilerServices;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
@@ -16,10 +18,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
{
private GeneralSettings GeneralSettingsConfig { get; set; }
private UpdatingSettings UpdatingSettingsConfig { get; set; }
public ButtonClickCommand CheckForUpdatesEventHandler { get; set; }
public ButtonClickCommand RestartElevatedButtonEventHandler { get; set; }
public ButtonClickCommand UpdateNowButtonEventHandler { get; set; }
public Func<string, int> UpdateUIThemeCallBack { get; }
public Func<string, int> SendConfigMSG { get; }
@@ -34,10 +40,13 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
private string _settingsConfigFileFolder = string.Empty;
public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository, string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> updateTheme, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "")
private IFileSystemWatcher _fileWatcher;
public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository, string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> updateTheme, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "", Action dispatcherAction = null)
{
CheckForUpdatesEventHandler = new ButtonClickCommand(CheckForUpdatesClick);
RestartElevatedButtonEventHandler = new ButtonClickCommand(RestartElevated);
UpdateNowButtonEventHandler = new ButtonClickCommand(UpdateNowClick);
// To obtain the general settings configuration of PowerToys if it exists, else to create a new file and return the default configurations.
if (settingsRepository == null)
@@ -46,6 +55,11 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
}
GeneralSettingsConfig = settingsRepository.SettingsConfig;
UpdatingSettingsConfig = UpdatingSettings.LoadSettings();
if (UpdatingSettingsConfig == null)
{
UpdatingSettingsConfig = new UpdatingSettings();
}
// set the callback functions value to hangle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
@@ -86,6 +100,16 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
RunningAsAdminDefaultText = runAsAdminText;
_isAdmin = isAdmin;
_updatingState = UpdatingSettingsConfig.State;
_newAvailableVersion = UpdatingSettingsConfig.NewVersion;
_newAvailableVersionLink = UpdatingSettingsConfig.ReleasePageLink;
_updateCheckedDate = UpdatingSettingsConfig.LastCheckedDateLocalized;
if (dispatcherAction != null)
{
_fileWatcher = Helper.GetFileWatcher(string.Empty, UpdatingSettings.SettingsFile, dispatcherAction);
}
}
private bool _packaged;
@@ -98,9 +122,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
private bool _isSystemThemeRadioButtonChecked;
private bool _autoDownloadUpdates;
private string _latestAvailableVersion = string.Empty;
private UpdatingSettings.UpdatingState _updatingState = UpdatingSettings.UpdatingState.UpToDate;
private string _newAvailableVersion = string.Empty;
private string _newAvailableVersionLink = string.Empty;
private string _updateCheckedDate = string.Empty;
private bool _isNewVersionDownloading;
private bool _isNewVersionChecked;
// Gets or sets a value indicating whether packaged.
public bool Packaged
{
@@ -360,24 +389,90 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
}
}
// Temp string. Appears when a user clicks "Check for updates" button and shows latest version available on the Github.
public string LatestAvailableVersion
public UpdatingSettings.UpdatingState PowerToysUpdatingState
{
get
{
return _latestAvailableVersion;
return _updatingState;
}
private set
{
if (value != _updatingState)
{
_updatingState = value;
NotifyPropertyChanged();
}
}
}
public string PowerToysNewAvailableVersion
{
get
{
return _newAvailableVersion;
}
private set
{
if (value != _newAvailableVersion)
{
_newAvailableVersion = value;
NotifyPropertyChanged();
}
}
}
public string PowerToysNewAvailableVersionLink
{
get
{
return _newAvailableVersionLink;
}
private set
{
if (value != _newAvailableVersionLink)
{
_newAvailableVersionLink = value;
NotifyPropertyChanged();
}
}
}
public bool IsNewVersionDownloading
{
get
{
return _isNewVersionDownloading;
}
set
{
if (_latestAvailableVersion != value)
if (value != _isNewVersionDownloading)
{
_latestAvailableVersion = value;
_isNewVersionDownloading = value;
NotifyPropertyChanged();
}
}
}
public bool IsNewVersionCheckedAndUpToDate
{
get
{
return _isNewVersionChecked;
}
}
public bool IsDownloadAllowed
{
get
{
return AutoUpdatesEnabled && !IsNewVersionDownloading;
}
}
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
// Notify UI of property change
@@ -390,6 +485,15 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
// callback function to launch the URL to check for updates.
private void CheckForUpdatesClick()
{
IsNewVersionDownloading = string.IsNullOrEmpty(UpdatingSettingsConfig.DownloadedInstallerFilename);
NotifyPropertyChanged(nameof(IsDownloadAllowed));
if (_isNewVersionChecked)
{
_isNewVersionChecked = !IsNewVersionDownloading;
NotifyPropertyChanged(nameof(IsNewVersionCheckedAndUpToDate));
}
GeneralSettingsConfig.CustomActionName = "check_for_updates";
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig);
@@ -398,6 +502,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
SendCheckForUpdatesConfigMSG(customaction.ToString());
}
private void UpdateNowClick()
{
IsNewVersionDownloading = string.IsNullOrEmpty(UpdatingSettingsConfig.DownloadedInstallerFilename);
NotifyPropertyChanged(nameof(IsDownloadAllowed));
Process.Start(new ProcessStartInfo(Helper.GetPowerToysInstallationFolder() + "\\PowerToys.exe") { Arguments = "powertoys://update_now/" });
}
public void RequestUpdateCheckedDate()
{
GeneralSettingsConfig.CustomActionName = "request_update_state_date";
@@ -417,5 +529,45 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
SendRestartAsAdminConfigMSG(customaction.ToString());
}
public void RefreshUpdatingState()
{
var config = UpdatingSettings.LoadSettings();
// Retry loading if failed
for (int i = 0; i < 3 && config == null; i++)
{
System.Threading.Thread.Sleep(100);
config = UpdatingSettings.LoadSettings();
}
if (config == null || config.ToJsonString() == UpdatingSettingsConfig.ToJsonString())
{
return;
}
UpdatingSettingsConfig = config;
if (PowerToysUpdatingState != config.State)
{
IsNewVersionDownloading = false;
}
else
{
bool dateChanged = UpdateCheckedDate == UpdatingSettingsConfig.LastCheckedDateLocalized;
bool fileDownloaded = string.IsNullOrEmpty(UpdatingSettingsConfig.DownloadedInstallerFilename);
IsNewVersionDownloading = !(dateChanged || fileDownloaded);
}
PowerToysUpdatingState = UpdatingSettingsConfig.State;
PowerToysNewAvailableVersion = UpdatingSettingsConfig.NewVersion;
PowerToysNewAvailableVersionLink = UpdatingSettingsConfig.ReleasePageLink;
UpdateCheckedDate = UpdatingSettingsConfig.LastCheckedDateLocalized;
_isNewVersionChecked = PowerToysUpdatingState == UpdatingSettings.UpdatingState.UpToDate && !IsNewVersionDownloading;
NotifyPropertyChanged(nameof(IsNewVersionCheckedAndUpToDate));
NotifyPropertyChanged(nameof(IsDownloadAllowed));
}
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.PowerToys.Settings.UI.Library;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace Microsoft.PowerToys.Settings.UI.Converters
{
public sealed class UpdatingStateCannotDownloadToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (UpdatingSettings.UpdatingState)value == UpdatingSettings.UpdatingState.ErrorDownloading ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.PowerToys.Settings.UI.Library;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace Microsoft.PowerToys.Settings.UI.Converters
{
public sealed class UpdatingStateReadyToDownloadToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (UpdatingSettings.UpdatingState)value == UpdatingSettings.UpdatingState.ReadyToDownload ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.PowerToys.Settings.UI.Library;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace Microsoft.PowerToys.Settings.UI.Converters
{
public sealed class UpdatingStateReadyToInstallToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (UpdatingSettings.UpdatingState)value == UpdatingSettings.UpdatingState.ReadyToInstall ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
}

View File

@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.PowerToys.Settings.UI.Library;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace Microsoft.PowerToys.Settings.UI.Converters
{
public sealed class UpdatingStateUpToDateToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (UpdatingSettings.UpdatingState)value == UpdatingSettings.UpdatingState.UpToDate ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
}

View File

@@ -106,6 +106,10 @@
<DependentUpon>ShortcutVisualControl.xaml</DependentUpon>
</Compile>
<Compile Include="Converters\ModuleEnabledToForegroundConverter.cs" />
<Compile Include="Converters\UpdatingStateCannotDownloadToVisibilityConverter.cs" />
<Compile Include="Converters\UpdatingStateReadyToDownloadToVisibilityConverter.cs" />
<Compile Include="Converters\UpdatingStateReadyToInstallToVisibilityConverter.cs" />
<Compile Include="Converters\UpdatingStateUpToDateToVisibilityConverter.cs" />
<Compile Include="Generated Files\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>

View File

@@ -400,6 +400,9 @@
<data name="GeneralPage_CheckForUpdates.Content" xml:space="preserve">
<value>Check for updates</value>
</data>
<data name="GeneralPage_UpdateNow.Content" xml:space="preserve">
<value>Update now</value>
</data>
<data name="GeneralPage_PrivacyStatement_URL.Text" xml:space="preserve">
<value>Privacy statement</value>
</data>
@@ -706,10 +709,10 @@
<value>Updates</value>
</data>
<data name="General_Version.Text" xml:space="preserve">
<value>Version:</value>
<value>Installed version:</value>
</data>
<data name="General_VersionLastChecked.Text" xml:space="preserve">
<value>Last successfully checked: </value>
<value>Last checked: </value>
</data>
<data name="General_Version.AutomationProperties.Name" xml:space="preserve">
<value>Version</value>
@@ -1194,4 +1197,34 @@ From there, simply click on a Markdown file or SVG icon in the File Explorer and
<data name="ShortcutGuide_OpenShortcutGuide.Header" xml:space="preserve">
<value>Open Shortcut Guide</value>
</data>
<data name="General_FailedToDownloadTheNewVersion.Text" xml:space="preserve">
<value>An error occurred trying to update to</value>
</data>
<data name="General_InstallNow.Content" xml:space="preserve">
<value>Install now</value>
</data>
<data name="General_ReadMore.Text" xml:space="preserve">
<value>Read more</value>
</data>
<data name="General_NewVersionAvailable.Text" xml:space="preserve">
<value>A new version is available: </value>
</data>
<data name="General_Downloading.Text" xml:space="preserve">
<value>Downloading...</value>
</data>
<data name="General_TryAgainToDownloadAndInstall.Content" xml:space="preserve">
<value>Try again to download and install</value>
</data>
<data name="General_CheckingForUpdates.Text" xml:space="preserve">
<value>Checking for updates...</value>
</data>
<data name="General_NewVersionReadyToInstall.Text" xml:space="preserve">
<value>A new version is ready to install:</value>
</data>
<data name="General_UpToDate.Text" xml:space="preserve">
<value>PowerToys is up to date</value>
</data>
<data name="General_DownloadAndInstall.Content" xml:space="preserve">
<value>Download and install</value>
</data>
</root>

View File

@@ -6,6 +6,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters"
xmlns:localConverters="using:Microsoft.PowerToys.Settings.UI.Converters"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
@@ -14,6 +15,10 @@
<Page.Resources>
<converters:BoolToObjectConverter x:Key="BoolToVisibilityConverter" TrueValue="Collapsed" FalseValue="Visible"/>
<converters:BoolToVisibilityConverter x:Key="VisibleIfTrueConverter"/>
<localConverters:UpdatingStateUpToDateToVisibilityConverter x:Key="UpdatingStateUpToDateToVisibilityConverter" />
<localConverters:UpdatingStateCannotDownloadToVisibilityConverter x:Key="UpdatingStateCannotDownloadToVisibilityConverter" />
<localConverters:UpdatingStateReadyToDownloadToVisibilityConverter x:Key="UpdatingStateReadyToDownloadToVisibilityConverter" />
<localConverters:UpdatingStateReadyToInstallToVisibilityConverter x:Key="UpdatingStateReadyToInstallToVisibilityConverter" />
</Page.Resources>
<Grid RowSpacing="{StaticResource DefaultRowSpacing}">
@@ -62,7 +67,7 @@
AutomationProperties.HeadingLevel="Level2"
Style="{StaticResource SubtitleTextBlockStyle}"/>
<TextBlock Text="{x:Bind Mode=TwoWay, Path=ViewModel.RunningAsText}"
<TextBlock Text="{Binding Mode=TwoWay, Path=RunningAsText}"
TextWrapping="Wrap"
Margin="{StaticResource SmallTopMargin}"/>
@@ -116,45 +121,176 @@
IsOn="{Binding Mode=TwoWay, Path=Startup}"/>
<TextBlock x:Uid="General_Updates"
Style="{StaticResource SettingsGroupTitleStyle}"/>
<StackPanel Orientation="Horizontal"
<StackPanel Visibility="{Binding PowerToysUpdatingState, Converter={StaticResource UpdatingStateUpToDateToVisibilityConverter}}">
<StackPanel Orientation="Horizontal"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
<TextBlock x:Name="General_Version_UpToDate"
x:Uid="General_Version"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<TextBlock Text="{Binding PowerToysVersion }"
Margin="4,0,0,0"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_VersionLastChecked}"
Visibility="{Binding AutoUpdatesEnabled, Converter={StaticResource VisibleIfTrueConverter}}">
<TextBlock x:Name="General_VersionLastChecked"
x:Uid="General_VersionLastChecked"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<TextBlock Text="{Binding UpdateCheckedDate, Mode=OneWay}"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
Margin="6,0" />
</StackPanel>
<TextBlock x:Name="General_CheckingForUpdates"
x:Uid="General_CheckingForUpdates"
Margin="{StaticResource SmallTopMargin}"
Visibility="{Binding IsNewVersionDownloading, Converter={StaticResource VisibleIfTrueConverter}}"/>
<TextBlock x:Name="General_UpToDate"
x:Uid="General_UpToDate"
Margin="{StaticResource SmallTopMargin}"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
Visibility="{Binding IsNewVersionCheckedAndUpToDate, Converter={StaticResource VisibleIfTrueConverter}}"/>
<Button x:Uid="GeneralPage_CheckForUpdates"
Style="{StaticResource AccentButtonStyle}"
Foreground="White"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
<TextBlock x:Name="General_Version" x:Uid="General_Version" />
<HyperlinkButton NavigateUri="https://github.com/microsoft/PowerToys/releases" Margin="4,-6,0,0">
<TextBlock Text="{x:Bind ViewModel.PowerToysVersion }" />
</HyperlinkButton>
<TextBlock Text="{x:Bind ViewModel.LatestAvailableVersion, Mode=OneWay}"
Foreground="{ThemeResource SystemControlErrorTextForegroundBrush}"
Margin="16,0,0,0" />
Command="{Binding CheckForUpdatesEventHandler}"
IsEnabled="{Binding IsDownloadAllowed}"
/>
</StackPanel>
<StackPanel Orientation="Horizontal"
Margin="{StaticResource SmallBottomMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_VersionLastChecked}"
Visibility="{Binding AutoUpdatesEnabled,
Converter={StaticResource VisibleIfTrueConverter}}">
<TextBlock x:Name="General_VersionLastChecked" x:Uid="General_VersionLastChecked" />
<TextBlock Text="{x:Bind ViewModel.UpdateCheckedDate, Mode=OneWay}"
Foreground="{ThemeResource ListViewItemForegroundPointerOver}"
Margin="6,0" />
<StackPanel Visibility="{Binding PowerToysUpdatingState, Converter={StaticResource UpdatingStateReadyToDownloadToVisibilityConverter}}">
<StackPanel Orientation="Horizontal"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
<TextBlock x:Name="General_Version_ReadyToDownload"
x:Uid="General_Version"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<TextBlock Text="{Binding PowerToysVersion }"
Margin="4,0,0,0"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
<TextBlock x:Name="General_NewVersionAvailable"
x:Uid="General_NewVersionAvailable"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink }" Margin="4,-6,0,0" IsEnabled="{Binding AutoUpdatesEnabled}">
<TextBlock Text="{Binding PowerToysNewAvailableVersion }" />
</HyperlinkButton>
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink}"
Margin="4,-6,0,0"
IsEnabled="{Binding AutoUpdatesEnabled}">
<TextBlock x:Name="General_ReadMore_ReadyToDownload" x:Uid="General_ReadMore" />
</HyperlinkButton>
</StackPanel>
<TextBlock x:Name="General_Downloading"
x:Uid="General_Downloading"
Visibility="{Binding Mode=OneWay, Path=IsNewVersionDownloading, Converter={StaticResource VisibleIfTrueConverter}}"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<Button x:Uid="General_DownloadAndInstall"
Margin="{StaticResource SmallTopMargin}"
Style="{StaticResource AccentButtonStyle}"
Foreground="White"
Command="{Binding UpdateNowButtonEventHandler}"
IsEnabled="{Binding IsDownloadAllowed}"/>
</StackPanel>
<Button x:Uid="GeneralPage_CheckForUpdates"
Style="{StaticResource AccentButtonStyle}"
Foreground="White"
Command="{Binding CheckForUpdatesEventHandler}"
IsEnabled="{Binding AutoUpdatesEnabled}"
/>
<StackPanel Visibility="{Binding PowerToysUpdatingState, Converter={StaticResource UpdatingStateReadyToInstallToVisibilityConverter}}">
<StackPanel Orientation="Horizontal"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
<TextBlock x:Name="General_Version_ReadyToInstall"
x:Uid="General_Version"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<TextBlock Text="{Binding PowerToysVersion }"
Margin="4,0,0,0"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
<TextBlock x:Name="General_NewVersionReadyToInstall"
x:Uid="General_NewVersionReadyToInstall"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink }" Margin="4,-6,0,0" IsEnabled="{Binding AutoUpdatesEnabled}">
<TextBlock Text="{Binding PowerToysNewAvailableVersion }" />
</HyperlinkButton>
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink}"
Margin="4,-6,0,0"
IsEnabled="{Binding AutoUpdatesEnabled}">
<TextBlock x:Name="General_ReadMore_ReadyToInstall" x:Uid="General_ReadMore" />
</HyperlinkButton>
</StackPanel>
<Button x:Uid="General_InstallNow"
Margin="{StaticResource SmallTopMargin}"
Style="{StaticResource AccentButtonStyle}"
Foreground="White"
Command="{Binding UpdateNowButtonEventHandler}"
IsEnabled="{Binding AutoUpdatesEnabled}"/>
</StackPanel>
<StackPanel Visibility="{Binding PowerToysUpdatingState, Converter={StaticResource UpdatingStateCannotDownloadToVisibilityConverter}}">
<StackPanel Orientation="Horizontal"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
<TextBlock x:Name="General_Version_Error"
x:Uid="General_Version"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<TextBlock Text="{Binding PowerToysVersion }"
Margin="4,0,0,0"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
Margin="{StaticResource SmallTopMargin}"
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
<TextBlock x:Name="General_FailedToDownloadTheNewVersion"
x:Uid="General_FailedToDownloadTheNewVersion"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink }" Margin="4,-6,0,0" IsEnabled="{Binding AutoUpdatesEnabled}">
<TextBlock Text="{Binding PowerToysNewAvailableVersion }" />
</HyperlinkButton>
</StackPanel>
<TextBlock x:Name="General_Downloading_TryAgain"
x:Uid="General_Downloading"
Visibility="{Binding Mode=OneWay, Path=IsNewVersionDownloading, Converter={StaticResource VisibleIfTrueConverter}}"
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
<Button x:Uid="General_TryAgainToDownloadAndInstall"
Margin="{StaticResource SmallTopMargin}"
Style="{StaticResource AccentButtonStyle}"
Foreground="White"
Command="{Binding UpdateNowButtonEventHandler}"
IsEnabled="{Binding IsDownloadAllowed}"/>
</StackPanel>
<ToggleSwitch x:Uid="GeneralPage_ToggleSwitch_AutoDownloadUpdates"
Margin="{StaticResource MediumTopMargin}"
Visibility="{Binding Mode=TwoWay, Path=IsAdmin, Converter={StaticResource VisibleIfTrueConverter}}"
IsOn="{Binding Mode=TwoWay, Path=AutoDownloadUpdates}"
IsEnabled="{Binding AutoUpdatesEnabled}" />
</StackPanel>
<RelativePanel x:Name="SidePanel"

View File

@@ -10,6 +10,7 @@ using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Microsoft.PowerToys.Settings.UI.Library.ViewModels;
using Windows.ApplicationModel.Resources;
using Windows.Data.Json;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@@ -38,6 +39,11 @@ namespace Microsoft.PowerToys.Settings.UI.Views
ResourceLoader loader = ResourceLoader.GetForViewIndependentUse();
var settingsUtils = new SettingsUtils();
Action stateUpdatingAction = async () =>
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, ViewModel.RefreshUpdatingState);
};
ViewModel = new GeneralViewModel(
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils),
loader.GetString("GeneralSettings_RunningAsAdminText"),
@@ -47,52 +53,9 @@ namespace Microsoft.PowerToys.Settings.UI.Views
UpdateUIThemeMethod,
ShellPage.SendDefaultIPCMessage,
ShellPage.SendRestartAdminIPCMessage,
ShellPage.SendCheckForUpdatesIPCMessage);
ShellPage.ShellHandler.IPCResponseHandleList.Add((JsonObject json) =>
{
try
{
string version = json.GetNamedString("version", string.Empty);
bool isLatest = json.GetNamedBoolean("isVersionLatest", false);
if (json.ContainsKey("version"))
{
ViewModel.RequestUpdateCheckedDate();
}
var str = string.Empty;
if (isLatest)
{
str = ResourceLoader.GetForCurrentView().GetString("GeneralSettings_VersionIsLatest");
}
else if (!string.IsNullOrEmpty(version))
{
str = ResourceLoader.GetForCurrentView().GetString("GeneralSettings_NewVersionIsAvailable");
if (!string.IsNullOrEmpty(str))
{
str += ": " + version;
}
}
// Using CurrentCulture since this is user-facing
if (!string.IsNullOrEmpty(str))
{
ViewModel.LatestAvailableVersion = string.Format(CultureInfo.CurrentCulture, str);
}
string updateStateDate = json.GetNamedString("updateStateDate", string.Empty);
if (!string.IsNullOrEmpty(updateStateDate) && long.TryParse(updateStateDate, out var uTCTime))
{
var localTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(uTCTime).ToLocalTime();
ViewModel.UpdateCheckedDate = localTime.ToString(CultureInfo.CurrentCulture);
}
}
catch (Exception e)
{
Logger.LogError("Exception encountered when reading the version.", e);
}
});
ShellPage.SendCheckForUpdatesIPCMessage,
string.Empty,
stateUpdatingAction);
DataContext = ViewModel;
}