From 86f78940b156a129114ab271a40fe8c4999b90d0 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 25 Jun 2024 21:29:52 +0200 Subject: [PATCH] Workshop - Manage entries after installing them Workshop - Auto-enable plugins after installing them Workshop - Show the latest release above the details page --- .../Routing/Router/IRouter.cs | 2 +- .../Routing/Router/NavigationArguments.cs | 8 +- .../Routing/Router/Router.cs | 6 +- .../Routing/Router/RouterNavigationOptions.cs | 5 + .../Screens/Plugins/PluginViewModel.cs | 19 +- .../EntryReleases/EntryReleaseInfoView.axaml | 111 +++++++++++ .../EntryReleaseInfoView.axaml.cs | 11 ++ .../EntryReleaseInfoViewModel.cs | 173 ++++++++++++++++++ .../EntryReleases/EntryReleaseView.axaml | 100 +--------- .../EntryReleases/EntryReleaseViewModel.cs | 83 +-------- .../Layout/LayoutDescriptionView.axaml | 4 + .../Layout/LayoutDescriptionViewModel.cs | 9 + .../Workshop/Layout/LayoutDetailsViewModel.cs | 5 +- .../Plugins/PluginDescriptionView.axaml | 4 + .../Plugins/PluginDescriptionViewModel.cs | 7 +- .../Plugins/PluginDetailsViewModel.cs | 1 + .../Workshop/Plugins/PluginManageViewModel.cs | 6 + .../Profile/ProfileDescriptionView.axaml | 4 + .../Profile/ProfileDescriptionViewModel.cs | 7 +- .../Profile/ProfileDetailsViewModel.cs | 1 + .../Queries/Fragments.graphql | 11 ++ .../Queries/GetEntryById.graphql | 8 +- .../Queries/GetReleaseById.graphql | 6 +- 23 files changed, 401 insertions(+), 190 deletions(-) create mode 100644 src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoView.axaml create mode 100644 src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoViewModel.cs diff --git a/src/Artemis.UI.Shared/Routing/Router/IRouter.cs b/src/Artemis.UI.Shared/Routing/Router/IRouter.cs index 2901fdbaf..58d915da4 100644 --- a/src/Artemis.UI.Shared/Routing/Router/IRouter.cs +++ b/src/Artemis.UI.Shared/Routing/Router/IRouter.cs @@ -50,7 +50,7 @@ public interface IRouter /// Asynchronously navigates upwards to the parent route. /// /// - Task GoUp(); + Task GoUp(RouterNavigationOptions? options = null); /// /// Clears the navigation history. diff --git a/src/Artemis.UI.Shared/Routing/Router/NavigationArguments.cs b/src/Artemis.UI.Shared/Routing/Router/NavigationArguments.cs index 5c26142e9..3b732d987 100644 --- a/src/Artemis.UI.Shared/Routing/Router/NavigationArguments.cs +++ b/src/Artemis.UI.Shared/Routing/Router/NavigationArguments.cs @@ -8,9 +8,10 @@ namespace Artemis.UI.Shared.Routing; /// public class NavigationArguments { - internal NavigationArguments(IRouter router, string path, object[] routeParameters) + internal NavigationArguments(IRouter router, RouterNavigationOptions options, string path, object[] routeParameters) { Router = router; + Options = options; Path = path; RouteParameters = routeParameters; SegmentParameters = Array.Empty(); @@ -21,6 +22,11 @@ public class NavigationArguments /// public IRouter Router { get; } + /// + /// Gets the options that are being used for this navigation. + /// + public RouterNavigationOptions Options { get; } + /// /// Gets the path of the route that is being navigated to. /// diff --git a/src/Artemis.UI.Shared/Routing/Router/Router.cs b/src/Artemis.UI.Shared/Routing/Router/Router.cs index 269d51fce..2850b88a3 100644 --- a/src/Artemis.UI.Shared/Routing/Router/Router.cs +++ b/src/Artemis.UI.Shared/Routing/Router/Router.cs @@ -114,7 +114,7 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable return; } - NavigationArguments args = new(this, resolution.Path, resolution.GetAllParameters()); + NavigationArguments args = new(this, options, resolution.Path, resolution.GetAllParameters()); if (!await RequestClose(_root, args)) return; @@ -169,7 +169,7 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable } /// - public async Task GoUp() + public async Task GoUp(RouterNavigationOptions? options = null) { string? currentPath = _currentRouteSubject.Value; @@ -180,7 +180,7 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable RouteResolution resolution = Resolve(parentPath); if (resolution.Success) { - await Navigate(parentPath, new RouterNavigationOptions {AddToHistory = false}); + await Navigate(parentPath, options); return true; } diff --git a/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs b/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs index 273f85c2c..e0a8bbd18 100644 --- a/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs +++ b/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs @@ -35,6 +35,11 @@ public class RouterNavigationOptions /// public bool EnableLogging { get; set; } = true; + /// + /// Gets or sets any additional arguments to pass to the screen. + /// + public object? AdditionalArguments { get; set; } + /// /// Determines whether the given two paths are considered equal using these navigation options. /// diff --git a/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs b/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs index 1a0333aca..4cecb945e 100644 --- a/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs +++ b/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs @@ -249,7 +249,7 @@ public partial class PluginViewModel : ActivatableViewModelBase return; // If the plugin or any of its features has uninstall actions, offer to run these - await ExecuteRemovePrerequisites(true); + await ExecuteRemovePrerequisites(true); try { @@ -264,7 +264,7 @@ public partial class PluginViewModel : ActivatableViewModelBase InstalledEntry? entry = _workshopService.GetInstalledEntries().FirstOrDefault(e => e.TryGetMetadata("PluginId", out Guid pluginId) && pluginId == Plugin.Guid); if (entry != null) _workshopService.RemoveInstalledEntry(entry); - + _notificationService.CreateNotification().WithTitle("Removed plugin.").Show(); } @@ -303,4 +303,19 @@ public partial class PluginViewModel : ActivatableViewModelBase _settingsWindow?.Close(); }); } + + public async Task AutoEnable() + { + if (IsEnabled) + return; + + await UpdateEnabled(true); + + // If enabling failed, don't offer to show the settings + if (!IsEnabled || Plugin.ConfigurationDialog == null) + return; + + if (await _windowService.ShowConfirmContentDialog("Open plugin settings", "This plugin has settings, would you like to view them?", "Yes", "No")) + ExecuteOpenSettings(); + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoView.axaml b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoView.axaml new file mode 100644 index 000000000..6487fc19c --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoView.axaml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + Release info + Latest release + + + + + + + + + + + + + + + + + + + + + + + Version + + + + + + Release date + + + + + + File size + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoView.axaml.cs b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoView.axaml.cs new file mode 100644 index 000000000..f216c9ea7 --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.EntryReleases; + +public partial class EntryReleaseInfoView : ReactiveUserControl +{ + public EntryReleaseInfoView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoViewModel.cs b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoViewModel.cs new file mode 100644 index 000000000..fa1968f6e --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseInfoViewModel.cs @@ -0,0 +1,173 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Reactive.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.Shared; +using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Services; +using Artemis.UI.Shared.Services.Builders; +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Handlers.InstallationHandlers; +using Artemis.WebClient.Workshop.Models; +using Artemis.WebClient.Workshop.Services; +using Humanizer; +using PropertyChanged.SourceGenerator; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.EntryReleases; + +public partial class EntryReleaseInfoViewModel : ActivatableViewModelBase +{ + private readonly IRouter _router; + private readonly INotificationService _notificationService; + private readonly IWindowService _windowService; + private readonly IWorkshopService _workshopService; + private readonly IPluginManagementService _pluginManagementService; + private readonly EntryInstallationHandlerFactory _factory; + private readonly ISettingsVmFactory _settingsVmFactory; + private readonly Progress _progress = new(); + private readonly ObservableAsPropertyHelper _isCurrentVersion; + + [Notify] private IReleaseDetails? _release; + [Notify] private float _installProgress; + [Notify] private bool _installationInProgress; + [Notify] private bool _inDetailsScreen; + + private CancellationTokenSource? _cts; + + public EntryReleaseInfoViewModel(IRouter router, + INotificationService notificationService, + IWindowService windowService, + IWorkshopService workshopService, + IPluginManagementService pluginManagementService, + EntryInstallationHandlerFactory factory, + ISettingsVmFactory settingsVmFactory) + { + _router = router; + _notificationService = notificationService; + _windowService = windowService; + _workshopService = workshopService; + _pluginManagementService = pluginManagementService; + _factory = factory; + _settingsVmFactory = settingsVmFactory; + _progress.ProgressChanged += (_, f) => InstallProgress = f.ProgressPercentage; + + _isCurrentVersion = this.WhenAnyValue(vm => vm.Release, vm => vm.InstallationInProgress, (release, _) => release) + .Select(r => r != null && _workshopService.GetInstalledEntry(r.Entry.Id)?.ReleaseId == r.Id) + .ToProperty(this, vm => vm.IsCurrentVersion); + + InDetailsScreen = true; + } + + public bool IsCurrentVersion => _isCurrentVersion.Value; + + public async Task Close() + { + await _router.GoUp(); + } + + public async Task Install() + { + if (Release == null) + return; + + // If the entry has missing dependencies, show a dialog + foreach (IGetEntryById_Entry_LatestRelease_Dependencies dependency in Release.Dependencies) + { + if (_workshopService.GetInstalledEntry(dependency.Id) == null) + { + if (await _windowService.ShowConfirmContentDialog("Missing dependencies", + $"One or more dependencies are missing, this {Release.Entry.EntryType.Humanize(LetterCasing.LowerCase)} won't work without them", "View dependencies")) + await _router.GoUp(); + return; + } + } + + _cts = new CancellationTokenSource(); + InstallProgress = 0; + InstallationInProgress = true; + try + { + IEntryInstallationHandler handler = _factory.CreateHandler(Release.Entry.EntryType); + EntryInstallResult result = await handler.InstallAsync(Release.Entry, Release, _progress, _cts.Token); + if (result.IsSuccess) + { + _notificationService.CreateNotification().WithTitle("Installation succeeded").WithSeverity(NotificationSeverity.Success).Show(); + InstallationInProgress = false; + await Manage(); + } + else if (!_cts.IsCancellationRequested) + _notificationService.CreateNotification().WithTitle("Installation failed").WithMessage(result.Message).WithSeverity(NotificationSeverity.Error).Show(); + } + catch (Exception e) + { + _windowService.ShowExceptionDialog("Failed to install workshop entry", e); + } + finally + { + InstallationInProgress = false; + } + } + + public async Task Manage() + { + if (Release?.Entry.EntryType != EntryType.Profile) + await _router.Navigate("../../manage", new RouterNavigationOptions {AdditionalArguments = true}); + } + + public async Task Reinstall() + { + if (await _windowService.ShowConfirmContentDialog("Reinstall entry", "Are you sure you want to reinstall this entry?")) + await Install(); + } + + public async Task Uninstall() + { + InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(Release!.Entry.Id); + if (installedEntry == null) + return; + + InstallationInProgress = true; + try + { + bool confirmed = await _windowService.ShowConfirmContentDialog("Do you want to uninstall this entry?", "Both the entry and its contents will be removed."); + if (!confirmed) + return; + + // Ideally the installation handler does this but it doesn't have access to the required view models + if (installedEntry.EntryType == EntryType.Plugin) + await UninstallPluginPrerequisites(installedEntry); + + IEntryInstallationHandler handler = _factory.CreateHandler(installedEntry.EntryType); + await handler.UninstallAsync(installedEntry, CancellationToken.None); + } + finally + { + InstallationInProgress = false; + } + } + + public void Cancel() + { + _cts?.Cancel(); + } + + private async Task UninstallPluginPrerequisites(InstalledEntry installedEntry) + { + if (!installedEntry.TryGetMetadata("PluginId", out Guid pluginId)) + return; + Plugin? plugin = _pluginManagementService.GetAllPlugins().FirstOrDefault(p => p.Guid == pluginId); + if (plugin == null) + return; + + PluginViewModel pluginViewModel = _settingsVmFactory.PluginViewModel(plugin, ReactiveCommand.Create(() => { })); + await pluginViewModel.ExecuteRemovePrerequisites(true); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseView.axaml b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseView.axaml index 62a991f55..ea659de07 100644 --- a/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseView.axaml +++ b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseView.axaml @@ -4,110 +4,12 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" xmlns:entryReleases="clr-namespace:Artemis.UI.Screens.Workshop.EntryReleases" - xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" - xmlns:converters="clr-namespace:Artemis.UI.Converters" - xmlns:sharedConverters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.Workshop.EntryReleases.EntryReleaseView" x:DataType="entryReleases:EntryReleaseViewModel"> - - - - - - - - - - - - - - - - - Release info - - - - - - - - - - - - - - - - - - - - Version - - - - - - Release date - - - - - - File size - - - - - + diff --git a/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseViewModel.cs b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseViewModel.cs index 32b1de42a..47083dffd 100644 --- a/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/EntryReleases/EntryReleaseViewModel.cs @@ -1,14 +1,9 @@ -using System; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Screens.Workshop.Parameters; using Artemis.UI.Shared.Routing; using Artemis.UI.Shared.Services; -using Artemis.UI.Shared.Services.Builders; -using Artemis.UI.Shared.Utilities; using Artemis.WebClient.Workshop; -using Artemis.WebClient.Workshop.Handlers.InstallationHandlers; -using Artemis.WebClient.Workshop.Services; using PropertyChanged.SourceGenerator; using StrawberryShake; @@ -17,89 +12,27 @@ namespace Artemis.UI.Screens.Workshop.EntryReleases; public partial class EntryReleaseViewModel : RoutableScreen { private readonly IWorkshopClient _client; - private readonly IRouter _router; private readonly INotificationService _notificationService; - private readonly IWindowService _windowService; - private readonly IWorkshopService _workshopService; - private readonly EntryInstallationHandlerFactory _factory; - private readonly Progress _progress = new(); [Notify] private IGetReleaseById_Release? _release; - [Notify] private float _installProgress; - [Notify] private bool _installationInProgress; - [Notify] private bool _isCurrentVersion; - private CancellationTokenSource? _cts; - - public EntryReleaseViewModel(IWorkshopClient client, IRouter router, INotificationService notificationService, IWindowService windowService, IWorkshopService workshopService, - EntryInstallationHandlerFactory factory) + public EntryReleaseViewModel(IWorkshopClient client, INotificationService notificationService, EntryReleaseInfoViewModel entryReleaseInfoViewModel) { + EntryReleaseInfoViewModel = entryReleaseInfoViewModel; + _client = client; - _router = router; _notificationService = notificationService; - _windowService = windowService; - _workshopService = workshopService; - _factory = factory; - _progress.ProgressChanged += (_, f) => InstallProgress = f.ProgressPercentage; - } - - public async Task Close() - { - await _router.GoUp(); - } - - public async Task Install() - { - if (Release == null) - return; - - _cts = new CancellationTokenSource(); - InstallProgress = 0; - InstallationInProgress = true; - try - { - IEntryInstallationHandler handler = _factory.CreateHandler(Release.Entry.EntryType); - EntryInstallResult result = await handler.InstallAsync(Release.Entry, Release, _progress, _cts.Token); - if (result.IsSuccess) - { - _notificationService.CreateNotification().WithTitle("Installation succeeded").WithSeverity(NotificationSeverity.Success).Show(); - IsCurrentVersion = true; - InstallationInProgress = false; - await Manage(); - } - else if (!_cts.IsCancellationRequested) - _notificationService.CreateNotification().WithTitle("Installation failed").WithMessage(result.Message).WithSeverity(NotificationSeverity.Error).Show(); - } - catch (Exception e) - { - InstallationInProgress = false; - _windowService.ShowExceptionDialog("Failed to install workshop entry", e); - } - } - - public async Task Manage() - { - if (Release?.Entry.EntryType != EntryType.Profile) - await _router.Navigate("../../manage"); - } - - public async Task Reinstall() - { - if (await _windowService.ShowConfirmContentDialog("Reinstall entry", "Are you sure you want to reinstall this entry?")) - await Install(); - } - - public void Cancel() - { - _cts?.Cancel(); } + + public EntryReleaseInfoViewModel EntryReleaseInfoViewModel { get; } /// public override async Task OnNavigating(ReleaseDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken) { IOperationResult result = await _client.GetReleaseById.ExecuteAsync(parameters.ReleaseId, cancellationToken); + Release = result.Data?.Release; - IsCurrentVersion = Release != null && _workshopService.GetInstalledEntry(Release.Entry.Id)?.ReleaseId == Release.Id; + EntryReleaseInfoViewModel.Release = Release; } #region Overrides of RoutableScreen @@ -107,7 +40,7 @@ public partial class EntryReleaseViewModel : RoutableScreen public override Task OnClosing(NavigationArguments args) { - if (!InstallationInProgress) + if (!EntryReleaseInfoViewModel.InstallationInProgress) return Task.CompletedTask; args.Cancel(); diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDescriptionView.axaml b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDescriptionView.axaml index e4cf60508..a38ea2771 100644 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDescriptionView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDescriptionView.axaml @@ -8,6 +8,10 @@ x:Class="Artemis.UI.Screens.Workshop.Layout.LayoutDescriptionView" x:DataType="layout:LayoutDescriptionViewModel"> + + + + diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDescriptionViewModel.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDescriptionViewModel.cs index 3fb8f678e..e5f00884b 100644 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDescriptionViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDescriptionViewModel.cs @@ -1,3 +1,4 @@ +using Artemis.UI.Screens.Workshop.EntryReleases; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; using PropertyChanged.SourceGenerator; @@ -7,4 +8,12 @@ namespace Artemis.UI.Screens.Workshop.Layout; public partial class LayoutDescriptionViewModel : RoutableScreen { [Notify] private IEntryDetails? _entry; + + public LayoutDescriptionViewModel(EntryReleaseInfoViewModel releaseInfoViewModel) + { + ReleaseInfoViewModel = releaseInfoViewModel; + ReleaseInfoViewModel.InDetailsScreen = false; + } + + public EntryReleaseInfoViewModel ReleaseInfoViewModel { get; } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs index 7379c1217..20f4cd286 100644 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Reactive.Linq; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Screens.Workshop.Entries.Details; @@ -7,6 +8,7 @@ using Artemis.UI.Screens.Workshop.Parameters; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; using PropertyChanged.SourceGenerator; +using ReactiveUI; using StrawberryShake; namespace Artemis.UI.Screens.Workshop.Layout; @@ -31,7 +33,7 @@ public partial class LayoutDetailsViewModel : RoutableHostScreen + + + + diff --git a/src/Artemis.UI/Screens/Workshop/Plugins/PluginDescriptionViewModel.cs b/src/Artemis.UI/Screens/Workshop/Plugins/PluginDescriptionViewModel.cs index 0cae2bbcd..99a474583 100644 --- a/src/Artemis.UI/Screens/Workshop/Plugins/PluginDescriptionViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Plugins/PluginDescriptionViewModel.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Screens.Workshop.Entries.List; +using Artemis.UI.Screens.Workshop.EntryReleases; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; using PropertyChanged.SourceGenerator; @@ -18,12 +19,16 @@ public partial class PluginDescriptionViewModel : RoutableScreen private readonly IWorkshopClient _client; private readonly Func _getEntryListViewModel; - public PluginDescriptionViewModel(IWorkshopClient client, Func getEntryListViewModel) + public PluginDescriptionViewModel(IWorkshopClient client, EntryReleaseInfoViewModel releaseInfoViewModel, Func getEntryListViewModel) { _client = client; _getEntryListViewModel = getEntryListViewModel; + ReleaseInfoViewModel = releaseInfoViewModel; + ReleaseInfoViewModel.InDetailsScreen = false; } + public EntryReleaseInfoViewModel ReleaseInfoViewModel { get; } + public async Task SetEntry(IEntryDetails? entry, CancellationToken cancellationToken) { Entry = entry; diff --git a/src/Artemis.UI/Screens/Workshop/Plugins/PluginDetailsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Plugins/PluginDetailsViewModel.cs index 802698aab..24d731110 100644 --- a/src/Artemis.UI/Screens/Workshop/Plugins/PluginDetailsViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Plugins/PluginDetailsViewModel.cs @@ -64,5 +64,6 @@ public partial class PluginDetailsViewModel : RoutableHostScreen { })); PluginFeatures = new ObservableCollection(plugin.Features.Select(f => _settingsVmFactory.PluginFeatureViewModel(f, false))); + + // If additional arguments were provided and it is a boolean, auto-enable the plugin + if (args.Options.AdditionalArguments is true) + { + await PluginViewModel.AutoEnable(); + } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDescriptionView.axaml b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDescriptionView.axaml index 5b29dc430..a82df57ec 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDescriptionView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDescriptionView.axaml @@ -8,6 +8,10 @@ x:Class="Artemis.UI.Screens.Workshop.Profile.ProfileDescriptionView" x:DataType="profile:ProfileDescriptionViewModel"> + + + + diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDescriptionViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDescriptionViewModel.cs index fd16c6cac..aec502c40 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDescriptionViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDescriptionViewModel.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Artemis.UI.Screens.Workshop.Entries.List; +using Artemis.UI.Screens.Workshop.EntryReleases; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop; using PropertyChanged.SourceGenerator; @@ -18,12 +19,16 @@ public partial class ProfileDescriptionViewModel : RoutableScreen [Notify] private IEntryDetails? _entry; [Notify] private List? _dependencies; - public ProfileDescriptionViewModel(IWorkshopClient client, Func getEntryListViewModel) + public ProfileDescriptionViewModel(IWorkshopClient client, EntryReleaseInfoViewModel releaseInfoViewModel, Func getEntryListViewModel) { _client = client; _getEntryListViewModel = getEntryListViewModel; + ReleaseInfoViewModel = releaseInfoViewModel; + ReleaseInfoViewModel.InDetailsScreen = false; } + public EntryReleaseInfoViewModel ReleaseInfoViewModel { get; } + public async Task SetEntry(IEntryDetails? entry, CancellationToken cancellationToken) { Entry = entry; diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs index e9b8480a2..1d4987fb7 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs @@ -65,5 +65,6 @@ public partial class ProfileDetailsViewModel : RoutableHostScreen