feat(ui): wire update-check state and commands into shell VM

This commit is contained in:
mika kuns
2026-04-23 15:05:56 +02:00
parent 0934b294c2
commit bbe7d73de2

View File

@@ -1,3 +1,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using ClaudeDo.Ui.Services; using ClaudeDo.Ui.Services;
@@ -11,6 +14,7 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
public TasksIslandViewModel Tasks { get; } public TasksIslandViewModel Tasks { get; }
public DetailsIslandViewModel Details { get; } public DetailsIslandViewModel Details { get; }
public WorkerClient Worker { get; } public WorkerClient Worker { get; }
public UpdateCheckService UpdateCheck => _updateCheck;
public string ConnectionText => public string ConnectionText =>
Worker.IsConnected ? "Online" Worker.IsConnected ? "Online"
@@ -22,6 +26,11 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
private readonly UpdateCheckService _updateCheck; private readonly UpdateCheckService _updateCheck;
private readonly InstallerLocator _installerLocator; private readonly InstallerLocator _installerLocator;
[ObservableProperty] private bool _isUpdateBannerVisible;
[ObservableProperty] private string? _updateBannerLatestVersion;
[ObservableProperty] private string? _inlineUpdateStatus;
private bool _bannerDismissedThisSession;
[ObservableProperty] [ObservableProperty]
private double _windowWidth = 1280; private double _windowWidth = 1280;
@@ -76,5 +85,74 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
} }
}; };
_ = Lists.LoadAsync(); _ = Lists.LoadAsync();
_updateCheck.PropertyChanged += (_, e) =>
{
if (e.PropertyName == nameof(UpdateCheckService.LastCheckStatus))
{
RefreshBannerFromStatus();
}
};
// Fire-and-forget startup check — never block UI.
_ = Task.Run(async () =>
{
try { await _updateCheck.CheckNowAsync(CancellationToken.None); } catch { }
});
}
private void RefreshBannerFromStatus()
{
switch (_updateCheck.LastCheckStatus)
{
case UpdateCheckStatus.UpdateAvailable:
if (_bannerDismissedThisSession) { IsUpdateBannerVisible = false; break; }
UpdateBannerLatestVersion = _updateCheck.LatestVersion;
IsUpdateBannerVisible = true;
InlineUpdateStatus = null;
break;
case UpdateCheckStatus.UpToDate:
IsUpdateBannerVisible = false;
ShowInlineStatus($"You're up to date (v{_updateCheck.CurrentVersion})");
break;
case UpdateCheckStatus.CheckFailed:
ShowInlineStatus("Could not check for updates");
break;
}
}
private async void ShowInlineStatus(string text)
{
InlineUpdateStatus = text;
await Task.Delay(3000);
if (InlineUpdateStatus == text) InlineUpdateStatus = null;
}
[RelayCommand]
private async Task CheckForUpdatesAsync()
{
await _updateCheck.CheckNowAsync(CancellationToken.None);
}
[RelayCommand]
private void DismissBanner()
{
_bannerDismissedThisSession = true;
IsUpdateBannerVisible = false;
}
[RelayCommand]
private void UpdateNow()
{
var path = _installerLocator.Find();
if (path is null) return;
try
{
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(path) { UseShellExecute = true });
Environment.Exit(0);
}
catch
{
// Intentionally silent — if this fails there's nothing useful to show.
}
} }
} }