mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
[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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user