From c1036c76b702937f61758241f168df1a9d1c624f Mon Sep 17 00:00:00 2001 From: Dirk <93130991+DirkDoes@users.noreply.github.com> Date: Mon, 5 Oct 2026 22:50:27 +0200 Subject: [PATCH 1/2] improve update visibility --- .../Features/AutoUpdating/AutoUpdaterTests.cs | 27 ++++++++ .../WiiManagement/RegionLicenseTests.cs | 19 ++++-- .../AutoUpdaterSingletonService.cs | 53 +++++++++++---- WheelWizard/Views/Layout.axaml | 64 +++++++++++++------ WheelWizard/Views/Layout.axaml.cs | 22 ++++++- .../Popups/Generic/MessageBoxWindow.axaml | 9 ++- .../Popups/Generic/MessageBoxWindow.axaml.cs | 16 +++++ .../Views/Updating/UpdatePresentation.cs | 7 +- 8 files changed, 175 insertions(+), 42 deletions(-) diff --git a/WheelWizard.Test/Features/AutoUpdating/AutoUpdaterTests.cs b/WheelWizard.Test/Features/AutoUpdating/AutoUpdaterTests.cs index b5f69d95f..e337f6f94 100644 --- a/WheelWizard.Test/Features/AutoUpdating/AutoUpdaterTests.cs +++ b/WheelWizard.Test/Features/AutoUpdating/AutoUpdaterTests.cs @@ -79,6 +79,33 @@ public async Task ReleaseLookupFailure_IsPresentedWithoutStartingAnUpdate() Assert.Empty(fixture.Platform.ReceivedCalls()); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task PostponedUpdate_CanBeReopenedWithoutAnotherLookup(bool automatic) + { + var fixture = new Fixture(); + fixture.Platform.SupportsAutomaticUpdate.Returns(automatic); + fixture.Releases([Release("v2.0.0")]); + var notifications = 0; + fixture.Service.UpdateAvailable += (_, _) => notifications++; + + Assert.False(fixture.Service.IsUpdateAvailable); + await fixture.Service.ShowAvailableUpdateAsync(); + Assert.Empty(fixture.Presentation.ReceivedCalls()); + + await fixture.Service.CheckForUpdatesAsync(); + Assert.True(fixture.Service.IsUpdateAvailable); + Assert.Equal(1, notifications); + await fixture.Service.ShowAvailableUpdateAsync(); + + await fixture.GitHub.Received(1).GetReleasesAsync(); + if (automatic) + await fixture.Presentation.Received(2).ConfirmUpdateAsync("2.0.0", "1.0.0"); + else + await fixture.Presentation.Received(2).ShowManualUpdateAsync("2.0.0", "1.0.0"); + } + private static GithubRelease Release(string version, bool prerelease = false, bool compatible = true) => new() { diff --git a/WheelWizard.Test/Features/WiiManagement/RegionLicenseTests.cs b/WheelWizard.Test/Features/WiiManagement/RegionLicenseTests.cs index 70710eea0..cf68d7da8 100644 --- a/WheelWizard.Test/Features/WiiManagement/RegionLicenseTests.cs +++ b/WheelWizard.Test/Features/WiiManagement/RegionLicenseTests.cs @@ -75,11 +75,20 @@ private static (GameLicenseSingletonService, MockFileSystem, ISettingsManager) C var settings = Substitute.For(); var miis = Substitute.For(); miis.GetByAvatarId(Arg.Any()).Returns(Fail("Missing Mii")); - var service = new GameLicenseSingletonService(miis, fs, - Substitute.For(), Substitute.For(), settings, - Substitute.For(), Substitute.For(), paths, - Substitute.For(), Substitute.For(), System.TimeProvider.System, - NullLogger.Instance); + var service = new GameLicenseSingletonService( + miis, + fs, + Substitute.For(), + Substitute.For(), + settings, + Substitute.For(), + Substitute.For(), + paths, + Substitute.For(), + Substitute.For(), + System.TimeProvider.System, + NullLogger.Instance + ); return (service, fs, settings); } } diff --git a/WheelWizard/Features/AutoUpdating/AutoUpdaterSingletonService.cs b/WheelWizard/Features/AutoUpdating/AutoUpdaterSingletonService.cs index e0d39432f..52a3ef6f0 100644 --- a/WheelWizard/Features/AutoUpdating/AutoUpdaterSingletonService.cs +++ b/WheelWizard/Features/AutoUpdating/AutoUpdaterSingletonService.cs @@ -8,7 +8,10 @@ namespace WheelWizard.AutoUpdating; public interface IAutoUpdaterSingletonService { - public Task CheckForUpdatesAsync(); + bool IsUpdateAvailable { get; } + event EventHandler? UpdateAvailable; + Task CheckForUpdatesAsync(); + Task ShowAvailableUpdateAsync(); } public class AutoUpdaterSingletonService( @@ -19,6 +22,10 @@ IUpdatePresentation presentation ) : IAutoUpdaterSingletonService { private bool _manualUpdateShown; + private bool _updatePromptOpen; + private GithubRelease? _availableRelease; + public bool IsUpdateAvailable => _availableRelease is not null; + public event EventHandler? UpdateAvailable; private string CurrentVersion => brandingService.Branding.Version; public async Task CheckForUpdatesAsync() @@ -27,26 +34,44 @@ public async Task CheckForUpdatesAsync() if (latestRelease?.TagName is null) return; - var latestVersion = latestRelease.TagName.TrimStart('v'); - if (!updatePlatform.SupportsAutomaticUpdate) + _availableRelease = latestRelease; + UpdateAvailable?.Invoke(this, EventArgs.Empty); + if (!updatePlatform.SupportsAutomaticUpdate && _manualUpdateShown) + return; + + await ShowAvailableUpdateAsync(); + } + + public async Task ShowAvailableUpdateAsync() + { + if (_availableRelease is not { TagName: not null } latestRelease || _updatePromptOpen) + return; + + _updatePromptOpen = true; + try { - if (!_manualUpdateShown) + var latestVersion = latestRelease.TagName.TrimStart('v'); + if (!updatePlatform.SupportsAutomaticUpdate) { _manualUpdateShown = true; await presentation.ShowManualUpdateAsync(latestVersion, CurrentVersion); + return; } - return; - } - var asset = updatePlatform.GetAssetForCurrentPlatform(latestRelease); - if (asset is null || !await presentation.ConfirmUpdateAsync(latestVersion, CurrentVersion)) - return; + var asset = updatePlatform.GetAssetForCurrentPlatform(latestRelease); + if (asset is null || !await presentation.ConfirmUpdateAsync(latestVersion, CurrentVersion)) + return; - var updateResult = await presentation.RunUpdateAsync( - (progress, cancellation) => updatePlatform.ExecuteUpdateAsync(asset.BrowserDownloadUrl, progress, cancellation) - ); - if (updateResult.IsFailure) - await presentation.ShowUpdateFailureAsync(updateResult.Error.Message); + var updateResult = await presentation.RunUpdateAsync( + (progress, cancellation) => updatePlatform.ExecuteUpdateAsync(asset.BrowserDownloadUrl, progress, cancellation) + ); + if (updateResult.IsFailure) + await presentation.ShowUpdateFailureAsync(updateResult.Error.Message); + } + finally + { + _updatePromptOpen = false; + } } private async Task GetLatestReleaseAsync() diff --git a/WheelWizard/Views/Layout.axaml b/WheelWizard/Views/Layout.axaml index 7774da99e..c1ee3a61a 100644 --- a/WheelWizard/Views/Layout.axaml +++ b/WheelWizard/Views/Layout.axaml @@ -290,24 +290,52 @@ VerticalAlignment="Center" /> - - - +