Workshop - Reworked installation management

This commit is contained in:
Robert committed 2024-03-30 17:55:51 +01:00
1 parent d6f1ba9aad
commit 6b4ed48d05
28 files changed
+514 -197

No files matched your search

@@ -1,19 +0,0 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dialogs="clr-namespace:Artemis.UI.Screens.Workshop.Plugins.Dialogs"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Plugins.Dialogs.PluginDialogView"
x:DataType="dialogs:PluginDialogViewModel">
<Grid ColumnDefinitions="4*,5*" Width="800" Height="160">
<ContentControl Grid.Column="0" Content="{CompiledBinding PluginViewModel}" />
<Border Grid.Column="1" BorderBrush="{DynamicResource ButtonBorderBrush}" BorderThickness="1 0 0 0" Margin="10 0 0 0" Padding="10 0 0 0">
<Grid RowDefinitions="Auto,*">
<TextBlock Classes="h5">Plugin features</TextBlock>
<ListBox Grid.Row="1" MaxHeight="135" ItemsSource="{CompiledBinding PluginFeatures}" />
</Grid>
</Border>
</Grid>
</UserControl>
@@ -1,11 +0,0 @@
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Workshop.Plugins.Dialogs;
public partial class PluginDialogView : ReactiveUserControl<PluginDialogViewModel>
{
public PluginDialogView()
{
InitializeComponent();
}
}
@@ -1,23 +0,0 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using Artemis.Core;
using Artemis.UI.DryIoc.Factories;
using Artemis.UI.Screens.Plugins;
using Artemis.UI.Screens.Plugins.Features;
using Artemis.UI.Shared;
using ReactiveUI;
namespace Artemis.UI.Screens.Workshop.Plugins.Dialogs;
public class PluginDialogViewModel : ContentDialogViewModelBase
{
public PluginDialogViewModel(Plugin plugin, ISettingsVmFactory settingsVmFactory)
{
PluginViewModel = settingsVmFactory.PluginViewModel(plugin, ReactiveCommand.Create(() => {}, Observable.Empty<bool>()));
PluginFeatures = new ObservableCollection<PluginFeatureViewModel>(plugin.Features.Select(f => settingsVmFactory.PluginFeatureViewModel(f, false)));
}
public PluginViewModel PluginViewModel { get; }
public ObservableCollection<PluginFeatureViewModel> PluginFeatures { get; }
}
@@ -1,20 +1,13 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Screens.Workshop.Entries.Details;
using Artemis.UI.Screens.Workshop.Entries.List;
using Artemis.UI.Screens.Workshop.EntryReleases;
using Artemis.UI.Screens.Workshop.Parameters;
using Artemis.UI.Screens.Workshop.Plugins.Dialogs;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
using Artemis.WebClient.Workshop;
using Artemis.WebClient.Workshop.Models;
using PropertyChanged.SourceGenerator;
using StrawberryShake;
@@ -23,8 +16,6 @@ namespace Artemis.UI.Screens.Workshop.Plugins;
public partial class PluginDetailsViewModel : RoutableHostScreen<RoutableScreen, WorkshopDetailParameters>
{
private readonly IWorkshopClient _client;
private readonly IWindowService _windowService;
private readonly IPluginManagementService _pluginManagementService;
private readonly Func<IEntryDetails, EntryInfoViewModel> _getEntryInfoViewModel;
private readonly Func<IEntryDetails, EntryReleasesViewModel> _getEntryReleasesViewModel;
private readonly Func<IEntryDetails, EntryImagesViewModel> _getEntryImagesViewModel;
@@ -35,16 +26,12 @@ public partial class PluginDetailsViewModel : RoutableHostScreen<RoutableScreen,
[Notify] private ReadOnlyObservableCollection<EntryListItemViewModel>? _dependants;
public PluginDetailsViewModel(IWorkshopClient client,
IWindowService windowService,
IPluginManagementService pluginManagementService,
PluginDescriptionViewModel pluginDescriptionViewModel,
Func<IEntryDetails, EntryInfoViewModel> getEntryInfoViewModel,
Func<IEntryDetails, EntryReleasesViewModel> getEntryReleasesViewModel,
Func<IEntryDetails, EntryImagesViewModel> getEntryImagesViewModel)
{
_client = client;
_windowService = windowService;
_pluginManagementService = pluginManagementService;
_getEntryInfoViewModel = getEntryInfoViewModel;
_getEntryReleasesViewModel = getEntryReleasesViewModel;
_getEntryImagesViewModel = getEntryImagesViewModel;
@@ -72,35 +59,6 @@ public partial class PluginDetailsViewModel : RoutableHostScreen<RoutableScreen,
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
if (EntryReleasesViewModel != null)
{
EntryReleasesViewModel.OnInstallationStarted = OnInstallationStarted;
EntryReleasesViewModel.OnInstallationFinished = OnInstallationFinished;
}
await PluginDescriptionViewModel.SetEntry(Entry, cancellationToken);
}
private async Task<bool> OnInstallationStarted(IEntryDetails entryDetails, IRelease release)
{
bool confirm = await _windowService.ShowConfirmContentDialog(
"Installing plugin",
$"You are about to install version {release.Version} of {entryDetails.Name}. \r\n\r\n" +
"Plugins are NOT verified by Artemis and could harm your PC, if you have doubts about a plugin please ask on Discord!",
"I trust this plugin, install it"
);
return !confirm;
}
private async Task OnInstallationFinished(InstalledEntry installedEntry)
{
if (!installedEntry.TryGetMetadata("PluginId", out Guid pluginId))
return;
Plugin? plugin = _pluginManagementService.GetAllPlugins().FirstOrDefault(p => p.Guid == pluginId);
if (plugin == null)
return;
await _windowService.CreateContentDialog().WithTitle("Manage plugin").WithViewModel(out PluginDialogViewModel _, plugin).WithFullScreen().ShowAsync();
}
}
@@ -0,0 +1,33 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:plugins="clr-namespace:Artemis.UI.Screens.Workshop.Plugins"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Plugins.PluginManageView"
x:DataType="plugins:PluginManageViewModel">
<Border Classes="card" VerticalAlignment="Top">
<StackPanel>
<Grid ColumnDefinitions="Auto,*,Auto">
<Button Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Classes="icon-button" Command="{CompiledBinding Close}">
<avalonia:MaterialIcon Kind="ArrowBack" />
</Button>
<TextBlock Grid.Row="0" Grid.Column="1" Classes="h4 no-margin">Manage plugin</TextBlock>
</Grid>
<Border Classes="card-separator" />
<Grid ColumnDefinitions="4*,5*" Height="160">
<ContentControl Grid.Column="0" Content="{CompiledBinding PluginViewModel}" />
<Border Grid.Column="1" BorderBrush="{DynamicResource ButtonBorderBrush}" BorderThickness="1 0 0 0" Margin="10 0 0 0" Padding="10 0 0 0">
<Grid RowDefinitions="Auto,*">
<TextBlock Classes="h5">Plugin features</TextBlock>
<ListBox Grid.Row="1" MaxHeight="135" ItemsSource="{CompiledBinding PluginFeatures}" />
</Grid>
</Border>
</Grid>
</StackPanel>
</Border>
</UserControl>
@@ -0,0 +1,14 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Workshop.Plugins;
public partial class PluginManageView : ReactiveUserControl<PluginManageViewModel>
{
public PluginManageView()
{
InitializeComponent();
}
}
@@ -0,0 +1,77 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories;
using Artemis.UI.Screens.Plugins;
using Artemis.UI.Screens.Plugins.Features;
using Artemis.UI.Screens.Workshop.Parameters;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
using Artemis.WebClient.Workshop.Models;
using Artemis.WebClient.Workshop.Services;
using Avalonia.Threading;
using PropertyChanged.SourceGenerator;
using ReactiveUI;
namespace Artemis.UI.Screens.Workshop.Plugins;
public partial class PluginManageViewModel : RoutableScreen<WorkshopDetailParameters>
{
private readonly ISettingsVmFactory _settingsVmFactory;
private readonly IRouter _router;
private readonly IWorkshopService _workshopService;
private readonly IPluginManagementService _pluginManagementService;
private readonly IWindowService _windowService;
[Notify] private PluginViewModel? _pluginViewModel;
[Notify] private ObservableCollection<PluginFeatureViewModel>? _pluginFeatures;
public PluginManageViewModel(ISettingsVmFactory settingsVmFactory, IRouter router, IWorkshopService workshopService, IPluginManagementService pluginManagementService, IWindowService windowService)
{
_settingsVmFactory = settingsVmFactory;
_router = router;
_workshopService = workshopService;
_pluginManagementService = pluginManagementService;
_windowService = windowService;
ParameterSource = ParameterSource.Route;
}
public async Task Close()
{
await _router.GoUp();
}
/// <inheritdoc />
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
{
InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(parameters.EntryId);
if (installedEntry == null || !installedEntry.TryGetMetadata("PluginId", out Guid pluginId))
{
// TODO: Fix cancelling without this workaround, currently navigation is stopped but the page still opens
Dispatcher.UIThread.InvokeAsync(async () =>
{
await _windowService.ShowConfirmContentDialog("Invalid plugin", "The plugin you're trying to manage is invalid or doesn't exist", "Go back", null);
await Close();
});
return;
}
Plugin? plugin = _pluginManagementService.GetAllPlugins().FirstOrDefault(p => p.Guid == pluginId);
if (plugin == null)
{
// TODO: Fix cancelling without this workaround, currently navigation is stopped but the page still opens
Dispatcher.UIThread.InvokeAsync(async () =>
{
await _windowService.ShowConfirmContentDialog("Invalid plugin", "The plugin you're trying to manage is invalid or doesn't exist", "Go back", null);
await Close();
});
return;
}
PluginViewModel = _settingsVmFactory.PluginViewModel(plugin, ReactiveCommand.Create(() => { }));
PluginFeatures = new ObservableCollection<PluginFeatureViewModel>(plugin.Features.Select(f => _settingsVmFactory.PluginFeatureViewModel(f, false)));
}
}