You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
7.4 KiB
235 lines
7.4 KiB
using System.Collections.Generic; |
|
using System.Linq; |
|
using System.Threading.Tasks; |
|
using AsyncAwaitBestPractices; |
|
using Avalonia.Controls; |
|
using Avalonia.Threading; |
|
using CommunityToolkit.Mvvm.ComponentModel; |
|
using CommunityToolkit.Mvvm.Input; |
|
using Exceptionless.DateTimeExtensions; |
|
using FluentAvalonia.UI.Controls; |
|
using FluentAvalonia.UI.Media.Animation; |
|
using Semver; |
|
using StabilityMatrix.Avalonia.Languages; |
|
using StabilityMatrix.Avalonia.Models; |
|
using StabilityMatrix.Avalonia.Services; |
|
using StabilityMatrix.Avalonia.ViewModels.Base; |
|
using StabilityMatrix.Avalonia.Views.Settings; |
|
using StabilityMatrix.Core.Attributes; |
|
using StabilityMatrix.Core.Models.Update; |
|
using StabilityMatrix.Core.Processes; |
|
using StabilityMatrix.Core.Services; |
|
using StabilityMatrix.Core.Updater; |
|
using Symbol = FluentIcons.Common.Symbol; |
|
using SymbolIconSource = FluentIcons.Avalonia.Fluent.SymbolIconSource; |
|
|
|
namespace StabilityMatrix.Avalonia.ViewModels.Settings; |
|
|
|
[View(typeof(UpdateSettingsPage))] |
|
[Singleton, ManagedService] |
|
public partial class UpdateSettingsViewModel : PageViewModelBase |
|
{ |
|
private readonly IUpdateHelper updateHelper; |
|
private readonly IAccountsService accountsService; |
|
private readonly INavigationService<SettingsViewModel> settingsNavService; |
|
|
|
[ObservableProperty] |
|
[NotifyPropertyChangedFor(nameof(IsUpdateAvailable))] |
|
[NotifyPropertyChangedFor(nameof(HeaderText))] |
|
[NotifyPropertyChangedFor(nameof(SubtitleText))] |
|
private UpdateStatusChangedEventArgs? updateStatus; |
|
|
|
public bool IsUpdateAvailable => UpdateStatus?.LatestUpdate != null; |
|
|
|
public string HeaderText => |
|
IsUpdateAvailable ? Resources.Label_UpdateAvailable : Resources.Label_YouAreUpToDate; |
|
|
|
public string? SubtitleText => |
|
UpdateStatus is null |
|
? null |
|
: string.Format( |
|
Resources.TextTemplate_LastChecked, |
|
UpdateStatus.CheckedAt.ToApproximateAgeString() |
|
); |
|
|
|
[ObservableProperty] |
|
private bool isAutoCheckUpdatesEnabled = true; |
|
|
|
[ObservableProperty] |
|
[NotifyPropertyChangedFor(nameof(SelectedUpdateChannelCard))] |
|
private UpdateChannel preferredUpdateChannel = UpdateChannel.Stable; |
|
|
|
public UpdateChannelCard? SelectedUpdateChannelCard |
|
{ |
|
get => AvailableUpdateChannelCards.First(c => c.UpdateChannel == PreferredUpdateChannel); |
|
set => PreferredUpdateChannel = value?.UpdateChannel ?? UpdateChannel.Stable; |
|
} |
|
|
|
public IReadOnlyList<UpdateChannelCard> AvailableUpdateChannelCards { get; } = |
|
new UpdateChannelCard[] |
|
{ |
|
new() |
|
{ |
|
UpdateChannel = UpdateChannel.Development, |
|
Description = Resources.Label_UpdatesDevChannelDescription |
|
}, |
|
new() |
|
{ |
|
UpdateChannel = UpdateChannel.Preview, |
|
Description = Resources.Label_UpdatesPreviewChannelDescription |
|
}, |
|
new() { UpdateChannel = UpdateChannel.Stable } |
|
}; |
|
|
|
public UpdateSettingsViewModel( |
|
ISettingsManager settingsManager, |
|
IUpdateHelper updateHelper, |
|
IAccountsService accountsService, |
|
INavigationService<SettingsViewModel> settingsNavService |
|
) |
|
{ |
|
this.updateHelper = updateHelper; |
|
this.accountsService = accountsService; |
|
this.settingsNavService = settingsNavService; |
|
|
|
settingsManager.RelayPropertyFor( |
|
this, |
|
vm => vm.PreferredUpdateChannel, |
|
settings => settings.PreferredUpdateChannel, |
|
true |
|
); |
|
|
|
settingsManager.RelayPropertyFor( |
|
this, |
|
vm => vm.IsAutoCheckUpdatesEnabled, |
|
settings => settings.CheckForUpdates, |
|
true |
|
); |
|
|
|
accountsService.LykosAccountStatusUpdate += (_, args) => |
|
{ |
|
var isBetaChannelsEnabled = args.User?.IsActiveSupporter == true; |
|
|
|
foreach ( |
|
var card in AvailableUpdateChannelCards.Where(c => c.UpdateChannel > UpdateChannel.Stable) |
|
) |
|
{ |
|
card.IsSelectable = isBetaChannelsEnabled; |
|
} |
|
}; |
|
|
|
// On update status changed |
|
updateHelper.UpdateStatusChanged += (_, args) => |
|
{ |
|
UpdateStatus = args; |
|
}; |
|
} |
|
|
|
/// <inheritdoc /> |
|
public override async Task OnLoadedAsync() |
|
{ |
|
if (UpdateStatus is null) |
|
{ |
|
await CheckForUpdates(); |
|
} |
|
OnPropertyChanged(nameof(SubtitleText)); |
|
} |
|
|
|
[RelayCommand] |
|
private async Task CheckForUpdates() |
|
{ |
|
if (Design.IsDesignMode) |
|
{ |
|
return; |
|
} |
|
await updateHelper.CheckForUpdate(); |
|
} |
|
|
|
/// <summary> |
|
/// Verify a new channel selection is valid, else returns false. |
|
/// </summary> |
|
/// <param name="card"></param> |
|
/// <returns></returns> |
|
public bool VerifyChannelSelection(UpdateChannelCard card) |
|
{ |
|
if (card.UpdateChannel == UpdateChannel.Stable) |
|
{ |
|
return true; |
|
} |
|
|
|
if (accountsService.LykosStatus?.User?.IsActiveSupporter == true) |
|
{ |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
public void ShowLoginRequiredDialog() |
|
{ |
|
Dispatcher |
|
.UIThread.InvokeAsync(async () => |
|
{ |
|
var dialog = DialogHelper.CreateTaskDialog( |
|
"Become a Supporter", |
|
"" |
|
+ "Support the Stability Matrix Team and get access to early development builds and be the first to test new features. " |
|
); |
|
|
|
dialog.Buttons = new[] |
|
{ |
|
new(Resources.Label_Accounts, TaskDialogStandardResult.OK), |
|
TaskDialogButton.CloseButton |
|
}; |
|
|
|
dialog.Commands = new[] |
|
{ |
|
new TaskDialogCommand |
|
{ |
|
Text = "Patreon", |
|
Description = "https://patreon.com/StabilityMatrix", |
|
Command = new RelayCommand(() => |
|
{ |
|
ProcessRunner.OpenUrl("https://patreon.com/StabilityMatrix"); |
|
}) |
|
} |
|
}; |
|
|
|
if (await dialog.ShowAsync(true) is TaskDialogStandardResult.OK) |
|
{ |
|
settingsNavService.NavigateTo<AccountSettingsViewModel>( |
|
new SuppressNavigationTransitionInfo() |
|
); |
|
} |
|
}) |
|
.SafeFireAndForget(); |
|
} |
|
|
|
partial void OnUpdateStatusChanged(UpdateStatusChangedEventArgs? value) |
|
{ |
|
// Update the update channel cards |
|
|
|
// Use maximum version from platforms equal or lower than current |
|
foreach (var card in AvailableUpdateChannelCards) |
|
{ |
|
card.LatestVersion = value |
|
?.UpdateChannels |
|
.Where(kv => kv.Key <= card.UpdateChannel) |
|
.Select(kv => kv.Value) |
|
.MaxBy(info => info.Version, SemVersion.PrecedenceComparer) |
|
?.Version; |
|
} |
|
} |
|
|
|
partial void OnPreferredUpdateChannelChanged(UpdateChannel value) |
|
{ |
|
CheckForUpdatesCommand.ExecuteAsync(null).SafeFireAndForget(); |
|
} |
|
|
|
/// <inheritdoc /> |
|
public override string Title => "Updates"; |
|
|
|
/// <inheritdoc /> |
|
public override IconSource IconSource => |
|
new SymbolIconSource { Symbol = Symbol.Settings, IsFilled = true }; |
|
}
|
|
|