diff --git a/ZuneModdingHelper/Pages/AboutPage.xaml b/ZuneModdingHelper/Pages/AboutPage.xaml
index 14cfffb..f7e3468 100644
--- a/ZuneModdingHelper/Pages/AboutPage.xaml
+++ b/ZuneModdingHelper/Pages/AboutPage.xaml
@@ -44,9 +44,12 @@
-
+
-
+
+
diff --git a/ZuneModdingHelper/Pages/AboutPage.xaml.cs b/ZuneModdingHelper/Pages/AboutPage.xaml.cs
index 14408b1..a436e37 100644
--- a/ZuneModdingHelper/Pages/AboutPage.xaml.cs
+++ b/ZuneModdingHelper/Pages/AboutPage.xaml.cs
@@ -1,5 +1,15 @@
-using System.Windows.Controls;
+using CommunityToolkit.Mvvm.DependencyInjection;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using Octokit;
+using Syroot.Windows.IO;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Controls;
using System.Windows.Navigation;
+using ZuneModdingHelper.Messages;
namespace ZuneModdingHelper.Pages
{
@@ -8,6 +18,12 @@ namespace ZuneModdingHelper.Pages
///
public partial class AboutPage : UserControl
{
+ const string UPDATES_DIALOG_TITLE = "UPDATES";
+
+ private readonly IGitHubClient? _gitHub = Ioc.Default.GetService();
+ private ReleaseAsset _latestAsset;
+ private string _downloadedUpdatePath;
+
public AboutPage()
{
InitializeComponent();
@@ -18,5 +34,135 @@ namespace ZuneModdingHelper.Pages
App.OpenInBrowser(e.Uri.AbsoluteUri);
e.Handled = true;
}
+
+ private async void UpdateCheckButton_Click(object sender, System.Windows.RoutedEventArgs e)
+ {
+ if (_gitHub 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
+ {
+ // Get releases list from GitHub
+ // Why not use the `releases/latest` endpoint? Good question: https://github.com/octokit/octokit.net/issues/2916
+ var releases = await _gitHub.Repository.Release.GetAll("ZuneDev", "ZuneModdingHelper");
+ var latest = releases
+ .Select(r => new { Release = r, Version = ReleaseVersion.Parse(r.TagName) })
+ .OrderByDescending(t => t.Version)
+ .ThenBy(t => t.Release.Prerelease)
+ .First();
+
+ if (ReleaseVersion.TryParse(latest.Release.TagName, out var latestVer) || App.Version >= latestVer)
+ {
+ 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
+ _latestAsset = latest.Release.Assets[0];
+
+ WeakReferenceMessenger.Default.Send();
+ WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new DialogViewModel
+ {
+ Title = UPDATES_DIALOG_TITLE,
+ Description = $"Release {latest.Release.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 = 100,
+ };
+ WeakReferenceMessenger.Default.Send(new ShowDialogMessage(prog));
+
+ // Download new version to AppData
+ string downloadedFile = Path.Combine(Path.GetTempPath(), _latestAsset.Name);
+ if (File.Exists(downloadedFile)) File.Delete(downloadedFile);
+ using (var client = new System.Net.WebClient())
+ {
+ client.DownloadProgressChanged += (object sender, System.Net.DownloadProgressChangedEventArgs e) =>
+ {
+ // Update UI with download progress
+ prog.Progress = e.ProgressPercentage;
+ };
+
+ prog.Progress = 0;
+ prog.IsIndeterminate = false;
+ await client.DownloadFileTaskAsync(new Uri(_latestAsset.BrowserDownloadUrl), downloadedFile);
+ }
+
+ // Ask user to save file
+ Microsoft.Win32.SaveFileDialog saveFileDialog = new()
+ {
+ FileName = _latestAsset.Name,
+ InitialDirectory = new KnownFolder(KnownFolderType.Downloads).Path
+ };
+ bool dialogResult = saveFileDialog.ShowDialog() ?? false;
+ WeakReferenceMessenger.Default.Send();
+
+ if (dialogResult)
+ {
+ _downloadedUpdatePath = saveFileDialog.FileName;
+ File.Copy(downloadedFile, _downloadedUpdatePath, true);
+
+ WeakReferenceMessenger.Default.Send(new ShowDialogMessage(new DialogViewModel
+ {
+ Title = UPDATES_DIALOG_TITLE,
+ Description = "Update downloaded. Would you like to install the new version?",
+ AffirmativeText = "YES",
+ NegativeText = "NO",
+ ShowAffirmativeButton = true,
+ ShowNegativeButton = true,
+ OnAction = new AsyncRelayCommand(OnLaunchUpdateDialogResult)
+ }));
+ }
+
+ File.Delete(downloadedFile);
+ }
+
+ 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);
+ }
}
}