1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2026-03-25 02:38:48 +00:00
Artemis/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepViewModel.cs
Robert 565647f1ed Workshop - Improves default entry handling in workshop
Core - Modifies the Artemis data folder path based on the build configuration.
Plugins - Adds a confirmation dialog to prompt the user to restart if a plugin requires admin rights.
Startup wizard - Updates the installation progress bar in the startup wizard.
Workshop - Changes category retrieval to be based on EntryType.
Workshop - Adds the ability to include default entries when searching the workshop.
2025-12-08 22:27:18 +01:00

135 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Artemis.Core.Services;
using Artemis.UI.Extensions;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Utilities;
using Artemis.WebClient.Workshop;
using Artemis.WebClient.Workshop.Services;
using PropertyChanged.SourceGenerator;
using ReactiveUI;
using StrawberryShake;
namespace Artemis.UI.Screens.StartupWizard.Steps;
public partial class DefaultEntriesStepViewModel : WizardStepViewModel
{
[Notify] private bool _fetchingDefaultEntries = true;
[Notify] private int _installedEntries;
[Notify] private int _totalEntries = 1;
[Notify] private DefaultEntryItemViewModel? _currentEntry;
private readonly IDeviceService _deviceService;
private readonly IWorkshopClient _client;
private readonly Func<IEntrySummary, DefaultEntryItemViewModel> _getDefaultEntryItemViewModel;
private readonly ObservableAsPropertyHelper<int> _remainingEntries;
public ObservableCollection<DefaultEntryItemViewModel> DeviceProviderEntryViewModels { get; } = [];
public ObservableCollection<DefaultEntryItemViewModel> EssentialEntryViewModels { get; } = [];
public ObservableCollection<DefaultEntryItemViewModel> OtherEntryViewModels { get; } = [];
public int RemainingEntries => _remainingEntries.Value;
public DefaultEntriesStepViewModel(IWorkshopService workshopService, IDeviceService deviceService, IWorkshopClient client,
Func<IEntrySummary, DefaultEntryItemViewModel> getDefaultEntryItemViewModel)
{
_deviceService = deviceService;
_client = client;
_getDefaultEntryItemViewModel = getDefaultEntryItemViewModel;
_remainingEntries = this.WhenAnyValue(vm => vm.InstalledEntries, vm => vm.TotalEntries)
.Select(t => t.Item2 - t.Item1 + 1)
.ToProperty(this, vm => vm.RemainingEntries);
ContinueText = "Install selected entries";
Continue = ReactiveCommand.CreateFromTask(async ct =>
{
await Install(ct);
ExecuteContinue();
}, this.WhenAnyValue(vm => vm.FetchingDefaultEntries).Select(b => !b));
GoBack = ReactiveCommand.Create(() => Wizard.ChangeScreen<WelcomeStepViewModel>());
this.WhenActivatedAsync(async d =>
{
CancellationToken ct = d.AsCancellationToken();
if (await workshopService.ValidateWorkshopStatus(false, ct))
await GetDefaultEntries(d.AsCancellationToken());
else if (!ct.IsCancellationRequested)
Wizard.ChangeScreen<WorkshopUnreachableStepViewModel>();
});
}
private void ExecuteContinue()
{
// Without devices skip to the last step
if (_deviceService.EnabledDevices.Count == 0)
Wizard.ChangeScreen<SettingsStepViewModel>();
else
Wizard.ChangeScreen<LayoutsStepViewModel>();
}
private async Task Install(CancellationToken cancellationToken)
{
List<DefaultEntryItemViewModel> entries =
[
..DeviceProviderEntryViewModels.Where(e => e.ShouldInstall && !e.IsInstalled),
..EssentialEntryViewModels.Where(e => e.ShouldInstall && !e.IsInstalled),
..OtherEntryViewModels.Where(e => e.ShouldInstall && !e.IsInstalled)
];
InstalledEntries = 0;
TotalEntries = entries.Count;
// Continue to the next screen if there are no entries to install
if (TotalEntries == 0)
return;
foreach (DefaultEntryItemViewModel defaultEntryItemViewModel in entries)
{
cancellationToken.ThrowIfCancellationRequested();
CurrentEntry = defaultEntryItemViewModel;
await defaultEntryItemViewModel.InstallEntry(cancellationToken);
InstalledEntries++;
}
await Task.Delay(1000, cancellationToken);
CurrentEntry = null;
}
private async Task GetDefaultEntries(CancellationToken cancellationToken)
{
FetchingDefaultEntries = true;
IOperationResult<IGetDefaultEntriesResult> result = await _client.GetDefaultEntries.ExecuteAsync(100, null, cancellationToken);
List<IEntrySummary> entries = result.Data?.EntriesV2?.Edges?.Select(e => e.Node).Cast<IEntrySummary>().ToList() ?? [];
while (result.Data?.EntriesV2?.PageInfo is {HasNextPage: true})
{
result = await _client.GetDefaultEntries.ExecuteAsync(100, result.Data.EntriesV2.PageInfo.EndCursor, cancellationToken);
if (result.Data?.EntriesV2?.Edges != null)
entries.AddRange(result.Data.EntriesV2.Edges.Select(e => e.Node));
}
DeviceProviderEntryViewModels.Clear();
EssentialEntryViewModels.Clear();
OtherEntryViewModels.Clear();
foreach (IEntrySummary entry in entries)
{
if (entry.DefaultEntryInfo == null)
continue;
DefaultEntryItemViewModel viewModel = _getDefaultEntryItemViewModel(entry);
viewModel.ShouldInstall = entry.DefaultEntryInfo.IsEssential;
if (entry.DefaultEntryInfo.IsDeviceProvider)
DeviceProviderEntryViewModels.Add(viewModel);
else if (entry.DefaultEntryInfo.IsEssential)
EssentialEntryViewModels.Add(viewModel);
else
OtherEntryViewModels.Add(viewModel);
}
FetchingDefaultEntries = false;
}
}