From 8b34ab8b750a6374604aa215b637440d4a9916ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Climent?= Date: Fri, 15 Nov 2024 15:23:01 +0100 Subject: [PATCH 1/9] Add the skeleton for the new updater function --- src/UniGetUI.Core.Data/CoreData.cs | 1 + src/UniGetUI.Interface.Enums/Enums.cs | 1 + src/UniGetUI/App.xaml.cs | 141 ------------ src/UniGetUI/AutoUpdater.cs | 300 ++++++++++++++++++++++++++ src/UniGetUI/MainWindow.xaml.cs | 6 +- 5 files changed, 307 insertions(+), 142 deletions(-) create mode 100644 src/UniGetUI/AutoUpdater.cs diff --git a/src/UniGetUI.Core.Data/CoreData.cs b/src/UniGetUI.Core.Data/CoreData.cs index 96c35c711c..4aa2a58457 100644 --- a/src/UniGetUI.Core.Data/CoreData.cs +++ b/src/UniGetUI.Core.Data/CoreData.cs @@ -169,6 +169,7 @@ public static string IgnoredUpdatesDatabaseFile /// The ID of the notification that is used to inform the user that updates are available /// public const int UpdatesAvailableNotificationTag = 1234; + public const int UniGetUICanBeUpdated = 1235; /// diff --git a/src/UniGetUI.Interface.Enums/Enums.cs b/src/UniGetUI.Interface.Enums/Enums.cs index c76b7f8fd6..2992c8f12f 100644 --- a/src/UniGetUI.Interface.Enums/Enums.cs +++ b/src/UniGetUI.Interface.Enums/Enums.cs @@ -91,5 +91,6 @@ public class NotificationArguments public const string Show = "openUniGetUI"; public const string ShowOnUpdatesTab = "openUniGetUIOnUpdatesTab"; public const string UpdateAllPackages = "updateAll"; + public const string ReleaseSelfUpdateLock = "releaseSelfUpdateLock"; } } diff --git a/src/UniGetUI/App.xaml.cs b/src/UniGetUI/App.xaml.cs index 1dc0c939af..253b9f08f4 100644 --- a/src/UniGetUI/App.xaml.cs +++ b/src/UniGetUI/App.xaml.cs @@ -404,147 +404,6 @@ public async void DisposeAndQuit(int outputCode = 0) Environment.Exit(outputCode); } - private async void UpdateUniGetUIIfPossible(int round = 0) - { - InfoBar? banner = null; - try - { - Logger.Debug("Starting update check"); - - string fileContents; - - using (HttpClient client = new(CoreData.GenericHttpClientParameters)) - { - client.Timeout = TimeSpan.FromSeconds(600); - client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); - fileContents = await client.GetStringAsync("https://www.marticliment.com/versions/unigetui.ver"); - } - - if (!fileContents.Contains("///")) - { - throw new FormatException("The updates file does not follow the FloatVersion///Sha256Hash format"); - } - - float LatestVersion = float.Parse(fileContents.Split("///")[0].Replace("\n", "").Trim(), CultureInfo.InvariantCulture); - string InstallerHash = fileContents.Split("///")[1].Replace("\n", "").Trim().ToLower(); - - if (LatestVersion > CoreData.VersionNumber) - { - Logger.Info("Updates found, downloading installer..."); - Logger.Info("Current version: " + CoreData.VersionNumber.ToString(CultureInfo.InvariantCulture)); - Logger.Info("Latest version : " + LatestVersion.ToString(CultureInfo.InvariantCulture)); - - banner = MainWindow.UpdatesBanner; - banner.Title = CoreTools.Translate("WingetUI version {0} is being downloaded.", LatestVersion.ToString(CultureInfo.InvariantCulture)); - banner.Message = CoreTools.Translate("This may take a minute or two"); - banner.Severity = InfoBarSeverity.Informational; - banner.IsOpen = true; - banner.IsClosable = false; - - Uri DownloadUrl = new("https://github.com/marticliment/WingetUI/releases/latest/download/UniGetUI.Installer.exe"); - string InstallerPath = Path.Join(Directory.CreateTempSubdirectory().FullName, "unigetui-updater.exe"); - - using (HttpClient client = new(CoreData.GenericHttpClientParameters)) - { - client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); - HttpResponseMessage result = await client.GetAsync(DownloadUrl); - using FileStream fs = new(InstallerPath, FileMode.CreateNew); - await result.Content.CopyToAsync(fs); - } - - string Hash = ""; - SHA256 Sha256 = SHA256.Create(); - using (FileStream stream = File.OpenRead(InstallerPath)) - { - Hash = Convert.ToHexString(Sha256.ComputeHash(stream)).ToLower(); - } - - if (Hash == InstallerHash) - { - - banner.Title = CoreTools.Translate("WingetUI {0} is ready to be installed.", LatestVersion.ToString(CultureInfo.InvariantCulture)); - banner.Message = CoreTools.Translate("The update will be installed upon closing WingetUI"); - banner.ActionButton = new Button - { - Content = CoreTools.Translate("Update now") - }; - banner.ActionButton.Click += (_, _) => { MainWindow.HideWindow(); }; - banner.Severity = InfoBarSeverity.Success; - banner.IsOpen = true; - banner.IsClosable = true; - - if (MainWindow.Visible) - { - Logger.Debug("Waiting for mainWindow to be hidden"); - } - - while (MainWindow.Visible) - { - await Task.Delay(100); - } - - if (Settings.Get("DisableAutoUpdateWingetUI")) - { - Logger.Warn("User disabled updates!"); - return; - } - - Logger.ImportantInfo("The hash matches the expected value, starting update process..."); - Process p = new(); - p.StartInfo.FileName = "cmd.exe"; - p.StartInfo.Arguments = $"/c start /B \"\" \"{InstallerPath}\" /silent"; - p.StartInfo.UseShellExecute = true; - p.StartInfo.CreateNoWindow = true; - p.Start(); - DisposeAndQuit(); - } - else - { - Logger.Error("Hash mismatch, not updating!"); - Logger.Error("Current hash : " + Hash); - Logger.Error("Expected hash: " + InstallerHash); - File.Delete(InstallerPath); - - banner.Title = CoreTools.Translate("The installer hash does not match the expected value."); - banner.Message = CoreTools.Translate("The update will not continue."); - banner.Severity = InfoBarSeverity.Error; - banner.IsOpen = true; - banner.IsClosable = true; - - await Task.Delay(3600000); // Check again in 1 hour - UpdateUniGetUIIfPossible(); - } - } - else - { - Logger.Info("UniGetUI is up to date"); - await Task.Delay(3600000); // Check again in 1 hour - UpdateUniGetUIIfPossible(); - } - } - catch (Exception e) - { - if (banner is not null) - { - banner.Title = CoreTools.Translate("An error occurred when checking for updates: "); - banner.Message = e.Message; - banner.Severity = InfoBarSeverity.Error; - banner.IsOpen = true; - banner.IsClosable = true; - } - - Logger.Error(e); - - if (round >= 3) - { - return; - } - - await Task.Delay(600000); // Try again in 10 minutes - UpdateUniGetUIIfPossible(round + 1); - } - } - public void KillAndRestart() { Process.Start(CoreData.UniGetUIExecutableFile); diff --git a/src/UniGetUI/AutoUpdater.cs b/src/UniGetUI/AutoUpdater.cs new file mode 100644 index 0000000000..3501708728 --- /dev/null +++ b/src/UniGetUI/AutoUpdater.cs @@ -0,0 +1,300 @@ +using System.Diagnostics; +using System.Globalization; +using System.Security.Cryptography; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.Windows.AppNotifications; +using Microsoft.Windows.AppNotifications.Builder; +using UniGetUI.Core.Data; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; +using UniGetUI.Interface; +using UniGetUI.Interface.Enums; +using Version = YamlDotNet.Core.Version; + +namespace UniGetUI; + +public class AutoUpdater +{ + public static Window Window = null!; + public static InfoBar Banner = null!; + //------------------------------------------------------------------------------------------------------------------ + private const string STABLE_ENDPOINT = "https://www.marticliment.com/versions/unigetui-stable.ver"; + private const string BETA_ENDPOINT = "https://www.marticliment.com/versions/unigetui-beta.ver"; + private const string STABLE_INSTALLER_URL = "https://github.com/marticliment/UniGetUI/releases/latest/download/UniGetUI.Installer.exe"; + private const string BETA_INSTALLER_URL = "https://github.com/marticliment/UniGetUI/releases/download/$TAG/UniGetUI.Installer.exe"; + //------------------------------------------------------------------------------------------------------------------ + private static bool _installerHasBeenLaunched; + public static bool ReleaseLockForAutoupdate_Notification; + public static bool AnUpdateIsAwaitingWindowClose { get; private set; } + + public static async Task UpdateCheckLoop(Window window, InfoBar banner) + { + Window = window; + Banner = banner; + + bool result = await CheckAndInstallUpdates(window, banner, false); + + // TODO: Wait for internet connection + + // Check for updates + + // Set timer to check again in X time, X = ERROR ? 10min : 120min + } + + /// + /// Performs the entire update process, and returns true/false whether the process finished successfully; + /// + public static async Task CheckAndInstallUpdates(Window window, InfoBar banner, bool Verbose, bool AutoLaunch = false) + { + Window = window; + Banner = banner; + + try + { + if (Verbose) ShowMessage_ThreadSafe( + CoreTools.Translate("We are checking for updates."), + CoreTools.Translate("Please wait"), + InfoBarSeverity.Informational, + false + ); + + // Check for updates + string UpdatesEndpoint = Settings.Get("EnableUniGetUIBeta") ? BETA_ENDPOINT : STABLE_ENDPOINT; + string InstallerDownloadUrl = Settings.Get("EnableUniGetUIBeta") ? BETA_INSTALLER_URL : STABLE_INSTALLER_URL; + var (IsUpgradable, LatestVersion, InstallerHash) = await CheckForUpdates(UpdatesEndpoint); + + if (IsUpgradable) + { + InstallerDownloadUrl = InstallerDownloadUrl.Replace("$TAG", LatestVersion); + + Logger.Info($"An update to UniGetUI version {LatestVersion} is available"); + string InstallerPath = Path.Join(CoreData.UniGetUIDataDirectory, "Updater.exe"); + + if (File.Exists(InstallerPath) + && await CheckInstallerHash(InstallerPath, InstallerHash)) + { + Logger.Info($"A cached valid installer was found, launching update process..."); + return await PrepairToLaunchInstaller(InstallerPath, LatestVersion, AutoLaunch); + } + else + { + File.Delete(InstallerPath); + } + + ShowMessage_ThreadSafe( + CoreTools.Translate("UniGetUI version {0} is being downloaded.", LatestVersion.ToString(CultureInfo.InvariantCulture)), + CoreTools.Translate("This may take a minute or two"), + InfoBarSeverity.Informational, + false); + + // Download the installer + await DownloadInstaller(InstallerDownloadUrl, InstallerPath); + + if (await CheckInstallerHash(InstallerPath, InstallerHash)) + { + Logger.Info("The downloaded installer is valid, launching update process..."); + return await PrepairToLaunchInstaller(InstallerPath, LatestVersion, AutoLaunch); + } + else + { + ShowMessage_ThreadSafe( + CoreTools.Translate("The installer authenticity could not be verified."), + CoreTools.Translate("The update process has been aborted."), + InfoBarSeverity.Error, + true); + return false; + } + } + else + { + if (Verbose) ShowMessage_ThreadSafe( + CoreTools.Translate("Great! You are on the latest version."), + CoreTools.Translate("There are no new UniGetUI versions to be installed"), + InfoBarSeverity.Success, + true + ); + return true; + } + + } + catch (Exception e) + { + ShowMessage_ThreadSafe( + CoreTools.Translate("An error occurred when checking for updates: "), + e.Message, + InfoBarSeverity.Error, + true + ); + return false; + } + } + + /// + /// Checks whether new updates are available, and returns a tuple containing: + /// - A boolean that is set to True if new updates are available + /// - The new version name + /// - The hash of the installer for the new version, as a string. + /// + private static async Task<(bool, string, string)> CheckForUpdates(string endpoint) + { + Logger.Debug($"Begin check for updates on endpoint {endpoint}"); + string[] UpdateResponse; + using (HttpClient client = new(CoreData.GenericHttpClientParameters)) + { + client.Timeout = TimeSpan.FromSeconds(600); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + UpdateResponse = (await client.GetStringAsync(endpoint)).Split("///"); + } + + if (UpdateResponse.Length >= 2) + { + double LatestVersion = double.Parse(UpdateResponse[0].Replace("\n", "").Replace("\r", "").Trim(), CultureInfo.InvariantCulture); + string InstallerHash = UpdateResponse[1].Replace("\n", "").Replace("\r", "").Trim(); + string VersionName = UpdateResponse.Length >= 3 ? UpdateResponse[2] : LatestVersion.ToString(CultureInfo.InvariantCulture); + Logger.Debug($"Got response from endpoint: ({LatestVersion}, {VersionName}, {InstallerHash})"); + return (LatestVersion > CoreData.VersionNumber, VersionName, InstallerHash); + } + + Logger.Warn($"Received update string is {UpdateResponse[0]}"); + throw new FormatException("The updates file does not follow the FloatVersion///Sha256Hash[///VersionName] format"); + } + + /// + /// Checks whether the downloaded updater matches the hash. + /// + private static async Task CheckInstallerHash(string installerLocation, string expectedHash) + { + Logger.Debug($"Checking updater hash on location {installerLocation}"); + using (FileStream stream = File.OpenRead(installerLocation)) + { + string hash = Convert.ToHexString(await SHA256.Create().ComputeHashAsync(stream)).ToLower(); + if (hash == expectedHash.ToLower()) + { + Logger.Debug($"The hashes match ({hash})"); + return true; + } + Logger.Warn($"Hash mismatch.\nExpected: {expectedHash}\nGot: {hash}"); + return false; + } + } + + private static async Task DownloadInstaller(string downloadUrl, string installerLocation) + { + Logger.Debug($"Downloading installer from {downloadUrl} to {installerLocation}"); + using (HttpClient client = new(CoreData.GenericHttpClientParameters)) + { + client.Timeout = TimeSpan.FromSeconds(600); + client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); + HttpResponseMessage result = await client.GetAsync(downloadUrl); + using FileStream fs = new(installerLocation, FileMode.OpenOrCreate); + await result.Content.CopyToAsync(fs); + } + Logger.Debug("The download has finished successfully"); + } + + /// + /// Waits for the window to be closed if it is open and launches the updater + /// + private static async Task PrepairToLaunchInstaller(string installerLocation, string NewVersion, bool AutoLaunch) + { + Logger.Debug("Starting the process to launch the installer."); + AnUpdateIsAwaitingWindowClose = true; + + Window.DispatcherQueue.TryEnqueue(() => + { + // Set the banner to Restart UniGetUI to update + var UpdateNowButton = new Button { Content = CoreTools.Translate("Update now") }; + UpdateNowButton.Click += (_, _) => LaunchInstallerAndQuit(installerLocation); + ShowMessage_ThreadSafe( + CoreTools.Translate("UniGetUI {0} is ready to be installed.", NewVersion), + CoreTools.Translate("The update process will start after closing UniGetUI"), + InfoBarSeverity.Success, + true, + UpdateNowButton); + + // Show a toast notification + AppNotificationBuilder builder = new AppNotificationBuilder() + .SetScenario(AppNotificationScenario.Default) + .SetTag(CoreData.UniGetUICanBeUpdated.ToString()) + .AddText(CoreTools.Translate("{0} can be updated to version {1}", "UniGetUI", NewVersion)) + .SetAttributionText(CoreTools.Translate("You have currently version {0} installed", CoreData.VersionName)) + .AddArgument("action", NotificationArguments.Show) + .AddButton(new AppNotificationButton(CoreTools.Translate("Update now")) + .AddArgument("action", NotificationArguments.ReleaseSelfUpdateLock) + ); + AppNotification notification = builder.BuildNotification(); + notification.ExpiresOnReboot = true; + AppNotificationManager.Default.Show(notification); + + }); + + // Check if the user has disabled updates + if (Settings.Get("DisableAutoUpdateWingetUI")) + { + Logger.Warn("User disabled updates!"); + return true; + } + + if (AutoLaunch) + { + Logger.Debug("Waiting for mainWindow to be hidden or for user to trigger the update from the notification..."); + while (Window.Visible && !ReleaseLockForAutoupdate_Notification) await Task.Delay(100); + } + else + { + Logger.Debug("Waiting for user to trigger the update from the notification..."); + while (!ReleaseLockForAutoupdate_Notification) await Task.Delay(100); + } + LaunchInstallerAndQuit(installerLocation); + return true; + } + + /// + /// Launches the installer located on the installerLocation argument and quits UniGetUI + /// + private static void LaunchInstallerAndQuit(string installerLocation) + { + if (_installerHasBeenLaunched) + { + Logger.Warn("The installer has already been launched, something went wrong if you are seeing this."); + return; + } + + Logger.Debug("Launching the updater..."); + Process p = new() + { + StartInfo = new() + { + FileName = installerLocation, + Arguments = "/SILENT /SUPPRESSMSGBOXES /NORESTART /SP-", + UseShellExecute = true, + CreateNoWindow = true, + } + }; + p.Start(); + _installerHasBeenLaunched = true; + MainApp.Instance.DisposeAndQuit(0); + } + + private static void ShowMessage_ThreadSafe(string Title, string Message, InfoBarSeverity MessageSeverity, bool BannerClosable, Button? ActionButton = null) + { + if (Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread() is null) + { + Window.DispatcherQueue.TryEnqueue(() => ShowMessage_ThreadSafe(Title, Message, MessageSeverity, BannerClosable, ActionButton)); + return; + } + + Banner.Title = Title; + Banner.Message = Message; + Banner.Severity = MessageSeverity; + Banner.IsClosable = BannerClosable; + Banner.ActionButton = ActionButton; + Banner.IsOpen = true; + } + + + + +} diff --git a/src/UniGetUI/MainWindow.xaml.cs b/src/UniGetUI/MainWindow.xaml.cs index 6583710772..c8a48d7cf9 100644 --- a/src/UniGetUI/MainWindow.xaml.cs +++ b/src/UniGetUI/MainWindow.xaml.cs @@ -130,10 +130,14 @@ public void HandleNotificationActivation(AppNotificationActivatedEventArgs args) { Activate(); } + else if (action == NotificationArguments.ReleaseSelfUpdateLock) + { + AutoUpdater.ReleaseLockForAutoupdate_Notification = true; + } else { throw new ArgumentException( - "args.Argument was not set to a value present in Enums.NotificationArguments"); + $"args.Argument was not set to a value present in Enums.NotificationArguments (value is {action})"); } Logger.Debug("Notification activated: " + args.Arguments); From 27588e26fc95f17fe3f7813c6b543e1f97523f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Climent?= Date: Sat, 16 Nov 2024 12:53:21 +0100 Subject: [PATCH 2/9] Funal theoretical (still untested) code for the updater --- src/UniGetUI/App.xaml.cs | 6 -- src/UniGetUI/AutoUpdater.cs | 121 +++++++++++++++++++++++--------- src/UniGetUI/MainWindow.xaml.cs | 5 +- 3 files changed, 91 insertions(+), 41 deletions(-) diff --git a/src/UniGetUI/App.xaml.cs b/src/UniGetUI/App.xaml.cs index 253b9f08f4..5021f12741 100644 --- a/src/UniGetUI/App.xaml.cs +++ b/src/UniGetUI/App.xaml.cs @@ -228,12 +228,6 @@ private async Task LoadComponentsAsync() { try { - // Run other initializations asynchronously - if (!Settings.Get("DisableAutoUpdateWingetUI")) - { - UpdateUniGetUIIfPossible(); - } - IconDatabase.InitializeInstance(); IconDatabase.Instance.LoadIconAndScreenshotsDatabase(); diff --git a/src/UniGetUI/AutoUpdater.cs b/src/UniGetUI/AutoUpdater.cs index 3501708728..e22507abdc 100644 --- a/src/UniGetUI/AutoUpdater.cs +++ b/src/UniGetUI/AutoUpdater.cs @@ -1,6 +1,8 @@ using System.Diagnostics; using System.Globalization; +using System.Net.NetworkInformation; using System.Security.Cryptography; +using H.NotifyIcon; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.Windows.AppNotifications; @@ -25,22 +27,62 @@ public class AutoUpdater private const string STABLE_INSTALLER_URL = "https://github.com/marticliment/UniGetUI/releases/latest/download/UniGetUI.Installer.exe"; private const string BETA_INSTALLER_URL = "https://github.com/marticliment/UniGetUI/releases/download/$TAG/UniGetUI.Installer.exe"; //------------------------------------------------------------------------------------------------------------------ - private static bool _installerHasBeenLaunched; public static bool ReleaseLockForAutoupdate_Notification; - public static bool AnUpdateIsAwaitingWindowClose { get; private set; } + public static bool ReleaseLockForAutoupdate_Window; + public static bool ReleaseLockForAutoupdate_UpdateBanner; + public static bool UpdateReadyToBeInstalled { get; private set; } public static async Task UpdateCheckLoop(Window window, InfoBar banner) { + if (Settings.Get("DisableAutoUpdateWingetUI")) + { + Logger.Warn("User has disabled updates"); + return; + } + + bool IsFirstLaunch = true; Window = window; Banner = banner; - bool result = await CheckAndInstallUpdates(window, banner, false); - - // TODO: Wait for internet connection - - // Check for updates + await WaitForInternetConnection(); + while (true) + { + // User could have disabled updates on runtime + if (Settings.Get("DisableAutoUpdateWingetUI")) + { + Logger.Warn("User has disabled updates"); + return; + } + bool updateSucceeded = await CheckAndInstallUpdates(window, banner, IsFirstLaunch); + IsFirstLaunch = false; + await Task.Delay(TimeSpan.FromMinutes(updateSucceeded ? 60 : 10)); + } + } - // Set timer to check again in X time, X = ERROR ? 10min : 120min + /// + /// Pings the update server and 3 well-known sites to check for internet availability + /// + public static async Task WaitForInternetConnection() + { + Logger.Debug("Checking for internet connectivity. Pinging google.com, microsoft.com, couldflare.com and marticliment.com"); + string[] hosts = ["google.com", "microsoft.com", "cloudflare.com", "marticliment.com"]; + while (true) + { + using (var pinger = new Ping()) + { + foreach (var host in hosts) + { + PingReply reply = await pinger.SendPingAsync(host); + if (reply.Status is IPStatus.Success) + { + Logger.Debug($"{host} responded successfully to ping, internet connection was validated."); + return; + } + Logger.Debug($"Could not ping {host}!"); + } + } + await Task.Delay(TimeSpan.FromSeconds(5)); + } } /// @@ -50,6 +92,7 @@ public static async Task CheckAndInstallUpdates(Window window, InfoBar ban { Window = window; Banner = banner; + bool WasCheckingForUpdates = true; try { @@ -67,6 +110,7 @@ public static async Task CheckAndInstallUpdates(Window window, InfoBar ban if (IsUpgradable) { + WasCheckingForUpdates = false; InstallerDownloadUrl = InstallerDownloadUrl.Replace("$TAG", LatestVersion); Logger.Info($"An update to UniGetUI version {LatestVersion} is available"); @@ -121,7 +165,10 @@ public static async Task CheckAndInstallUpdates(Window window, InfoBar ban } catch (Exception e) { - ShowMessage_ThreadSafe( + Logger.Error("An error occurred while checking for updates: "); + Logger.Error(e); + // We don't want an error popping if updates can't + if(Verbose || !WasCheckingForUpdates) ShowMessage_ThreadSafe( CoreTools.Translate("An error occurred when checking for updates: "), e.Message, InfoBarSeverity.Error, @@ -180,6 +227,9 @@ private static async Task CheckInstallerHash(string installerLocation, str } } + /// + /// Downloads the given installer to the given location + /// private static async Task DownloadInstaller(string downloadUrl, string installerLocation) { Logger.Debug($"Downloading installer from {downloadUrl} to {installerLocation}"); @@ -200,13 +250,22 @@ private static async Task DownloadInstaller(string downloadUrl, string installer private static async Task PrepairToLaunchInstaller(string installerLocation, string NewVersion, bool AutoLaunch) { Logger.Debug("Starting the process to launch the installer."); - AnUpdateIsAwaitingWindowClose = true; + UpdateReadyToBeInstalled = true; + ReleaseLockForAutoupdate_Window = false; + ReleaseLockForAutoupdate_Notification = false; + + // Check if the user has disabled updates + if (Settings.Get("DisableAutoUpdateWingetUI")) + { + Logger.Warn("User disabled updates!"); + return true; + } Window.DispatcherQueue.TryEnqueue(() => { // Set the banner to Restart UniGetUI to update var UpdateNowButton = new Button { Content = CoreTools.Translate("Update now") }; - UpdateNowButton.Click += (_, _) => LaunchInstallerAndQuit(installerLocation); + UpdateNowButton.Click += (_, _) => ReleaseLockForAutoupdate_UpdateBanner = true; ShowMessage_ThreadSafe( CoreTools.Translate("UniGetUI {0} is ready to be installed.", NewVersion), CoreTools.Translate("The update process will start after closing UniGetUI"), @@ -230,23 +289,29 @@ private static async Task PrepairToLaunchInstaller(string installerLocatio }); - // Check if the user has disabled updates - if (Settings.Get("DisableAutoUpdateWingetUI")) + if (AutoLaunch && !Window.Visible) { - Logger.Warn("User disabled updates!"); - return true; + Logger.Debug("AutoLaunch is enabled and the Window is hidden, launching installer..."); } - - if (AutoLaunch) + else { - Logger.Debug("Waiting for mainWindow to be hidden or for user to trigger the update from the notification..."); - while (Window.Visible && !ReleaseLockForAutoupdate_Notification) await Task.Delay(100); + Logger.Debug("Waiting for mainWindow to be closed or for user to trigger the update from the notification..."); + while ( + !ReleaseLockForAutoupdate_Window && + !ReleaseLockForAutoupdate_Notification && + !ReleaseLockForAutoupdate_UpdateBanner) + { + await Task.Delay(100); + } + Logger.Debug("Autoupdater lock released, launching installer..."); } - else + + if (Settings.Get("DisableAutoUpdateWingetUI")) { - Logger.Debug("Waiting for user to trigger the update from the notification..."); - while (!ReleaseLockForAutoupdate_Notification) await Task.Delay(100); + Logger.Warn("User has disabled updates"); + return true; } + LaunchInstallerAndQuit(installerLocation); return true; } @@ -256,12 +321,6 @@ private static async Task PrepairToLaunchInstaller(string installerLocatio /// private static void LaunchInstallerAndQuit(string installerLocation) { - if (_installerHasBeenLaunched) - { - Logger.Warn("The installer has already been launched, something went wrong if you are seeing this."); - return; - } - Logger.Debug("Launching the updater..."); Process p = new() { @@ -274,8 +333,6 @@ private static void LaunchInstallerAndQuit(string installerLocation) } }; p.Start(); - _installerHasBeenLaunched = true; - MainApp.Instance.DisposeAndQuit(0); } private static void ShowMessage_ThreadSafe(string Title, string Message, InfoBarSeverity MessageSeverity, bool BannerClosable, Button? ActionButton = null) @@ -293,8 +350,4 @@ private static void ShowMessage_ThreadSafe(string Title, string Message, InfoBar Banner.ActionButton = ActionButton; Banner.IsOpen = true; } - - - - } diff --git a/src/UniGetUI/MainWindow.xaml.cs b/src/UniGetUI/MainWindow.xaml.cs index c8a48d7cf9..27a6c0e277 100644 --- a/src/UniGetUI/MainWindow.xaml.cs +++ b/src/UniGetUI/MainWindow.xaml.cs @@ -110,6 +110,8 @@ public MainWindow() { ParametersToProcess.Enqueue(arg); } + + _ = AutoUpdater.UpdateCheckLoop(this, UpdatesBanner); } public void HandleNotificationActivation(AppNotificationActivatedEventArgs args) @@ -148,8 +150,9 @@ public void HandleNotificationActivation(AppNotificationActivatedEventArgs args) /// public async void HandleClosingEvent(AppWindow sender, AppWindowClosingEventArgs args) { + AutoUpdater.ReleaseLockForAutoupdate_Window = true; SaveGeometry(Force: true); - if (!Settings.Get("DisableSystemTray")) + if (!Settings.Get("DisableSystemTray") || AutoUpdater.UpdateReadyToBeInstalled) { args.Cancel = true; try From c4e69c6f07754086e2a96047903c53bfc2138431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Climent?= Date: Sat, 16 Nov 2024 12:55:55 +0100 Subject: [PATCH 3/9] add mising flag reset --- src/UniGetUI/AutoUpdater.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/UniGetUI/AutoUpdater.cs b/src/UniGetUI/AutoUpdater.cs index e22507abdc..37392c47d5 100644 --- a/src/UniGetUI/AutoUpdater.cs +++ b/src/UniGetUI/AutoUpdater.cs @@ -253,6 +253,7 @@ private static async Task PrepairToLaunchInstaller(string installerLocatio UpdateReadyToBeInstalled = true; ReleaseLockForAutoupdate_Window = false; ReleaseLockForAutoupdate_Notification = false; + ReleaseLockForAutoupdate_UpdateBanner = false; // Check if the user has disabled updates if (Settings.Get("DisableAutoUpdateWingetUI")) From ed0c7760eb5d681e54df614b0ae3e6f178a45bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Climent?= Date: Sat, 16 Nov 2024 16:05:38 +0100 Subject: [PATCH 4/9] Update channel and force check for updates button added to Settings page --- scripts/translation_utils.py | 2 + src/UniGetUI/AutoUpdater.cs | 2 +- .../SettingsWidgets/CheckboxButtonCard.cs | 85 +++++++++++++++++++ src/UniGetUI/Pages/SettingsPage.xaml | 11 ++- src/UniGetUI/Pages/SettingsPage.xaml.cs | 6 ++ src/UniGetUI/UniGetUI.csproj.user | 2 +- 6 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 src/UniGetUI/Controls/SettingsWidgets/CheckboxButtonCard.cs diff --git a/scripts/translation_utils.py b/scripts/translation_utils.py index 1faec50a2d..4df41371d3 100644 --- a/scripts/translation_utils.py +++ b/scripts/translation_utils.py @@ -50,6 +50,8 @@ def get_all_strings(): r'<[a-zA-Z0-9]+:ButtonCard' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'), r'<[a-zA-Z0-9]+:ButtonCard' + MAIN_WILDCARD + r'+ButtonText=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" ButtonText=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'), r'<[a-zA-Z0-9]+:CheckboxCard' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'), + r'<[a-zA-Z0-9]+:CheckboxButtonCard' + MAIN_WILDCARD + r'+CheckboxText=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'), + r'<[a-zA-Z0-9]+:CheckboxButtonCard' + MAIN_WILDCARD + r'+ButtonText=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'), r'<[a-zA-Z0-9]+:ComboboxCard' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'), r'<[a-zA-Z0-9]+:BetterMenuItem' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'), r'<[a-zA-Z0-9]+:NavButton' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'), diff --git a/src/UniGetUI/AutoUpdater.cs b/src/UniGetUI/AutoUpdater.cs index 37392c47d5..e5f13e7da9 100644 --- a/src/UniGetUI/AutoUpdater.cs +++ b/src/UniGetUI/AutoUpdater.cs @@ -53,7 +53,7 @@ public static async Task UpdateCheckLoop(Window window, InfoBar banner) Logger.Warn("User has disabled updates"); return; } - bool updateSucceeded = await CheckAndInstallUpdates(window, banner, IsFirstLaunch); + bool updateSucceeded = await CheckAndInstallUpdates(window, banner, false, IsFirstLaunch); IsFirstLaunch = false; await Task.Delay(TimeSpan.FromMinutes(updateSucceeded ? 60 : 10)); } diff --git a/src/UniGetUI/Controls/SettingsWidgets/CheckboxButtonCard.cs b/src/UniGetUI/Controls/SettingsWidgets/CheckboxButtonCard.cs new file mode 100644 index 0000000000..0936b959bb --- /dev/null +++ b/src/UniGetUI/Controls/SettingsWidgets/CheckboxButtonCard.cs @@ -0,0 +1,85 @@ +using CommunityToolkit.WinUI.Controls; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.Tools; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace UniGetUI.Interface.Widgets +{ + public sealed class CheckboxButtonCard : SettingsCard + { + public CheckBox CheckBox; + public Button Button; + private bool IS_INVERTED; + + private string setting_name = ""; + public string SettingName + { + set { + setting_name = value; + IS_INVERTED = value.StartsWith("Disable"); + CheckBox.IsChecked = Settings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + } + } + + public bool ForceInversion { get; set; } + + public bool Checked + { + get => CheckBox.IsChecked ?? false; + } + public event EventHandler? StateChanged; + public new event EventHandler? Click; + + public string CheckboxText + { + set => CheckBox.Content = CoreTools.Translate(value); + } + + public string ButtonText + { + set => Button.Content = CoreTools.Translate(value); + } + + private bool _buttonAlwaysOn; + public bool ButtonAlwaysOn + { + set => _buttonAlwaysOn = value; + } + + + public CheckboxButtonCard() + { + Button = new Button(); + CheckBox = new CheckBox(); + IS_INVERTED = false; + + //ContentAlignment = ContentAlignment.Left; + //HorizontalAlignment = HorizontalAlignment.Stretch; + + DefaultStyleKey = typeof(CheckboxCard); + Description = CheckBox; + Content = Button; + CheckBox.HorizontalAlignment = HorizontalAlignment.Stretch; + CheckBox.Checked += (_, _) => + { + Settings.Set(setting_name, true ^ IS_INVERTED ^ ForceInversion); + StateChanged?.Invoke(this, EventArgs.Empty); + Button.IsEnabled = true; + }; + + CheckBox.Unchecked += (_, _) => + { + Settings.Set(setting_name, false ^ IS_INVERTED ^ ForceInversion); + StateChanged?.Invoke(this, EventArgs.Empty); + Button.IsEnabled = _buttonAlwaysOn; + }; + + Button.MinWidth = 200; + Button.Click += (s, e) => Click?.Invoke(s, e); + } + } +} diff --git a/src/UniGetUI/Pages/SettingsPage.xaml b/src/UniGetUI/Pages/SettingsPage.xaml index a4a21f1150..043925fdbf 100644 --- a/src/UniGetUI/Pages/SettingsPage.xaml +++ b/src/UniGetUI/Pages/SettingsPage.xaml @@ -75,9 +75,16 @@ Click="OpenWelcomeWizard" IsEnabled="False" /--> - + ProjectDebugger - ModernWindow (Unpackaged) + UniGetUI (Unpackaged) From e150ad9c9db8274f63a20d5c18d7b19b44adc06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Climent?= Date: Sat, 16 Nov 2024 16:18:06 +0100 Subject: [PATCH 5/9] Replace VersionNumber for BuildNumber --- src/UniGetUI.Core.Data.Tests/CoreTests.cs | 5 +---- src/UniGetUI.Core.Data/CoreData.cs | 2 +- .../BackgroundApi.cs | 2 +- src/UniGetUI/AutoUpdater.cs | 18 +++++++++--------- src/UniGetUI/EntryPoint.cs | 2 +- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/UniGetUI.Core.Data.Tests/CoreTests.cs b/src/UniGetUI.Core.Data.Tests/CoreTests.cs index c49d0b56df..8a9f31509e 100644 --- a/src/UniGetUI.Core.Data.Tests/CoreTests.cs +++ b/src/UniGetUI.Core.Data.Tests/CoreTests.cs @@ -23,12 +23,9 @@ public void CheckDirectoryAttributes(string directory) public void CheckOtherAttributes() { Assert.NotEmpty(CoreData.VersionName); - Assert.NotEqual(0, CoreData.VersionNumber); + Assert.NotEqual(0, CoreData.BuildNumber); Assert.True(File.Exists(CoreData.IgnoredUpdatesDatabaseFile), "The Ignored Updates database file does not exist, but it should have been created automatically."); - int notif_3 = CoreData.UpdatesAvailableNotificationTag; - int notif_4 = CoreData.UpdatesAvailableNotificationTag; - Assert.True(notif_3 == notif_4, "The UpdatesAvailableNotificationId must be always the same"); Assert.NotEqual(0, CoreData.UpdatesAvailableNotificationTag); Assert.True(Directory.Exists(CoreData.UniGetUIExecutableDirectory), "Directory where the executable is located does not exist"); diff --git a/src/UniGetUI.Core.Data/CoreData.cs b/src/UniGetUI.Core.Data/CoreData.cs index 4aa2a58457..3eb033b815 100644 --- a/src/UniGetUI.Core.Data/CoreData.cs +++ b/src/UniGetUI.Core.Data/CoreData.cs @@ -47,7 +47,7 @@ private static int GetCodePage() } public const string VersionName = "3.1.4-beta1"; // Do not modify this line, use file scripts/apply_versions.py - public const double VersionNumber = 3.14; // Do not modify this line, use file scripts/apply_versions.py + public const int BuildNumber = 70; // Do not modify this line, use file scripts/apply_versions.py public const string UserAgentString = $"UniGetUI/{VersionName} (https://marticliment.com/unigetui/; contact@marticliment.com)"; diff --git a/src/UniGetUI.Interface.BackgroundApi/BackgroundApi.cs b/src/UniGetUI.Interface.BackgroundApi/BackgroundApi.cs index fdcefa9fc4..2b3fc55c57 100644 --- a/src/UniGetUI.Interface.BackgroundApi/BackgroundApi.cs +++ b/src/UniGetUI.Interface.BackgroundApi/BackgroundApi.cs @@ -174,7 +174,7 @@ public void BuildV1WidgetsApi() return 401; } - return CoreData.VersionNumber.ToString(); + return CoreData.BuildNumber.ToString(); }); // Return found updates diff --git a/src/UniGetUI/AutoUpdater.cs b/src/UniGetUI/AutoUpdater.cs index e5f13e7da9..ccfe0cf597 100644 --- a/src/UniGetUI/AutoUpdater.cs +++ b/src/UniGetUI/AutoUpdater.cs @@ -22,8 +22,8 @@ public class AutoUpdater public static Window Window = null!; public static InfoBar Banner = null!; //------------------------------------------------------------------------------------------------------------------ - private const string STABLE_ENDPOINT = "https://www.marticliment.com/versions/unigetui-stable.ver"; - private const string BETA_ENDPOINT = "https://www.marticliment.com/versions/unigetui-beta.ver"; + private const string STABLE_ENDPOINT = "https://www.marticliment.com/versions/unigetui/stable.ver"; + private const string BETA_ENDPOINT = "https://www.marticliment.com/versions/unigetui/beta.ver"; private const string STABLE_INSTALLER_URL = "https://github.com/marticliment/UniGetUI/releases/latest/download/UniGetUI.Installer.exe"; private const string BETA_INSTALLER_URL = "https://github.com/marticliment/UniGetUI/releases/download/$TAG/UniGetUI.Installer.exe"; //------------------------------------------------------------------------------------------------------------------ @@ -192,20 +192,20 @@ public static async Task CheckAndInstallUpdates(Window window, InfoBar ban { client.Timeout = TimeSpan.FromSeconds(600); client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); - UpdateResponse = (await client.GetStringAsync(endpoint)).Split("///"); + UpdateResponse = (await client.GetStringAsync(endpoint)).Split("////"); } - if (UpdateResponse.Length >= 2) + if (UpdateResponse.Length >= 3) { - double LatestVersion = double.Parse(UpdateResponse[0].Replace("\n", "").Replace("\r", "").Trim(), CultureInfo.InvariantCulture); + int LatestVersion = int.Parse(UpdateResponse[0].Replace("\n", "").Replace("\r", "").Trim()); string InstallerHash = UpdateResponse[1].Replace("\n", "").Replace("\r", "").Trim(); - string VersionName = UpdateResponse.Length >= 3 ? UpdateResponse[2] : LatestVersion.ToString(CultureInfo.InvariantCulture); + string VersionName = UpdateResponse[2].Replace("\n", "").Replace("\r", "").Trim(); Logger.Debug($"Got response from endpoint: ({LatestVersion}, {VersionName}, {InstallerHash})"); - return (LatestVersion > CoreData.VersionNumber, VersionName, InstallerHash); + return (LatestVersion > CoreData.BuildNumber, VersionName, InstallerHash); } Logger.Warn($"Received update string is {UpdateResponse[0]}"); - throw new FormatException("The updates file does not follow the FloatVersion///Sha256Hash[///VersionName] format"); + throw new FormatException("The updates file does not follow the FloatVersion////Sha256Hash////VersionName format"); } /// @@ -333,7 +333,7 @@ private static void LaunchInstallerAndQuit(string installerLocation) CreateNoWindow = true, } }; - p.Start(); + // p.Start(); } private static void ShowMessage_ThreadSafe(string Title, string Message, InfoBarSeverity MessageSeverity, bool BannerClosable, Button? ActionButton = null) diff --git a/src/UniGetUI/EntryPoint.cs b/src/UniGetUI/EntryPoint.cs index 8a96f4ee86..71702ada15 100644 --- a/src/UniGetUI/EntryPoint.cs +++ b/src/UniGetUI/EntryPoint.cs @@ -55,7 +55,7 @@ Welcome to UniGetUI Version {CoreData.VersionName} Logger.ImportantInfo(textart); Logger.ImportantInfo(" "); - Logger.ImportantInfo($"Version Code: {CoreData.VersionNumber}"); + Logger.ImportantInfo($"Build {CoreData.BuildNumber}"); Logger.ImportantInfo($"Encoding Code Page set to {CoreData.CODE_PAGE}"); // WinRT single-instance fancy stuff From f542119ae38768058db8bc17ff2df8d93c7c4167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Climent?= Date: Sat, 16 Nov 2024 19:01:26 +0100 Subject: [PATCH 6/9] tweaks to the autoupdater --- src/UniGetUI/AutoUpdater.cs | 50 ++++++++++++++----- .../SettingsWidgets/CheckboxButtonCard.cs | 2 + src/UniGetUI/Pages/SettingsPage.xaml | 1 - 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/UniGetUI/AutoUpdater.cs b/src/UniGetUI/AutoUpdater.cs index ccfe0cf597..826b226833 100644 --- a/src/UniGetUI/AutoUpdater.cs +++ b/src/UniGetUI/AutoUpdater.cs @@ -114,7 +114,7 @@ public static async Task CheckAndInstallUpdates(Window window, InfoBar ban InstallerDownloadUrl = InstallerDownloadUrl.Replace("$TAG", LatestVersion); Logger.Info($"An update to UniGetUI version {LatestVersion} is available"); - string InstallerPath = Path.Join(CoreData.UniGetUIDataDirectory, "Updater.exe"); + string InstallerPath = Path.Join(CoreData.UniGetUIDataDirectory, "UniGetUI Updater.exe"); if (File.Exists(InstallerPath) && await CheckInstallerHash(InstallerPath, InstallerHash)) @@ -238,6 +238,7 @@ private static async Task DownloadInstaller(string downloadUrl, string installer client.Timeout = TimeSpan.FromSeconds(600); client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString); HttpResponseMessage result = await client.GetAsync(downloadUrl); + result.EnsureSuccessStatusCode(); using FileStream fs = new(installerLocation, FileMode.OpenOrCreate); await result.Content.CopyToAsync(fs); } @@ -258,6 +259,7 @@ private static async Task PrepairToLaunchInstaller(string installerLocatio // Check if the user has disabled updates if (Settings.Get("DisableAutoUpdateWingetUI")) { + Banner.IsOpen = false; Logger.Warn("User disabled updates!"); return true; } @@ -313,14 +315,14 @@ private static async Task PrepairToLaunchInstaller(string installerLocatio return true; } - LaunchInstallerAndQuit(installerLocation); + await LaunchInstallerAndQuit(installerLocation); return true; } /// /// Launches the installer located on the installerLocation argument and quits UniGetUI /// - private static void LaunchInstallerAndQuit(string installerLocation) + private static async Task LaunchInstallerAndQuit(string installerLocation) { Logger.Debug("Launching the updater..."); Process p = new() @@ -333,22 +335,44 @@ private static void LaunchInstallerAndQuit(string installerLocation) CreateNoWindow = true, } }; - // p.Start(); + p.Start(); + ShowMessage_ThreadSafe( + CoreTools.Translate("UniGetUI is being updated..."), + CoreTools.Translate("This may take a minute or two"), + InfoBarSeverity.Informational, + false + ); + await p.WaitForExitAsync(); + ShowMessage_ThreadSafe( + CoreTools.Translate("Something went wrong while launching the updater."), + CoreTools.Translate("Please try again later"), + InfoBarSeverity.Error, + true + ); } private static void ShowMessage_ThreadSafe(string Title, string Message, InfoBarSeverity MessageSeverity, bool BannerClosable, Button? ActionButton = null) { - if (Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread() is null) + try { - Window.DispatcherQueue.TryEnqueue(() => ShowMessage_ThreadSafe(Title, Message, MessageSeverity, BannerClosable, ActionButton)); - return; + if (Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread() is null) + { + Window.DispatcherQueue.TryEnqueue(() => + ShowMessage_ThreadSafe(Title, Message, MessageSeverity, BannerClosable, ActionButton)); + return; + } + + Banner.Title = Title; + Banner.Message = Message; + Banner.Severity = MessageSeverity; + Banner.IsClosable = BannerClosable; + Banner.ActionButton = ActionButton; + Banner.IsOpen = true; + } + catch (Exception ex) + { + Logger.Error(ex); } - Banner.Title = Title; - Banner.Message = Message; - Banner.Severity = MessageSeverity; - Banner.IsClosable = BannerClosable; - Banner.ActionButton = ActionButton; - Banner.IsOpen = true; } } diff --git a/src/UniGetUI/Controls/SettingsWidgets/CheckboxButtonCard.cs b/src/UniGetUI/Controls/SettingsWidgets/CheckboxButtonCard.cs index 0936b959bb..3fee7e56f7 100644 --- a/src/UniGetUI/Controls/SettingsWidgets/CheckboxButtonCard.cs +++ b/src/UniGetUI/Controls/SettingsWidgets/CheckboxButtonCard.cs @@ -22,6 +22,7 @@ public string SettingName setting_name = value; IS_INVERTED = value.StartsWith("Disable"); CheckBox.IsChecked = Settings.Get(setting_name) ^ IS_INVERTED ^ ForceInversion; + Button.IsEnabled = (CheckBox.IsChecked ?? false) || _buttonAlwaysOn ; } } @@ -78,6 +79,7 @@ public CheckboxButtonCard() Button.IsEnabled = _buttonAlwaysOn; }; + Button.MinWidth = 200; Button.Click += (s, e) => Click?.Invoke(s, e); } diff --git a/src/UniGetUI/Pages/SettingsPage.xaml b/src/UniGetUI/Pages/SettingsPage.xaml index 043925fdbf..1ca315a095 100644 --- a/src/UniGetUI/Pages/SettingsPage.xaml +++ b/src/UniGetUI/Pages/SettingsPage.xaml @@ -79,7 +79,6 @@ CheckboxText="Update WingetUI automatically" ButtonText="Check for updates" SettingName="DisableAutoUpdateWingetUI" - ButtonAlwaysOn="True" Click="ForceUpdateUniGetUI_OnClick" /> Date: Sat, 16 Nov 2024 19:22:05 +0100 Subject: [PATCH 7/9] Improvements to how the AutoUpdater waits until an internet connection is available --- src/UniGetUI.Core.Tools/Tools.cs | 40 ++++++++++++++++++++++++++++++++ src/UniGetUI/AutoUpdater.cs | 28 +--------------------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/UniGetUI.Core.Tools/Tools.cs b/src/UniGetUI.Core.Tools/Tools.cs index 7d7ff1e2c6..9e21d427b4 100644 --- a/src/UniGetUI.Core.Tools/Tools.cs +++ b/src/UniGetUI.Core.Tools/Tools.cs @@ -2,9 +2,11 @@ using System.Diagnostics; using System.Globalization; using System.Net; +using System.Net.NetworkInformation; using System.Security.Cryptography; using System.Security.Principal; using System.Text; +using UniGetUI.Core.Classes; using UniGetUI.Core.Data; using UniGetUI.Core.Language; using UniGetUI.Core.Logging; @@ -542,5 +544,43 @@ public static ProcessStartInfo UpdateEnvironmentVariables(ProcessStartInfo info) } return info; } + + + /// + /// Pings the update server and 3 well-known sites to check for internet availability + /// + public static async Task WaitForInternetConnection() + => await (await TaskRecycler.RunOrAttachAsync(_waitForInternetConnection)); + + public static async Task _waitForInternetConnection() + { + Logger.Debug("Checking for internet connectivity. Pinging google.com, microsoft.com, couldflare.com and marticliment.com"); + string[] hosts = ["google.com", "microsoft.com", "cloudflare.com", "marticliment.com"]; + while (true) + { + foreach (var host in hosts) + { + using (var pinger = new Ping()) + { + try + { + PingReply reply = await pinger.SendPingAsync(host, 10); + if (reply.Status is IPStatus.Success) + { + Logger.Debug($"{host} responded successfully to ping, internet connection was validated."); + return; + } + + Logger.Debug($"Could not ping {host}!"); + } + catch (Exception ex) + { + Logger.Debug($"Could not ping {host} with error {ex.Message}. Are you connected to the internet?"); + } + } + } + await Task.Delay(TimeSpan.FromSeconds(5)); + } + } } } diff --git a/src/UniGetUI/AutoUpdater.cs b/src/UniGetUI/AutoUpdater.cs index 826b226833..adec375c8f 100644 --- a/src/UniGetUI/AutoUpdater.cs +++ b/src/UniGetUI/AutoUpdater.cs @@ -44,7 +44,7 @@ public static async Task UpdateCheckLoop(Window window, InfoBar banner) Window = window; Banner = banner; - await WaitForInternetConnection(); + await CoreTools.WaitForInternetConnection(); while (true) { // User could have disabled updates on runtime @@ -59,32 +59,6 @@ public static async Task UpdateCheckLoop(Window window, InfoBar banner) } } - /// - /// Pings the update server and 3 well-known sites to check for internet availability - /// - public static async Task WaitForInternetConnection() - { - Logger.Debug("Checking for internet connectivity. Pinging google.com, microsoft.com, couldflare.com and marticliment.com"); - string[] hosts = ["google.com", "microsoft.com", "cloudflare.com", "marticliment.com"]; - while (true) - { - using (var pinger = new Ping()) - { - foreach (var host in hosts) - { - PingReply reply = await pinger.SendPingAsync(host); - if (reply.Status is IPStatus.Success) - { - Logger.Debug($"{host} responded successfully to ping, internet connection was validated."); - return; - } - Logger.Debug($"Could not ping {host}!"); - } - } - await Task.Delay(TimeSpan.FromSeconds(5)); - } - } - /// /// Performs the entire update process, and returns true/false whether the process finished successfully; /// From 28b97be813440d406eaaded3a3874948dca7d50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Climent?= Date: Sun, 17 Nov 2024 10:12:27 +0100 Subject: [PATCH 8/9] Add an autoincremented build number counter to the build script --- UniGetUI.iss | 4 ++-- scripts/BuildNumber | 1 + scripts/apply_versions.py | 22 +++++++++++++++++----- src/SharedAssemblyInfo.cs | 6 +++--- src/UniGetUI.Core.Data/CoreData.cs | 2 +- src/UniGetUI/app.manifest | 2 +- 6 files changed, 25 insertions(+), 12 deletions(-) create mode 100644 scripts/BuildNumber diff --git a/UniGetUI.iss b/UniGetUI.iss index 2692996635..50cf1f48ab 100644 --- a/UniGetUI.iss +++ b/UniGetUI.iss @@ -1,7 +1,7 @@ ; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! -#define MyAppVersion "3.1.2" +#define MyAppVersion "3.1.4-beta1" #define MyAppName "UniGetUI (formerly WingetUI)" #define MyAppPublisher "Martí Climent" #define MyAppURL "https://github.com/marticliment/UniGetUI" @@ -23,7 +23,7 @@ AppPublisher={#MyAppPublisher} AppPublisherURL="https://www.marticliment.com/unigetui/" AppSupportURL={#MyAppURL} AppUpdatesURL={#MyAppURL} -VersionInfoVersion=3.1.2.0 +VersionInfoVersion=3.1.4.0 DefaultDirName="{autopf64}\UniGetUI" DisableProgramGroupPage=yes DisableDirPage=no diff --git a/scripts/BuildNumber b/scripts/BuildNumber new file mode 100644 index 0000000000..8c0474e323 --- /dev/null +++ b/scripts/BuildNumber @@ -0,0 +1 @@ +69 \ No newline at end of file diff --git a/scripts/apply_versions.py b/scripts/apply_versions.py index 1d29718d66..42e821ffb2 100644 --- a/scripts/apply_versions.py +++ b/scripts/apply_versions.py @@ -4,14 +4,26 @@ os.chdir(os.path.join(os.path.dirname(__file__), "..")) # move to root project try: - floatval = input("Enter version code (X.XXX) : ") + # floatval = input("Enter version code (X.XXX) : ") + # versionCode = float(floatval) + versionName = str(input("Enter version name (string) : ")) - if floatval == "": + if versionName == "": print("Version changer script aborted") exit() + + BuildNumber = -1 + c = "" + if os.path.exists("scripts/BuildNumber"): + with open("scripts/BuildNumber", "r") as f: + c = f.read() + + BuildNumber = int(c) if c != "" else int(input("Build number file was empty. Insert (integer) build number: "))-1 + print(f"Build number set to {BuildNumber+1}") + with open("scripts/BuildNumber", "w") as f: + f.write(str(BuildNumber+1)) + - versionCode = float(floatval) - versionName = str(input("Enter version name (string) : ")) versionISS = str(input("Enter version (X.X.X.X) : ")) def fileReplaceLinesWith(filename: str, list: dict[str, str], encoding="utf-8"): @@ -32,7 +44,7 @@ def fileReplaceLinesWith(filename: str, list: dict[str, str], encoding="utf-8"): fileReplaceLinesWith("src/UniGetUI.Core.Data/CoreData.cs", { " public const string VersionName = ": f" \"{versionName}\"; // Do not modify this line, use file scripts/apply_versions.py\n", - " public const double VersionNumber = ": f" {versionCode}; // Do not modify this line, use file scripts/apply_versions.py\n", + " public const int BuildNumber = ": f" {BuildNumber+1}; // Do not modify this line, use file scripts/apply_versions.py\n", }, encoding="utf-8-sig") fileReplaceLinesWith("src/SharedAssemblyInfo.cs", { diff --git a/src/SharedAssemblyInfo.cs b/src/SharedAssemblyInfo.cs index 875020225d..5b6f6a6296 100644 --- a/src/SharedAssemblyInfo.cs +++ b/src/SharedAssemblyInfo.cs @@ -6,7 +6,7 @@ [assembly: AssemblyTitle("UniGetUI")] [assembly: AssemblyDefaultAlias("UniGetUI")] [assembly: AssemblyCopyright("2024, Martí Climent")] -[assembly: AssemblyVersion("3.1.2.0")] -[assembly: AssemblyFileVersion("3.1.2.0")] -[assembly: AssemblyInformationalVersion("3.1.2")] +[assembly: AssemblyVersion("3.1.4.0")] +[assembly: AssemblyFileVersion("3.1.4.0")] +[assembly: AssemblyInformationalVersion("3.1.4-beta1")] [assembly: SupportedOSPlatform("windows10.0.19041")] diff --git a/src/UniGetUI.Core.Data/CoreData.cs b/src/UniGetUI.Core.Data/CoreData.cs index 3eb033b815..de49906ff5 100644 --- a/src/UniGetUI.Core.Data/CoreData.cs +++ b/src/UniGetUI.Core.Data/CoreData.cs @@ -47,7 +47,7 @@ private static int GetCodePage() } public const string VersionName = "3.1.4-beta1"; // Do not modify this line, use file scripts/apply_versions.py - public const int BuildNumber = 70; // Do not modify this line, use file scripts/apply_versions.py + public const int BuildNumber = 69; // Do not modify this line, use file scripts/apply_versions.py public const string UserAgentString = $"UniGetUI/{VersionName} (https://marticliment.com/unigetui/; contact@marticliment.com)"; diff --git a/src/UniGetUI/app.manifest b/src/UniGetUI/app.manifest index c899a29bb2..70ca760360 100644 --- a/src/UniGetUI/app.manifest +++ b/src/UniGetUI/app.manifest @@ -2,7 +2,7 @@ From af06b27703530fb8de89243df8b607192cbe27bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Climent?= Date: Sun, 17 Nov 2024 10:13:54 +0100 Subject: [PATCH 9/9] Update build number --- scripts/BuildNumber | 2 +- src/UniGetUI.Core.Data/CoreData.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/BuildNumber b/scripts/BuildNumber index 8c0474e323..d7765fe47e 100644 --- a/scripts/BuildNumber +++ b/scripts/BuildNumber @@ -1 +1 @@ -69 \ No newline at end of file +70 \ No newline at end of file diff --git a/src/UniGetUI.Core.Data/CoreData.cs b/src/UniGetUI.Core.Data/CoreData.cs index de49906ff5..3eb033b815 100644 --- a/src/UniGetUI.Core.Data/CoreData.cs +++ b/src/UniGetUI.Core.Data/CoreData.cs @@ -47,7 +47,7 @@ private static int GetCodePage() } public const string VersionName = "3.1.4-beta1"; // Do not modify this line, use file scripts/apply_versions.py - public const int BuildNumber = 69; // Do not modify this line, use file scripts/apply_versions.py + public const int BuildNumber = 70; // Do not modify this line, use file scripts/apply_versions.py public const string UserAgentString = $"UniGetUI/{VersionName} (https://marticliment.com/unigetui/; contact@marticliment.com)";