diff --git a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs index b3da24ce2..5184c3c94 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs @@ -160,10 +160,10 @@ public class ProfileEditorViewModel : RoutableScreen c.ProfileId == parameters.ProfileId); - // If the profile doesn't exist, navigate home for lack of some kind of 404 :p + // If the profile doesn't exist, cancel navigation if (profileConfiguration == null) { - await args.Router.Navigate("home"); + args.Cancel(); return; } diff --git a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs index e559e7e09..45de1c801 100644 --- a/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Layout/LayoutDetailsViewModel.cs @@ -10,7 +10,6 @@ using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Artemis.UI.Shared.Utilities; using Artemis.WebClient.Workshop; -using Artemis.WebClient.Workshop.DownloadHandlers; using ReactiveUI; using StrawberryShake; diff --git a/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs index 2b05edc76..61270df28 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs @@ -15,8 +15,8 @@ using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Utilities; using Artemis.WebClient.Workshop; using Artemis.WebClient.Workshop.Exceptions; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; using Artemis.WebClient.Workshop.Services; -using Artemis.WebClient.Workshop.UploadHandlers; using Avalonia.Media.Imaging; using ReactiveUI; using StrawberryShake; diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml index 4d01b32b0..3631f30ef 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemView.axaml @@ -5,6 +5,7 @@ xmlns:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Library.Tabs" xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia" xmlns:converters="clr-namespace:Artemis.UI.Converters" + 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.Library.Tabs.InstalledTabItemView" x:DataType="tabs:InstalledTabItemViewModel"> @@ -12,14 +13,14 @@ - - - + HorizontalAlignment="Stretch" + HorizontalContentAlignment="Stretch" + Command="{CompiledBinding ViewWorkshopPage}"> + - - - + - + Text="{CompiledBinding InstalledEntry.Author, FallbackValue=Summary}"> - - - - - + + + + + Installed + + + + + + - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemViewModel.cs index 54f171c52..1b22e37aa 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabItemViewModel.cs @@ -1,14 +1,70 @@ +using System; +using System.Reactive; +using System.Threading; +using System.Threading.Tasks; using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; +using Artemis.UI.Shared.Services; +using Artemis.WebClient.Workshop; +using Artemis.WebClient.Workshop.Handlers.InstallationHandlers; using Artemis.WebClient.Workshop.Services; +using ReactiveUI; namespace Artemis.UI.Screens.Workshop.Library.Tabs; public class InstalledTabItemViewModel : ViewModelBase { - public InstalledTabItemViewModel(InstalledEntry installedEntry) + private readonly IWorkshopService _workshopService; + private readonly IRouter _router; + private readonly EntryInstallationHandlerFactory _factory; + private readonly IWindowService _windowService; + private bool _isRemoved; + + public InstalledTabItemViewModel(InstalledEntry installedEntry, IWorkshopService workshopService, IRouter router, EntryInstallationHandlerFactory factory, IWindowService windowService) { + _workshopService = workshopService; + _router = router; + _factory = factory; + _windowService = windowService; InstalledEntry = installedEntry; + + ViewWorkshopPage = ReactiveCommand.CreateFromTask(ExecuteViewWorkshopPage); + ViewLocal = ReactiveCommand.CreateFromTask(ExecuteViewLocal); + Uninstall = ReactiveCommand.CreateFromTask(ExecuteUninstall); + } + + public bool IsRemoved + { + get => _isRemoved; + private set => RaiseAndSetIfChanged(ref _isRemoved, value); } public InstalledEntry InstalledEntry { get; } + public ReactiveCommand ViewWorkshopPage { get; } + public ReactiveCommand ViewLocal { get; } + public ReactiveCommand Uninstall { get; } + + private async Task ExecuteViewWorkshopPage() + { + await _workshopService.NavigateToEntry(InstalledEntry.EntryId, InstalledEntry.EntryType); + } + + private async Task ExecuteViewLocal(CancellationToken cancellationToken) + { + if (InstalledEntry.EntryType == EntryType.Profile && Guid.TryParse(InstalledEntry.LocalReference, out Guid profileId)) + { + await _router.Navigate($"profile-editor/{profileId}"); + } + } + + private async Task ExecuteUninstall(CancellationToken cancellationToken) + { + bool confirmed = await _windowService.ShowConfirmContentDialog("Do you want to uninstall this entry?", "Both the entry and its contents will be removed."); + if (!confirmed) + return; + + IEntryInstallationHandler handler = _factory.CreateHandler(InstalledEntry.EntryType); + await handler.UninstallAsync(InstalledEntry, cancellationToken); + IsRemoved = true; + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml index 9689f09bf..fe1fef9e2 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabView.axaml @@ -6,13 +6,34 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.InstalledTabView" x:DataType="tabs:InstalledTabViewModel"> - - - - - - - - - + + + + + + + + + Not much here yet, huh! + + Any entries you download from the workshop you can later manage here + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabViewModel.cs index 9e02249f7..7267c6e25 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/InstalledTabViewModel.cs @@ -1,10 +1,10 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Reactive.Disposables; +using System.Reactive; using System.Reactive.Linq; using Artemis.UI.Shared.Routing; using Artemis.WebClient.Workshop.Services; -using Avalonia.ReactiveUI; using DynamicData; using DynamicData.Binding; using ReactiveUI; @@ -15,27 +15,32 @@ public class InstalledTabViewModel : RoutableScreen { private string? _searchEntryInput; - public InstalledTabViewModel(IWorkshopService workshopService, Func getInstalledTabItemViewModel) + public InstalledTabViewModel(IWorkshopService workshopService, IRouter router, Func getInstalledTabItemViewModel) { SourceList installedEntries = new(); IObservable> pluginFilter = this.WhenAnyValue(vm => vm.SearchEntryInput).Throttle(TimeSpan.FromMilliseconds(100)).Select(CreatePredicate); installedEntries.Connect() .Filter(pluginFilter) - .Sort(SortExpressionComparer.Ascending(p => p.Name)) + .Sort(SortExpressionComparer.Descending(p => p.InstalledAt)) .Transform(getInstalledTabItemViewModel) - .ObserveOn(AvaloniaScheduler.Instance) + .AutoRefresh(vm => vm.IsRemoved) + .Filter(vm => !vm.IsRemoved) .Bind(out ReadOnlyObservableCollection installedEntryViewModels) .Subscribe(); + + List entries = workshopService.GetInstalledEntries(); + installedEntries.AddRange(entries); + + Empty = entries.Count == 0; InstalledEntries = installedEntryViewModels; - this.WhenActivated(d => - { - installedEntries.AddRange(workshopService.GetInstalledEntries()); - Disposable.Create(installedEntries, e => e.Clear()).DisposeWith(d); - }); + OpenWorkshop = ReactiveCommand.CreateFromTask(async () => await router.Navigate("workshop")); } + public bool Empty { get; } + public ReactiveCommand OpenWorkshop { get; } + public ReadOnlyObservableCollection InstalledEntries { get; } public string? SearchEntryInput @@ -49,7 +54,6 @@ public class InstalledTabViewModel : RoutableScreen if (string.IsNullOrWhiteSpace(text)) return _ => true; - return data => data.Name.Contains(text, StringComparison.InvariantCultureIgnoreCase) || - data.Summary.Contains(text, StringComparison.InvariantCultureIgnoreCase); + return data => data.Name.Contains(text, StringComparison.InvariantCultureIgnoreCase); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml new file mode 100644 index 000000000..583f14c4f --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml @@ -0,0 +1,76 @@ + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml.cs new file mode 100644 index 000000000..8bf14a3bf --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemView.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public partial class SubmissionsTabItemView : UserControl +{ + public SubmissionsTabItemView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemViewModel.cs new file mode 100644 index 000000000..21c8098ee --- /dev/null +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabItemViewModel.cs @@ -0,0 +1,30 @@ +using System.Reactive; +using System.Threading; +using System.Threading.Tasks; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Routing; +using Artemis.WebClient.Workshop; +using ReactiveUI; + +namespace Artemis.UI.Screens.Workshop.Library.Tabs; + +public class SubmissionsTabItemViewModel : ViewModelBase +{ + private readonly IRouter _router; + + public SubmissionsTabItemViewModel(IGetSubmittedEntries_SubmittedEntries entry, IRouter router) + { + _router = router; + Entry = entry; + + NavigateToEntry = ReactiveCommand.CreateFromTask(ExecuteNavigateToEntry); + } + + public IGetSubmittedEntries_SubmittedEntries Entry { get; } + public ReactiveCommand NavigateToEntry { get; } + + private async Task ExecuteNavigateToEntry(CancellationToken cancellationToken) + { + await _router.Navigate($"workshop/library/submissions/{Entry.Id}"); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml index 9fb0f3055..c52644447 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabView.axaml @@ -3,17 +3,9 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Library.Tabs" - xmlns:workshop="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop" - xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" - xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia" - xmlns:converters="clr-namespace:Artemis.UI.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="650" x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.SubmissionsTabView" x:DataType="tabs:SubmissionsTabViewModel"> - - - - @@ -44,71 +36,11 @@ - - + + - - + + diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabViewModel.cs index 0b4a906f6..14ae89b70 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/SubmissionsTabViewModel.cs @@ -21,21 +21,25 @@ public class SubmissionsTabViewModel : RoutableScreen private readonly IWorkshopClient _client; private readonly SourceCache _entries; private readonly IWindowService _windowService; - private readonly IRouter _router; private bool _isLoading = true; private bool _workshopReachable; - public SubmissionsTabViewModel(IWorkshopClient client, IAuthenticationService authenticationService, IWindowService windowService, IWorkshopService workshopService, IRouter router) + public SubmissionsTabViewModel(IWorkshopClient client, + IAuthenticationService authenticationService, + IWindowService windowService, + IWorkshopService workshopService, + Func getSubmissionsTabItemViewModel) { _client = client; _windowService = windowService; - _router = router; _entries = new SourceCache(e => e.Id); - _entries.Connect().Bind(out ReadOnlyObservableCollection entries).Subscribe(); + _entries.Connect() + .Transform(getSubmissionsTabItemViewModel) + .Bind(out ReadOnlyObservableCollection entries) + .Subscribe(); AddSubmission = ReactiveCommand.CreateFromTask(ExecuteAddSubmission, this.WhenAnyValue(vm => vm.WorkshopReachable)); Login = ReactiveCommand.CreateFromTask(ExecuteLogin, this.WhenAnyValue(vm => vm.WorkshopReachable)); - NavigateToEntry = ReactiveCommand.CreateFromTask(ExecuteNavigateToEntry); IsLoggedIn = authenticationService.IsLoggedIn; Entries = entries; @@ -53,7 +57,7 @@ public class SubmissionsTabViewModel : RoutableScreen public ReactiveCommand NavigateToEntry { get; } public IObservable IsLoggedIn { get; } - public ReadOnlyObservableCollection Entries { get; } + public ReadOnlyObservableCollection Entries { get; } public bool WorkshopReachable { @@ -77,12 +81,7 @@ public class SubmissionsTabViewModel : RoutableScreen { await _windowService.ShowDialogAsync(); } - - private async Task ExecuteNavigateToEntry(IGetSubmittedEntries_SubmittedEntries entry, CancellationToken cancellationToken) - { - await _router.Navigate($"workshop/library/submissions/{entry.Id}"); - } - + private async Task GetEntries(CancellationToken ct) { IsLoading = true; diff --git a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs index 2d026efec..80a09c02e 100644 --- a/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Profile/ProfileDetailsViewModel.cs @@ -10,8 +10,8 @@ using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Artemis.UI.Shared.Utilities; using Artemis.WebClient.Workshop; -using Artemis.WebClient.Workshop.DownloadHandlers; -using Artemis.WebClient.Workshop.DownloadHandlers.Implementations; +using Artemis.WebClient.Workshop.Handlers.InstallationHandlers; +using Artemis.WebClient.Workshop.Handlers.InstallationHandlers.Implementations; using ReactiveUI; using StrawberryShake; @@ -70,7 +70,7 @@ public class ProfileDetailsViewModel : RoutableScreen if (!confirm) return; - EntryInstallResult result = await _installationHandler.InstallProfileAsync(Entry, Entry.LatestRelease.Id, new Progress(), cancellationToken); + EntryInstallResult result = await _installationHandler.InstallAsync(Entry, Entry.LatestRelease.Id, new Progress(), cancellationToken); if (result.IsSuccess) _notificationService.CreateNotification().WithTitle("Profile installed").WithSeverity(NotificationSeverity.Success).Show(); else diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs index 7d0413714..689f80c4e 100644 --- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs @@ -8,8 +8,8 @@ using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Utilities; using Artemis.WebClient.Workshop; using Artemis.WebClient.Workshop.Exceptions; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; using Artemis.WebClient.Workshop.Services; -using Artemis.WebClient.Workshop.UploadHandlers; using ReactiveUI; using StrawberryShake; diff --git a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj index 389fa75e5..391d5c4b5 100644 --- a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj +++ b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj @@ -48,4 +48,8 @@ MSBuild:GenerateGraphQLCode + + + + diff --git a/src/Artemis.WebClient.Workshop/DownloadHandlers/EntryUploadResult.cs b/src/Artemis.WebClient.Workshop/DownloadHandlers/EntryUploadResult.cs deleted file mode 100644 index d1162bee8..000000000 --- a/src/Artemis.WebClient.Workshop/DownloadHandlers/EntryUploadResult.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Artemis.Web.Workshop.Entities; - -namespace Artemis.WebClient.Workshop.DownloadHandlers; - -public class EntryInstallResult -{ - public bool IsSuccess { get; set; } - public string? Message { get; set; } - public T? Result { get; set; } - - public static EntryInstallResult FromFailure(string? message) - { - return new EntryInstallResult - { - IsSuccess = false, - Message = message - }; - } - - public static EntryInstallResult FromSuccess(T installationResult) - { - return new EntryInstallResult - { - IsSuccess = true, - Result = installationResult - }; - } -} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/DownloadHandlers/IEntryInstallationHandler.cs b/src/Artemis.WebClient.Workshop/DownloadHandlers/IEntryInstallationHandler.cs deleted file mode 100644 index 435e17e82..000000000 --- a/src/Artemis.WebClient.Workshop/DownloadHandlers/IEntryInstallationHandler.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Artemis.UI.Shared.Utilities; - -namespace Artemis.WebClient.Workshop.DownloadHandlers; - -public interface IEntryInstallationHandler -{ -} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs index 5a4a29e6e..ddadc110e 100644 --- a/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.WebClient.Workshop/DryIoc/ContainerExtensions.cs @@ -1,10 +1,10 @@ using System.Reflection; -using Artemis.WebClient.Workshop.DownloadHandlers; using Artemis.WebClient.Workshop.Extensions; +using Artemis.WebClient.Workshop.Handlers.InstallationHandlers; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; using Artemis.WebClient.Workshop.Repositories; using Artemis.WebClient.Workshop.Services; using Artemis.WebClient.Workshop.State; -using Artemis.WebClient.Workshop.UploadHandlers; using DryIoc; using DryIoc.Microsoft.DependencyInjection; using IdentityModel.Client; diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallResult.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallResult.cs new file mode 100644 index 000000000..aaf56859e --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallResult.cs @@ -0,0 +1,26 @@ +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers; + +public class EntryInstallResult +{ + public bool IsSuccess { get; set; } + public string? Message { get; set; } + public object? Result { get; set; } + + public static EntryInstallResult FromFailure(string? message) + { + return new EntryInstallResult + { + IsSuccess = false, + Message = message + }; + } + + public static EntryInstallResult FromSuccess(object installationResult) + { + return new EntryInstallResult + { + IsSuccess = true, + Result = installationResult + }; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallationHandlerFactory.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallationHandlerFactory.cs new file mode 100644 index 000000000..ec9c63566 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryInstallationHandlerFactory.cs @@ -0,0 +1,23 @@ +using Artemis.WebClient.Workshop.Handlers.InstallationHandlers.Implementations; +using DryIoc; + +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers; + +public class EntryInstallationHandlerFactory +{ + private readonly IContainer _container; + + public EntryInstallationHandlerFactory(IContainer container) + { + _container = container; + } + + public IEntryInstallationHandler CreateHandler(EntryType entryType) + { + return entryType switch + { + EntryType.Profile => _container.Resolve(), + _ => throw new NotSupportedException($"EntryType '{entryType}' is not supported.") + }; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryUninstallResult.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryUninstallResult.cs new file mode 100644 index 000000000..6d28edf9a --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/EntryUninstallResult.cs @@ -0,0 +1,24 @@ +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers; + +public class EntryUninstallResult +{ + public bool IsSuccess { get; set; } + public string? Message { get; set; } + + public static EntryUninstallResult FromFailure(string? message) + { + return new EntryUninstallResult + { + IsSuccess = false, + Message = message + }; + } + + public static EntryUninstallResult FromSuccess() + { + return new EntryUninstallResult + { + IsSuccess = true + }; + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/IEntryInstallationHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/IEntryInstallationHandler.cs new file mode 100644 index 000000000..91b3fb7f8 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/IEntryInstallationHandler.cs @@ -0,0 +1,10 @@ +using Artemis.UI.Shared.Utilities; +using Artemis.WebClient.Workshop.Services; + +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers; + +public interface IEntryInstallationHandler +{ + Task InstallAsync(IGetEntryById_Entry entry, Guid releaseId, Progress progress, CancellationToken cancellationToken); + Task UninstallAsync(InstalledEntry installedEntry, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryInstallationHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs similarity index 66% rename from src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryInstallationHandler.cs rename to src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs index 83d057e61..c61921b06 100644 --- a/src/Artemis.WebClient.Workshop/DownloadHandlers/Implementations/ProfileEntryInstallationHandler.cs +++ b/src/Artemis.WebClient.Workshop/Handlers/InstallationHandlers/Implementations/ProfileEntryInstallationHandler.cs @@ -4,7 +4,7 @@ using Artemis.UI.Shared.Extensions; using Artemis.UI.Shared.Utilities; using Artemis.WebClient.Workshop.Services; -namespace Artemis.WebClient.Workshop.DownloadHandlers.Implementations; +namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers.Implementations; public class ProfileEntryInstallationHandler : IEntryInstallationHandler { @@ -19,7 +19,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler _workshopService = workshopService; } - public async Task> InstallProfileAsync(IGetEntryById_Entry entry, Guid releaseId, Progress progress, CancellationToken cancellationToken) + public async Task InstallAsync(IGetEntryById_Entry entry, Guid releaseId, Progress progress, CancellationToken cancellationToken) { using MemoryStream stream = new(); @@ -31,7 +31,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler } catch (Exception e) { - return EntryInstallResult.FromFailure(e.Message); + return EntryInstallResult.FromFailure(e.Message); } // Find existing installation to potentially replace the profile @@ -43,10 +43,10 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler { ProfileConfiguration overwritten = await _profileService.OverwriteProfile(stream, existing); installedEntry.LocalReference = overwritten.ProfileId.ToString(); - + // Update the release and return the profile configuration UpdateRelease(releaseId, installedEntry); - return EntryInstallResult.FromSuccess(overwritten); + return EntryInstallResult.FromSuccess(overwritten); } } @@ -60,7 +60,33 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler // Update the release and return the profile configuration UpdateRelease(releaseId, installedEntry); - return EntryInstallResult.FromSuccess(imported); + return EntryInstallResult.FromSuccess(imported); + } + + public async Task UninstallAsync(InstalledEntry installedEntry, CancellationToken cancellationToken) + { + if (!Guid.TryParse(installedEntry.LocalReference, out Guid profileId)) + return EntryUninstallResult.FromFailure("Local reference does not contain a GUID"); + + return await Task.Run(() => + { + try + { + // Find the profile if still there + ProfileConfiguration? profile = _profileService.ProfileConfigurations.FirstOrDefault(c => c.ProfileId == profileId); + if (profile != null) + _profileService.DeleteProfile(profile); + + // Remove the release + _workshopService.RemoveInstalledEntry(installedEntry); + } + catch (Exception e) + { + return EntryUninstallResult.FromFailure(e.Message); + } + + return EntryUninstallResult.FromSuccess(); + }, cancellationToken); } private void UpdateRelease(Guid releaseId, InstalledEntry installedEntry) diff --git a/src/Artemis.WebClient.Workshop/UploadHandlers/EntryUploadHandlerFactory.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadHandlerFactory.cs similarity index 81% rename from src/Artemis.WebClient.Workshop/UploadHandlers/EntryUploadHandlerFactory.cs rename to src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadHandlerFactory.cs index ea0155e4f..17dc5245c 100644 --- a/src/Artemis.WebClient.Workshop/UploadHandlers/EntryUploadHandlerFactory.cs +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadHandlerFactory.cs @@ -1,7 +1,7 @@ -using Artemis.WebClient.Workshop.UploadHandlers.Implementations; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers.Implementations; using DryIoc; -namespace Artemis.WebClient.Workshop.UploadHandlers; +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers; public class EntryUploadHandlerFactory { diff --git a/src/Artemis.WebClient.Workshop/UploadHandlers/EntryUploadResult.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadResult.cs similarity index 90% rename from src/Artemis.WebClient.Workshop/UploadHandlers/EntryUploadResult.cs rename to src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadResult.cs index 040b99413..477201b24 100644 --- a/src/Artemis.WebClient.Workshop/UploadHandlers/EntryUploadResult.cs +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/EntryUploadResult.cs @@ -1,6 +1,6 @@ using Artemis.Web.Workshop.Entities; -namespace Artemis.WebClient.Workshop.UploadHandlers; +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers; public class EntryUploadResult { diff --git a/src/Artemis.WebClient.Workshop/UploadHandlers/IEntryUploadHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/IEntryUploadHandler.cs similarity index 78% rename from src/Artemis.WebClient.Workshop/UploadHandlers/IEntryUploadHandler.cs rename to src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/IEntryUploadHandler.cs index 21cdc2d5a..85a316600 100644 --- a/src/Artemis.WebClient.Workshop/UploadHandlers/IEntryUploadHandler.cs +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/IEntryUploadHandler.cs @@ -1,6 +1,6 @@ using Artemis.UI.Shared.Utilities; -namespace Artemis.WebClient.Workshop.UploadHandlers; +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers; public interface IEntryUploadHandler { diff --git a/src/Artemis.WebClient.Workshop/UploadHandlers/ImageUploadResult.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/ImageUploadResult.cs similarity index 86% rename from src/Artemis.WebClient.Workshop/UploadHandlers/ImageUploadResult.cs rename to src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/ImageUploadResult.cs index 97f8e861c..7ebc08d2f 100644 --- a/src/Artemis.WebClient.Workshop/UploadHandlers/ImageUploadResult.cs +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/ImageUploadResult.cs @@ -1,4 +1,4 @@ -namespace Artemis.WebClient.Workshop.UploadHandlers; +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers; public class ImageUploadResult { diff --git a/src/Artemis.WebClient.Workshop/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs similarity index 81% rename from src/Artemis.WebClient.Workshop/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs rename to src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs index 57f2f664c..ac3d0e739 100644 --- a/src/Artemis.WebClient.Workshop/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/LayoutEntryUploadHandler.cs @@ -1,6 +1,6 @@ using Artemis.UI.Shared.Utilities; -namespace Artemis.WebClient.Workshop.UploadHandlers.Implementations; +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers.Implementations; public class LayoutEntryUploadHandler : IEntryUploadHandler { diff --git a/src/Artemis.WebClient.Workshop/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs similarity index 94% rename from src/Artemis.WebClient.Workshop/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs rename to src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs index 9b4287625..b5ecc03c2 100644 --- a/src/Artemis.WebClient.Workshop/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs +++ b/src/Artemis.WebClient.Workshop/Handlers/UploadHandlers/Implementations/ProfileEntryUploadHandler.cs @@ -1,12 +1,11 @@ using System.Net.Http.Headers; using Artemis.Core; using Artemis.Core.Services; -using Artemis.Storage.Repositories.Interfaces; using Artemis.UI.Shared.Utilities; using Artemis.Web.Workshop.Entities; using Newtonsoft.Json; -namespace Artemis.WebClient.Workshop.UploadHandlers.Implementations; +namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers.Implementations; public class ProfileEntryUploadHandler : IEntryUploadHandler { diff --git a/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs b/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs index 8ad0b50ab..073c74584 100644 --- a/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs +++ b/src/Artemis.WebClient.Workshop/Services/InstalledEntry.cs @@ -20,7 +20,6 @@ public class InstalledEntry Author = entry.Author; Name = entry.Name; - Summary = entry.Summary; } public Guid EntryId { get; set; } @@ -28,7 +27,6 @@ public class InstalledEntry public string Author { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; - public string Summary { get; set; } = string.Empty; public Guid ReleaseId { get; set; } public string ReleaseVersion { get; set; } = string.Empty; @@ -45,7 +43,6 @@ public class InstalledEntry Author = Entity.Author; Name = Entity.Name; - Summary = Entity.Summary; ReleaseId = Entity.ReleaseId; ReleaseVersion = Entity.ReleaseVersion; @@ -61,7 +58,6 @@ public class InstalledEntry Entity.Author = Author; Entity.Name = Name; - Entity.Summary = Summary; Entity.ReleaseId = ReleaseId; Entity.ReleaseVersion = ReleaseVersion; diff --git a/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs b/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs index bda524109..576b72b37 100644 --- a/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs +++ b/src/Artemis.WebClient.Workshop/Services/Interfaces/IWorkshopService.cs @@ -1,5 +1,5 @@ using Artemis.UI.Shared.Utilities; -using Artemis.WebClient.Workshop.UploadHandlers; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; namespace Artemis.WebClient.Workshop.Services; @@ -14,7 +14,9 @@ public interface IWorkshopService List GetInstalledEntries(); InstalledEntry? GetInstalledEntry(IGetEntryById_Entry entry); InstalledEntry CreateInstalledEntry(IGetEntryById_Entry entry); + void RemoveInstalledEntry(InstalledEntry installedEntry); void SaveInstalledEntry(InstalledEntry entry); + public record WorkshopStatus(bool IsReachable, string Message); } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs index 41924b8e1..db3a15ae7 100644 --- a/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs +++ b/src/Artemis.WebClient.Workshop/Services/WorkshopService.cs @@ -3,7 +3,7 @@ using Artemis.Storage.Entities.Workshop; using Artemis.Storage.Repositories.Interfaces; using Artemis.UI.Shared.Routing; using Artemis.UI.Shared.Utilities; -using Artemis.WebClient.Workshop.UploadHandlers; +using Artemis.WebClient.Workshop.Handlers.UploadHandlers; namespace Artemis.WebClient.Workshop.Services; @@ -124,6 +124,12 @@ public class WorkshopService : IWorkshopService return new InstalledEntry(entry); } + /// + public void RemoveInstalledEntry(InstalledEntry installedEntry) + { + _entryRepository.Remove(installedEntry.Entity); + } + /// public void SaveInstalledEntry(InstalledEntry entry) {