modified layout (#2)
Reviewed-on: #2 Co-authored-by: Aleksandr Neychev <alexnejchev73@gmail.com>
This commit was merged in pull request #2.
This commit is contained in:
@@ -15,17 +15,15 @@ namespace CursorLang.Settings.ViewModels;
|
||||
/// The updates section of the settings window.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A check made on opening the window passes its failures in silence: the machine does
|
||||
/// not always have a live network, and there is no point complaining about it to a user
|
||||
/// who came to change the popup colour. A check started by the button does report a
|
||||
/// failure — it is awaited and watched.
|
||||
/// The section always says where things stand: a check flies off the moment the window
|
||||
/// appears, and its outcome — including an unreachable network — stays written in the
|
||||
/// status line. Nothing here is silent, and nothing disappears: a user who opened the
|
||||
/// window is told about updates whether they came looking for them or not.
|
||||
/// </remarks>
|
||||
public sealed partial class UpdateViewModel : ObservableObject, IDisposable
|
||||
{
|
||||
private readonly IUpdateService _updates;
|
||||
private readonly ILocalizationService _localization;
|
||||
private readonly AppSettings _settings;
|
||||
private readonly UpdateOptions _options;
|
||||
|
||||
private CancellationTokenSource? _work;
|
||||
private ReleaseInfo? _release;
|
||||
@@ -35,7 +33,6 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
|
||||
[NotifyPropertyChangedFor(nameof(StatusText))]
|
||||
[NotifyPropertyChangedFor(nameof(IsBusy))]
|
||||
[NotifyPropertyChangedFor(nameof(CanCheck))]
|
||||
[NotifyPropertyChangedFor(nameof(HasStatus))]
|
||||
[NotifyPropertyChangedFor(nameof(IsProgressUnknown))]
|
||||
[NotifyPropertyChangedFor(nameof(IsDownloadOffered))]
|
||||
[NotifyPropertyChangedFor(nameof(IsInstallOffered))]
|
||||
@@ -48,16 +45,10 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
|
||||
[NotifyPropertyChangedFor(nameof(IsProgressUnknown))]
|
||||
private double _progress;
|
||||
|
||||
public UpdateViewModel(
|
||||
IUpdateService updates,
|
||||
ILocalizationService localization,
|
||||
AppSettings settings,
|
||||
UpdateOptions options)
|
||||
public UpdateViewModel(IUpdateService updates, ILocalizationService localization)
|
||||
{
|
||||
_updates = updates;
|
||||
_localization = localization;
|
||||
_settings = settings;
|
||||
_options = options;
|
||||
|
||||
_localization.PropertyChanged += OnLocalizationChanged;
|
||||
}
|
||||
@@ -67,29 +58,11 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
|
||||
|
||||
public string CurrentVersion => _updates.CurrentVersion.ToString();
|
||||
|
||||
/// <summary>Check for new versions at startup.</summary>
|
||||
public bool CheckAutomatically
|
||||
{
|
||||
get => _settings.CheckForUpdates;
|
||||
set
|
||||
{
|
||||
if (value == _settings.CheckForUpdates)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_settings.CheckForUpdates = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>A request or a download is in flight — the buttons freeze for that time.</summary>
|
||||
public bool IsBusy => Status is UpdateStatus.Checking or UpdateStatus.Downloading;
|
||||
|
||||
public bool CanCheck => !IsBusy;
|
||||
|
||||
public bool HasStatus => Status != UpdateStatus.Idle;
|
||||
|
||||
/// <summary>
|
||||
/// The package size is unknown, and the bar shows only the fact of the download.
|
||||
/// Its start looks the same until the first report arrives.
|
||||
@@ -107,6 +80,10 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
|
||||
/// <summary>The release page: the release notes live there too.</summary>
|
||||
public Uri? ReleaseUrl => _release?.PageUrl;
|
||||
|
||||
/// <summary>
|
||||
/// What the section says. There is a line for every state, the one before the
|
||||
/// first check included: the status is never an empty spot in the window.
|
||||
/// </summary>
|
||||
public string StatusText => Status switch
|
||||
{
|
||||
UpdateStatus.Checking => _localization["UpdateChecking"],
|
||||
@@ -115,33 +92,24 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
|
||||
UpdateStatus.Downloading => _localization["UpdateDownloading"],
|
||||
UpdateStatus.Ready => _localization["UpdateReady"],
|
||||
UpdateStatus.Failed => _localization["UpdateFailed"],
|
||||
_ => string.Empty,
|
||||
_ => _localization["UpdateNotChecked"],
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks for updates when the user has not forbidden it and enough time has
|
||||
/// passed since the previous check. Called once when the window opens.
|
||||
/// Asks about new versions. Called once, when the window has just appeared.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It used to be called when the application started, which back then meant when
|
||||
/// the machine was switched on. The background half is a separate process now and
|
||||
/// does not go to the network at all — nothing in it could show the answer — so the
|
||||
/// question is asked when there is a window to answer into.
|
||||
///
|
||||
/// And it is asked every time that window appears: opening it is a deliberate act
|
||||
/// of the user, rare enough that a request costs nothing, and the answer is what
|
||||
/// the section exists for. A remembered answer from yesterday is worth less than
|
||||
/// today's, so nothing is remembered.
|
||||
/// </remarks>
|
||||
public async Task StartAsync()
|
||||
{
|
||||
if (!IsSupported || !_settings.CheckForUpdates)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_settings.LastUpdateCheck is { } last && DateTimeOffset.UtcNow - last < _options.CheckInterval)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await RunCheckAsync(quiet: true);
|
||||
}
|
||||
public Task StartAsync() => CheckAsync();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -153,7 +121,36 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private Task CheckAsync() => RunCheckAsync(quiet: false);
|
||||
private async Task CheckAsync()
|
||||
{
|
||||
if (!IsSupported)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CancellationToken token = StartWork();
|
||||
Status = UpdateStatus.Checking;
|
||||
|
||||
try
|
||||
{
|
||||
_release = await _updates.CheckAsync(token);
|
||||
_packagePath = null;
|
||||
|
||||
Status = _release is null ? UpdateStatus.UpToDate : UpdateStatus.Available;
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
{
|
||||
// The check was cancelled by the next piece of work: it has already set its own state
|
||||
return;
|
||||
}
|
||||
catch (Exception e) when (IsExpected(e))
|
||||
{
|
||||
Status = UpdateStatus.Failed;
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(ReleaseUrl));
|
||||
OnPropertyChanged(nameof(IsReleaseLinkShown));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task DownloadAsync()
|
||||
@@ -216,38 +213,6 @@ public sealed partial class UpdateViewModel : ObservableObject, IDisposable
|
||||
or NotSupportedException or InvalidOperationException or Win32Exception
|
||||
or OperationCanceledException;
|
||||
|
||||
private async Task RunCheckAsync(bool quiet)
|
||||
{
|
||||
if (!IsSupported)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CancellationToken token = StartWork();
|
||||
Status = UpdateStatus.Checking;
|
||||
|
||||
try
|
||||
{
|
||||
_release = await _updates.CheckAsync(token);
|
||||
_packagePath = null;
|
||||
|
||||
_settings.LastUpdateCheck = DateTimeOffset.UtcNow;
|
||||
Status = _release is null ? UpdateStatus.UpToDate : UpdateStatus.Available;
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
{
|
||||
// The check was cancelled by the next piece of work: it has already set its own state
|
||||
return;
|
||||
}
|
||||
catch (Exception e) when (IsExpected(e))
|
||||
{
|
||||
Status = quiet ? UpdateStatus.Idle : UpdateStatus.Failed;
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(ReleaseUrl));
|
||||
OnPropertyChanged(nameof(IsReleaseLinkShown));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new piece of work, cancelling the previous one: the user may have
|
||||
/// pressed "Check" in the middle of a download.
|
||||
|
||||
Reference in New Issue
Block a user