using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive; using System.Reactive.Disposables; using System.Threading; using System.Threading.Tasks; using Artemis.Core; using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.Plugins.Prerequisites; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using Avalonia.Threading; using FluentAvalonia.Core; using FluentAvalonia.UI.Controls; using ReactiveUI; using ContentDialogButton = Artemis.UI.Shared.Services.Builders.ContentDialogButton; namespace Artemis.UI.Screens.Plugins; public class PluginPrerequisitesInstallDialogViewModel : ContentDialogViewModelBase { private PluginPrerequisiteViewModel? _activePrerequisite; private bool _canInstall; private bool _showFailed; private bool _showInstall = true; private bool _showIntro = true; private bool _showProgress; private CancellationTokenSource? _tokenSource; public PluginPrerequisitesInstallDialogViewModel(List subjects, IPrerequisitesVmFactory prerequisitesVmFactory) { Prerequisites = new ObservableCollection(); foreach (PluginPrerequisite prerequisite in subjects.SelectMany(prerequisitesSubject => prerequisitesSubject.PlatformPrerequisites)) Prerequisites.Add(prerequisitesVmFactory.PluginPrerequisiteViewModel(prerequisite, false)); Install = ReactiveCommand.CreateFromTask(ExecuteInstall, this.WhenAnyValue(vm => vm.CanInstall)); Dispatcher.UIThread.Post(() => CanInstall = Prerequisites.Any(p => !p.PluginPrerequisite.IsMet()), DispatcherPriority.Background); this.WhenActivated(d => { Disposable.Create(() => { _tokenSource?.Cancel(); _tokenSource?.Dispose(); _tokenSource = null; }).DisposeWith(d); }); } public ReactiveCommand Install { get; } public ObservableCollection Prerequisites { get; } public PluginPrerequisiteViewModel? ActivePrerequisite { get => _activePrerequisite; set => RaiseAndSetIfChanged(ref _activePrerequisite, value); } public bool ShowProgress { get => _showProgress; set => RaiseAndSetIfChanged(ref _showProgress, value); } public bool ShowIntro { get => _showIntro; set => RaiseAndSetIfChanged(ref _showIntro, value); } public bool ShowFailed { get => _showFailed; set => RaiseAndSetIfChanged(ref _showFailed, value); } public bool ShowInstall { get => _showInstall; set => RaiseAndSetIfChanged(ref _showInstall, value); } public bool CanInstall { get => _canInstall; set => RaiseAndSetIfChanged(ref _canInstall, value); } public static async Task Show(IWindowService windowService, List subjects) { await windowService.CreateContentDialog() .WithTitle("Plugin prerequisites") .WithViewModel(out PluginPrerequisitesInstallDialogViewModel vm, subjects) .WithCloseButtonText("Cancel") .HavingPrimaryButton(b => b.WithText("Install").WithCommand(vm.Install)) .WithDefaultButton(ContentDialogButton.Primary) .ShowAsync(); } private async Task ExecuteInstall() { Deferral? deferral = null; if (ContentDialog != null) ContentDialog.Closing += (_, args) => deferral = args.GetDeferral(); CanInstall = false; ShowFailed = false; ShowIntro = false; ShowProgress = true; _tokenSource?.Dispose(); _tokenSource = new CancellationTokenSource(); try { foreach (PluginPrerequisiteViewModel pluginPrerequisiteViewModel in Prerequisites) { pluginPrerequisiteViewModel.IsMet = pluginPrerequisiteViewModel.PluginPrerequisite.IsMet(); if (pluginPrerequisiteViewModel.IsMet) continue; ActivePrerequisite = pluginPrerequisiteViewModel; await ActivePrerequisite.Install(_tokenSource.Token); if (!ActivePrerequisite.IsMet) { CanInstall = true; ShowFailed = true; ShowProgress = false; return; } // Wait after the task finished for the user to process what happened if (pluginPrerequisiteViewModel != Prerequisites.Last()) await Task.Delay(250); else await Task.Delay(1000); } if (deferral != null) deferral.Complete(); else ContentDialog?.Hide(ContentDialogResult.Primary); } catch (OperationCanceledException) { // ignored } } }