Multi-Platform Package Manager for Stable Diffusion
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.

236 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 };
}