From 5f0b00cfa8b21d2a5ef7cdfb23addc51db574cea Mon Sep 17 00:00:00 2001 From: Yoshi Askharoun Date: Tue, 2 Sep 2025 12:17:28 -0700 Subject: [PATCH] Check for updates on startup --- ZuneModdingHelper/AppWindow.xaml.cs | 3 + ZuneModdingHelper/Pages/AboutPage.xaml.cs | 122 +--------------- ZuneModdingHelper/Services/UpdateHelper.cs | 155 +++++++++++++++++++++ 3 files changed, 161 insertions(+), 119 deletions(-) create mode 100644 ZuneModdingHelper/Services/UpdateHelper.cs diff --git a/ZuneModdingHelper/AppWindow.xaml.cs b/ZuneModdingHelper/AppWindow.xaml.cs index 0329139..1280db5 100644 --- a/ZuneModdingHelper/AppWindow.xaml.cs +++ b/ZuneModdingHelper/AppWindow.xaml.cs @@ -45,6 +45,9 @@ namespace ZuneModdingHelper { await _settings.LoadAsync(); + // Check for updates in the background + UpdateHelper.Instance.CheckForUpdatesAsync(false); + // Show a warning if Zune isn't found. Usually happens if Zune isn't installed, // is installed in an unusual directory, or the user is running ZMH 32-bit // on a 64-bit system. diff --git a/ZuneModdingHelper/Pages/AboutPage.xaml.cs b/ZuneModdingHelper/Pages/AboutPage.xaml.cs index 9358af0..4d6ab29 100644 --- a/ZuneModdingHelper/Pages/AboutPage.xaml.cs +++ b/ZuneModdingHelper/Pages/AboutPage.xaml.cs @@ -1,12 +1,5 @@ -using CommunityToolkit.Mvvm.DependencyInjection; -using CommunityToolkit.Mvvm.Input; -using CommunityToolkit.Mvvm.Messaging; -using Syroot.Windows.IO; -using System; -using System.Threading.Tasks; -using System.Windows.Controls; +using System.Windows.Controls; using System.Windows.Navigation; -using ZuneModdingHelper.Messages; using ZuneModdingHelper.Services; namespace ZuneModdingHelper.Pages @@ -16,19 +9,13 @@ namespace ZuneModdingHelper.Pages /// public partial class AboutPage : UserControl { - const string UPDATES_DIALOG_TITLE = "UPDATES"; - - private readonly IUpdateService? _updateService = Ioc.Default.GetService(); - private UpdateAvailableInfo _updateInfo; - private string _downloadedUpdatePath; - public AboutPage() { DataContext = this; InitializeComponent(); } - public bool EnableCheckForUpdates => _updateService is not null; + public bool EnableCheckForUpdates => UpdateHelper.Instance.Enabled; private void Link_RequestNavigate(object sender, RequestNavigateEventArgs e) { @@ -38,110 +25,7 @@ namespace ZuneModdingHelper.Pages private async void UpdateCheckButton_Click(object sender, System.Windows.RoutedEventArgs e) { - if (_updateService is null) - return; - - WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new ProgressDialogViewModel - { - Title = UPDATES_DIALOG_TITLE, - Description = "Checking for updates, please wait...", - IsIndeterminate = true, - ShowAffirmativeButton = false, - })); - - try - { - _updateInfo = await _updateService.FetchAvailableUpdate(); - if (_updateInfo is null) - { - WeakReferenceMessenger.Default.Send(); - WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new DialogViewModel - { - Title = UPDATES_DIALOG_TITLE, - Description = "No updates available.\r\n\r\nYou're already using the latest version.", - ShowAffirmativeButton = true, - })); - return; - } - - // Newer version available, prompt user to download - - WeakReferenceMessenger.Default.Send(); - WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new DialogViewModel - { - Title = UPDATES_DIALOG_TITLE, - Description = $"Release {_updateInfo.Name} is available. Would you like to download it now?", - AffirmativeText = "YES", - NegativeText = "NO", - ShowAffirmativeButton = true, - ShowNegativeButton = true, - OnAction = new AsyncRelayCommand(OnUpdateDialogResult) - })); - } - catch - { - App.OpenInBrowser("https://github.com/ZuneDev/ZuneModdingHelper/releases"); - WeakReferenceMessenger.Default.Send(); - } - } - - private async Task OnUpdateDialogResult(bool accepted) - { - WeakReferenceMessenger.Default.Send(); - if (!accepted) - return; - - ProgressDialogViewModel prog = new() - { - Title = UPDATES_DIALOG_TITLE, - Description = "Downloading update...\r\nThis may take a few minutes.", - IsIndeterminate = true, - ShowAffirmativeButton = false, - ShowNegativeButton = false, - Maximum = 1.0, - }; - WeakReferenceMessenger.Default.Send(new ShowDialogMessage(prog)); - - // Ask user to save file - Microsoft.Win32.SaveFileDialog saveFileDialog = new() - { - FileName = _updateInfo.Name, - InitialDirectory = new KnownFolder(KnownFolderType.Downloads).Path - }; - bool dialogResult = saveFileDialog.ShowDialog() ?? false; - WeakReferenceMessenger.Default.Send(); - - if (dialogResult) - { - _downloadedUpdatePath = saveFileDialog.FileName; - - // Download new version to requested folder with progress updates - Progress progress = new(p => prog.Progress = p); - prog.Progress = 0; - prog.IsIndeterminate = false; - await _updateService.DownloadUpdate(_updateInfo, _downloadedUpdatePath, progress); - - WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new DialogViewModel - { - Title = UPDATES_DIALOG_TITLE, - Description = "Update downloaded. Would you like to launch the new version?", - AffirmativeText = "YES", - NegativeText = "NO", - ShowAffirmativeButton = true, - ShowNegativeButton = true, - OnAction = new AsyncRelayCommand(OnLaunchUpdateDialogResult) - })); - } - } - - private async Task OnLaunchUpdateDialogResult(bool accepted) - { - WeakReferenceMessenger.Default.Send(); - if (!accepted) - return; - - // In the future, this should launch an installer - System.Diagnostics.Process.Start("explorer", _downloadedUpdatePath); + await UpdateHelper.Instance.CheckForUpdatesAsync(true); } } } diff --git a/ZuneModdingHelper/Services/UpdateHelper.cs b/ZuneModdingHelper/Services/UpdateHelper.cs new file mode 100644 index 0000000..eed9a7b --- /dev/null +++ b/ZuneModdingHelper/Services/UpdateHelper.cs @@ -0,0 +1,155 @@ +using CommunityToolkit.Mvvm.DependencyInjection; +using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.Mvvm.Messaging; +using Syroot.Windows.IO; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using ZuneModdingHelper.Messages; + +namespace ZuneModdingHelper.Services; + +public class UpdateHelper +{ + public const string UPDATES_DIALOG_TITLE = "UPDATES"; + + private readonly IUpdateService? _updateService = Ioc.Default.GetService(); + private bool _isRunning = false; + private UpdateAvailableInfo _updateInfo; + private string _downloadedUpdatePath; + + public static UpdateHelper Instance { get; } = new(); + + public bool Enabled => _updateService is not null; + + public async Task CheckForUpdatesAsync(bool isUserTriggered) + { + if (_isRunning) + return; + + _isRunning = true; + + if (isUserTriggered) + { + WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new ProgressDialogViewModel + { + Title = UPDATES_DIALOG_TITLE, + Description = "Checking for updates, please wait...", + IsIndeterminate = true, + ShowAffirmativeButton = false, + })); + } + + try + { + await Task.Delay(5000); + _updateInfo = await _updateService.FetchAvailableUpdate(); + + if (isUserTriggered) + WeakReferenceMessenger.Default.Send(); + + if (_updateInfo is null) + { + if (isUserTriggered) + { + WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new DialogViewModel + { + Title = UPDATES_DIALOG_TITLE, + Description = "No updates available.\r\n\r\nYou're already using the latest version.", + ShowAffirmativeButton = true, + })); + } + + _isRunning = false; + return; + } + + // Newer version available, prompt user to download + + WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new DialogViewModel + { + Title = UPDATES_DIALOG_TITLE, + Description = $"Release {_updateInfo.Name} is available. Would you like to download it now?", + AffirmativeText = "YES", + NegativeText = "NO", + ShowAffirmativeButton = true, + ShowNegativeButton = true, + OnAction = new AsyncRelayCommand(OnUpdateDialogResult) + })); + } + catch + { + if (isUserTriggered) + { + App.OpenInBrowser($"{App.RepoUri}/releases"); + WeakReferenceMessenger.Default.Send(); + } + + _isRunning = false; + } + } + + private async Task OnUpdateDialogResult(bool accepted) + { + WeakReferenceMessenger.Default.Send(); + if (!accepted) + return; + + ProgressDialogViewModel prog = new() + { + Title = UPDATES_DIALOG_TITLE, + Description = "Downloading update...\r\nThis may take a few minutes.", + IsIndeterminate = true, + ShowAffirmativeButton = false, + ShowNegativeButton = false, + Maximum = 1.0, + }; + WeakReferenceMessenger.Default.Send(new ShowDialogMessage(prog)); + + // Ask user to save file + Microsoft.Win32.SaveFileDialog saveFileDialog = new() + { + FileName = _updateInfo.Name, + InitialDirectory = new KnownFolder(KnownFolderType.Downloads).Path + }; + bool dialogResult = saveFileDialog.ShowDialog() ?? false; + WeakReferenceMessenger.Default.Send(); + + if (dialogResult) + { + _downloadedUpdatePath = saveFileDialog.FileName; + + // Download new version to requested folder with progress updates + Progress progress = new(p => prog.Progress = p); + prog.Progress = 0; + prog.IsIndeterminate = false; + await _updateService.DownloadUpdate(_updateInfo, _downloadedUpdatePath, progress); + + WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new DialogViewModel + { + Title = UPDATES_DIALOG_TITLE, + Description = "Update downloaded. Would you like to launch the new version?", + AffirmativeText = "YES", + NegativeText = "NO", + ShowAffirmativeButton = true, + ShowNegativeButton = true, + OnAction = new AsyncRelayCommand(OnLaunchUpdateDialogResult) + })); + } + + _isRunning = false; + } + + private async Task OnLaunchUpdateDialogResult(bool accepted) + { + WeakReferenceMessenger.Default.Send(); + if (!accepted) + return; + + // In the future, this should launch an installer + System.Diagnostics.Process.Start("explorer", _downloadedUpdatePath); + } +}