mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Workshop Library - Finished basic implementation of installed tab
This commit is contained in:
parent
876465cfdb
commit
3d1e53e395
@ -160,10 +160,10 @@ public class ProfileEditorViewModel : RoutableScreen<ProfileEditorViewModelParam
|
|||||||
{
|
{
|
||||||
ProfileConfiguration? profileConfiguration = _profileService.ProfileConfigurations.FirstOrDefault(c => c.ProfileId == parameters.ProfileId);
|
ProfileConfiguration? profileConfiguration = _profileService.ProfileConfigurations.FirstOrDefault(c => 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)
|
if (profileConfiguration == null)
|
||||||
{
|
{
|
||||||
await args.Router.Navigate("home");
|
args.Cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ using Artemis.UI.Shared.Services;
|
|||||||
using Artemis.UI.Shared.Services.Builders;
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
using Artemis.WebClient.Workshop.DownloadHandlers;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using StrawberryShake;
|
using StrawberryShake;
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,8 @@ using Artemis.UI.Shared.Services;
|
|||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
using Artemis.WebClient.Workshop.Exceptions;
|
using Artemis.WebClient.Workshop.Exceptions;
|
||||||
|
using Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||||
using Artemis.WebClient.Workshop.Services;
|
using Artemis.WebClient.Workshop.Services;
|
||||||
using Artemis.WebClient.Workshop.UploadHandlers;
|
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using StrawberryShake;
|
using StrawberryShake;
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
xmlns:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Library.Tabs"
|
xmlns:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Library.Tabs"
|
||||||
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
|
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
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"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.InstalledTabItemView"
|
x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.InstalledTabItemView"
|
||||||
x:DataType="tabs:InstalledTabItemViewModel">
|
x:DataType="tabs:InstalledTabItemViewModel">
|
||||||
@ -12,14 +13,14 @@
|
|||||||
<converters:EntryIconUriConverter x:Key="EntryIconUriConverter" />
|
<converters:EntryIconUriConverter x:Key="EntryIconUriConverter" />
|
||||||
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Border Classes="card-condensed"
|
<Button MinHeight="65"
|
||||||
MinHeight="80"
|
|
||||||
MaxHeight="110"
|
MaxHeight="110"
|
||||||
Padding="12 6"
|
Padding="6"
|
||||||
Margin="0 0 0 5"
|
Margin="0 0 0 5"
|
||||||
HorizontalAlignment="Stretch">
|
HorizontalAlignment="Stretch"
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
HorizontalContentAlignment="Stretch"
|
||||||
<!-- Icon -->
|
Command="{CompiledBinding ViewWorkshopPage}">
|
||||||
|
<Grid ColumnDefinitions="Auto,*,*,*,Auto">
|
||||||
<Border Grid.Column="0"
|
<Border Grid.Column="0"
|
||||||
CornerRadius="6"
|
CornerRadius="6"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
@ -30,24 +31,28 @@
|
|||||||
<Image Stretch="UniformToFill" asyncImageLoader:ImageLoader.Source="{CompiledBinding InstalledEntry.EntryId, Converter={StaticResource EntryIconUriConverter}, Mode=OneWay}" />
|
<Image Stretch="UniformToFill" asyncImageLoader:ImageLoader.Source="{CompiledBinding InstalledEntry.EntryId, Converter={StaticResource EntryIconUriConverter}, Mode=OneWay}" />
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- Body -->
|
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||||
<Grid Grid.Column="1" VerticalAlignment="Stretch" RowDefinitions="Auto,*,Auto">
|
<TextBlock TextTrimming="CharacterEllipsis"
|
||||||
<TextBlock Grid.Row="0"
|
|
||||||
Classes="h5 no-margin"
|
|
||||||
TextTrimming="CharacterEllipsis"
|
|
||||||
Text="{CompiledBinding InstalledEntry.Name, FallbackValue=Title}" />
|
Text="{CompiledBinding InstalledEntry.Name, FallbackValue=Title}" />
|
||||||
<TextBlock Grid.Row="1"
|
<TextBlock Classes="subtitle"
|
||||||
Classes="subtitle"
|
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
TextTrimming="CharacterEllipsis"
|
TextTrimming="CharacterEllipsis"
|
||||||
Text="{CompiledBinding InstalledEntry.Summary, FallbackValue=Summary}">
|
Text="{CompiledBinding InstalledEntry.Author, FallbackValue=Summary}">
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</Grid>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Info -->
|
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{CompiledBinding InstalledEntry.EntryType}"></TextBlock>
|
||||||
<StackPanel Grid.Column="2" Margin="0 0 4 0">
|
<TextBlock Grid.Column="3" VerticalAlignment="Center">
|
||||||
<TextBlock TextAlignment="Right" Text="{CompiledBinding InstalledEntry.InstalledAt, FallbackValue=01-01-1337, Converter={StaticResource DateTimeConverter}}" />
|
<Run>Installed</Run>
|
||||||
|
<Run Text="{CompiledBinding InstalledEntry.InstalledAt, FallbackValue=01-01-1337, Converter={StaticResource DateTimeConverter}}" />
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="4" VerticalAlignment="Center" Orientation="Horizontal" Spacing="6">
|
||||||
|
<Button Command="{CompiledBinding ViewLocal}">Open</Button>
|
||||||
|
<Button Command="{CompiledBinding Uninstall}" Theme="{StaticResource TransparentButton}" Height="32">
|
||||||
|
<avalonia:MaterialIcon Kind="Trash"/>
|
||||||
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Button>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,14 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Shared;
|
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 Artemis.WebClient.Workshop.Services;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.Library.Tabs;
|
namespace Artemis.UI.Screens.Workshop.Library.Tabs;
|
||||||
|
|
||||||
public class InstalledTabItemViewModel : ViewModelBase
|
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;
|
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 InstalledEntry InstalledEntry { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> ViewWorkshopPage { get; }
|
||||||
|
public ReactiveCommand<Unit,Unit> ViewLocal { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -6,13 +6,34 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.InstalledTabView"
|
x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.InstalledTabView"
|
||||||
x:DataType="tabs:InstalledTabViewModel">
|
x:DataType="tabs:InstalledTabViewModel">
|
||||||
<ScrollViewer>
|
<UserControl.Styles>
|
||||||
<ItemsRepeater ItemsSource="{CompiledBinding InstalledEntries}">
|
<Styles>
|
||||||
<ItemsRepeater.ItemTemplate>
|
<Style Selector="StackPanel.empty-state > TextBlock">
|
||||||
<DataTemplate>
|
<Setter Property="TextAlignment" Value="Center"></Setter>
|
||||||
<ContentControl Content="{CompiledBinding}"></ContentControl>
|
<Setter Property="TextWrapping" Value="Wrap"></Setter>
|
||||||
</DataTemplate>
|
</Style>
|
||||||
</ItemsRepeater.ItemTemplate>
|
</Styles>
|
||||||
</ItemsRepeater>
|
</UserControl.Styles>
|
||||||
</ScrollViewer>
|
|
||||||
|
<Panel>
|
||||||
|
<StackPanel IsVisible="{CompiledBinding Empty}" Margin="0 50 0 0" Classes="empty-state">
|
||||||
|
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">Not much here yet, huh!</TextBlock>
|
||||||
|
<TextBlock>
|
||||||
|
<Run>Any entries you download from the workshop you can later manage here</Run>
|
||||||
|
</TextBlock>
|
||||||
|
<Lottie Path="/Assets/Animations/empty.json" RepeatCount="1" Width="350" Height="350"></Lottie>
|
||||||
|
<Button HorizontalAlignment="Center" Command="{CompiledBinding OpenWorkshop}">Browse the Workshop</Button>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<ScrollViewer IsVisible="{CompiledBinding !Empty}">
|
||||||
|
<ItemsRepeater ItemsSource="{CompiledBinding InstalledEntries}">
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ContentControl Content="{CompiledBinding}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.WebClient.Workshop.Services;
|
using Artemis.WebClient.Workshop.Services;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
@ -15,27 +15,32 @@ public class InstalledTabViewModel : RoutableScreen
|
|||||||
{
|
{
|
||||||
private string? _searchEntryInput;
|
private string? _searchEntryInput;
|
||||||
|
|
||||||
public InstalledTabViewModel(IWorkshopService workshopService, Func<InstalledEntry, InstalledTabItemViewModel> getInstalledTabItemViewModel)
|
public InstalledTabViewModel(IWorkshopService workshopService, IRouter router, Func<InstalledEntry, InstalledTabItemViewModel> getInstalledTabItemViewModel)
|
||||||
{
|
{
|
||||||
SourceList<InstalledEntry> installedEntries = new();
|
SourceList<InstalledEntry> installedEntries = new();
|
||||||
IObservable<Func<InstalledEntry, bool>> pluginFilter = this.WhenAnyValue(vm => vm.SearchEntryInput).Throttle(TimeSpan.FromMilliseconds(100)).Select(CreatePredicate);
|
IObservable<Func<InstalledEntry, bool>> pluginFilter = this.WhenAnyValue(vm => vm.SearchEntryInput).Throttle(TimeSpan.FromMilliseconds(100)).Select(CreatePredicate);
|
||||||
|
|
||||||
installedEntries.Connect()
|
installedEntries.Connect()
|
||||||
.Filter(pluginFilter)
|
.Filter(pluginFilter)
|
||||||
.Sort(SortExpressionComparer<InstalledEntry>.Ascending(p => p.Name))
|
.Sort(SortExpressionComparer<InstalledEntry>.Descending(p => p.InstalledAt))
|
||||||
.Transform(getInstalledTabItemViewModel)
|
.Transform(getInstalledTabItemViewModel)
|
||||||
.ObserveOn(AvaloniaScheduler.Instance)
|
.AutoRefresh(vm => vm.IsRemoved)
|
||||||
|
.Filter(vm => !vm.IsRemoved)
|
||||||
.Bind(out ReadOnlyObservableCollection<InstalledTabItemViewModel> installedEntryViewModels)
|
.Bind(out ReadOnlyObservableCollection<InstalledTabItemViewModel> installedEntryViewModels)
|
||||||
.Subscribe();
|
.Subscribe();
|
||||||
|
|
||||||
|
List<InstalledEntry> entries = workshopService.GetInstalledEntries();
|
||||||
|
installedEntries.AddRange(entries);
|
||||||
|
|
||||||
|
Empty = entries.Count == 0;
|
||||||
InstalledEntries = installedEntryViewModels;
|
InstalledEntries = installedEntryViewModels;
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
OpenWorkshop = ReactiveCommand.CreateFromTask(async () => await router.Navigate("workshop"));
|
||||||
{
|
|
||||||
installedEntries.AddRange(workshopService.GetInstalledEntries());
|
|
||||||
Disposable.Create(installedEntries, e => e.Clear()).DisposeWith(d);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Empty { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> OpenWorkshop { get; }
|
||||||
|
|
||||||
public ReadOnlyObservableCollection<InstalledTabItemViewModel> InstalledEntries { get; }
|
public ReadOnlyObservableCollection<InstalledTabItemViewModel> InstalledEntries { get; }
|
||||||
|
|
||||||
public string? SearchEntryInput
|
public string? SearchEntryInput
|
||||||
@ -49,7 +54,6 @@ public class InstalledTabViewModel : RoutableScreen
|
|||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
return _ => true;
|
return _ => true;
|
||||||
|
|
||||||
return data => data.Name.Contains(text, StringComparison.InvariantCultureIgnoreCase) ||
|
return data => data.Name.Contains(text, StringComparison.InvariantCultureIgnoreCase);
|
||||||
data.Summary.Contains(text, StringComparison.InvariantCultureIgnoreCase);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
<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:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Library.Tabs"
|
||||||
|
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
|
||||||
|
xmlns:avalonia1="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.SubmissionsTabItemView"
|
||||||
|
x:DataType="tabs:SubmissionsTabItemViewModel">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<converters:EntryIconUriConverter x:Key="EntryIconUriConverter" />
|
||||||
|
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Button MinHeight="80"
|
||||||
|
MaxHeight="110"
|
||||||
|
Padding="12 6"
|
||||||
|
Margin="0 0 0 5"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
Command="{CompiledBinding NavigateToEntry}">
|
||||||
|
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||||
|
<!-- Icon -->
|
||||||
|
<Border Grid.Column="0"
|
||||||
|
CornerRadius="6"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0 0 10 0"
|
||||||
|
Width="50"
|
||||||
|
Height="50"
|
||||||
|
ClipToBounds="True">
|
||||||
|
<Image Stretch="UniformToFill" asyncImageLoader:ImageLoader.Source="{CompiledBinding Entry.Id, Converter={StaticResource EntryIconUriConverter}, Mode=OneWay}" />
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Body -->
|
||||||
|
<Grid Grid.Column="1" VerticalAlignment="Stretch" RowDefinitions="Auto,*,Auto">
|
||||||
|
<TextBlock Grid.Row="0"
|
||||||
|
Classes="h5 no-margin"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
Text="{CompiledBinding Entry.Name, FallbackValue=Title}" />
|
||||||
|
<TextBlock Grid.Row="1"
|
||||||
|
Classes="subtitle"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
Text="{CompiledBinding Entry.Summary, FallbackValue=Summary}">
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<ItemsControl Grid.Row="2" ItemsSource="{CompiledBinding Entry.Categories}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="8"></StackPanel>
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<avalonia1:MaterialIcon Kind="{CompiledBinding Icon}" Margin="0 0 3 0"></avalonia1:MaterialIcon>
|
||||||
|
<TextBlock Text="{CompiledBinding Name}" TextTrimming="CharacterEllipsis" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Info -->
|
||||||
|
<StackPanel Grid.Column="2" Margin="0 0 4 0">
|
||||||
|
<TextBlock TextAlignment="Right" Text="{CompiledBinding Entry.CreatedAt, FallbackValue=01-01-1337, Converter={StaticResource DateTimeConverter}}" />
|
||||||
|
<TextBlock TextAlignment="Right">
|
||||||
|
<avalonia1:MaterialIcon Kind="Downloads" />
|
||||||
|
<Run Classes="h5" Text="{CompiledBinding Entry.Downloads, FallbackValue=0}" />
|
||||||
|
<Run>downloads</Run>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
|
</UserControl>
|
||||||
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<Unit, Unit> NavigateToEntry { get; }
|
||||||
|
|
||||||
|
private async Task ExecuteNavigateToEntry(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await _router.Navigate($"workshop/library/submissions/{Entry.Id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,17 +3,9 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Library.Tabs"
|
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"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="650"
|
||||||
x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.SubmissionsTabView"
|
x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.SubmissionsTabView"
|
||||||
x:DataType="tabs:SubmissionsTabViewModel">
|
x:DataType="tabs:SubmissionsTabViewModel">
|
||||||
<UserControl.Resources>
|
|
||||||
<converters:EntryIconUriConverter x:Key="EntryIconUriConverter" />
|
|
||||||
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.Styles>
|
<UserControl.Styles>
|
||||||
<Styles>
|
<Styles>
|
||||||
@ -44,71 +36,11 @@
|
|||||||
<Button HorizontalAlignment="Center" Command="{CompiledBinding AddSubmission}">Submit new entry</Button>
|
<Button HorizontalAlignment="Center" Command="{CompiledBinding AddSubmission}">Submit new entry</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<ScrollViewer>
|
<ScrollViewer IsVisible="{CompiledBinding Entries.Count}">
|
||||||
<ItemsRepeater IsVisible="{CompiledBinding Entries.Count}" ItemsSource="{CompiledBinding Entries}">
|
<ItemsRepeater ItemsSource="{CompiledBinding Entries}">
|
||||||
<ItemsRepeater.ItemTemplate>
|
<ItemsRepeater.ItemTemplate>
|
||||||
<DataTemplate DataType="workshop:IGetSubmittedEntries_SubmittedEntries">
|
<DataTemplate>
|
||||||
<Button MinHeight="80"
|
<ContentControl Content="{CompiledBinding}"/>
|
||||||
MaxHeight="110"
|
|
||||||
Padding="12 6"
|
|
||||||
Margin="0 0 0 5"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Stretch"
|
|
||||||
Command="{Binding $parent[tabs:SubmissionsTabView].DataContext.NavigateToEntry}"
|
|
||||||
CommandParameter="{CompiledBinding}">
|
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
|
||||||
<!-- Icon -->
|
|
||||||
<Border Grid.Column="0"
|
|
||||||
CornerRadius="6"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="0 0 10 0"
|
|
||||||
Width="50"
|
|
||||||
Height="50"
|
|
||||||
ClipToBounds="True">
|
|
||||||
<Image Stretch="UniformToFill" asyncImageLoader:ImageLoader.Source="{CompiledBinding Id, Converter={StaticResource EntryIconUriConverter}, Mode=OneWay}" />
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- Body -->
|
|
||||||
<Grid Grid.Column="1" VerticalAlignment="Stretch" RowDefinitions="Auto,*,Auto">
|
|
||||||
<TextBlock Grid.Row="0"
|
|
||||||
Classes="h5 no-margin"
|
|
||||||
TextTrimming="CharacterEllipsis"
|
|
||||||
Text="{CompiledBinding Name, FallbackValue=Title}"/>
|
|
||||||
<TextBlock Grid.Row="1"
|
|
||||||
Classes="subtitle"
|
|
||||||
TextWrapping="Wrap"
|
|
||||||
TextTrimming="CharacterEllipsis"
|
|
||||||
Text="{CompiledBinding Summary, FallbackValue=Summary}">
|
|
||||||
</TextBlock>
|
|
||||||
|
|
||||||
<ItemsControl Grid.Row="2" ItemsSource="{CompiledBinding Categories}">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8"></StackPanel>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Margin="0 0 3 0"></avalonia:MaterialIcon>
|
|
||||||
<TextBlock Text="{CompiledBinding Name}" TextTrimming="CharacterEllipsis" />
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- Info -->
|
|
||||||
<StackPanel Grid.Column="2" Margin="0 0 4 0">
|
|
||||||
<TextBlock TextAlignment="Right" Text="{CompiledBinding CreatedAt, FallbackValue=01-01-1337, Converter={StaticResource DateTimeConverter}}" />
|
|
||||||
<TextBlock TextAlignment="Right">
|
|
||||||
<avalonia:MaterialIcon Kind="Downloads" />
|
|
||||||
<Run Classes="h5" Text="{CompiledBinding Downloads, FallbackValue=0}" />
|
|
||||||
<Run>downloads</Run>
|
|
||||||
</TextBlock>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Button>
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsRepeater.ItemTemplate>
|
</ItemsRepeater.ItemTemplate>
|
||||||
</ItemsRepeater>
|
</ItemsRepeater>
|
||||||
|
|||||||
@ -21,21 +21,25 @@ public class SubmissionsTabViewModel : RoutableScreen
|
|||||||
private readonly IWorkshopClient _client;
|
private readonly IWorkshopClient _client;
|
||||||
private readonly SourceCache<IGetSubmittedEntries_SubmittedEntries, Guid> _entries;
|
private readonly SourceCache<IGetSubmittedEntries_SubmittedEntries, Guid> _entries;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private readonly IRouter _router;
|
|
||||||
private bool _isLoading = true;
|
private bool _isLoading = true;
|
||||||
private bool _workshopReachable;
|
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<IGetSubmittedEntries_SubmittedEntries, SubmissionsTabItemViewModel> getSubmissionsTabItemViewModel)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
_router = router;
|
|
||||||
_entries = new SourceCache<IGetSubmittedEntries_SubmittedEntries, Guid>(e => e.Id);
|
_entries = new SourceCache<IGetSubmittedEntries_SubmittedEntries, Guid>(e => e.Id);
|
||||||
_entries.Connect().Bind(out ReadOnlyObservableCollection<IGetSubmittedEntries_SubmittedEntries> entries).Subscribe();
|
_entries.Connect()
|
||||||
|
.Transform(getSubmissionsTabItemViewModel)
|
||||||
|
.Bind(out ReadOnlyObservableCollection<SubmissionsTabItemViewModel> entries)
|
||||||
|
.Subscribe();
|
||||||
|
|
||||||
AddSubmission = ReactiveCommand.CreateFromTask(ExecuteAddSubmission, this.WhenAnyValue(vm => vm.WorkshopReachable));
|
AddSubmission = ReactiveCommand.CreateFromTask(ExecuteAddSubmission, this.WhenAnyValue(vm => vm.WorkshopReachable));
|
||||||
Login = ReactiveCommand.CreateFromTask(ExecuteLogin, this.WhenAnyValue(vm => vm.WorkshopReachable));
|
Login = ReactiveCommand.CreateFromTask(ExecuteLogin, this.WhenAnyValue(vm => vm.WorkshopReachable));
|
||||||
NavigateToEntry = ReactiveCommand.CreateFromTask<IGetSubmittedEntries_SubmittedEntries>(ExecuteNavigateToEntry);
|
|
||||||
|
|
||||||
IsLoggedIn = authenticationService.IsLoggedIn;
|
IsLoggedIn = authenticationService.IsLoggedIn;
|
||||||
Entries = entries;
|
Entries = entries;
|
||||||
@ -53,7 +57,7 @@ public class SubmissionsTabViewModel : RoutableScreen
|
|||||||
public ReactiveCommand<IGetSubmittedEntries_SubmittedEntries, Unit> NavigateToEntry { get; }
|
public ReactiveCommand<IGetSubmittedEntries_SubmittedEntries, Unit> NavigateToEntry { get; }
|
||||||
|
|
||||||
public IObservable<bool> IsLoggedIn { get; }
|
public IObservable<bool> IsLoggedIn { get; }
|
||||||
public ReadOnlyObservableCollection<IGetSubmittedEntries_SubmittedEntries> Entries { get; }
|
public ReadOnlyObservableCollection<SubmissionsTabItemViewModel> Entries { get; }
|
||||||
|
|
||||||
public bool WorkshopReachable
|
public bool WorkshopReachable
|
||||||
{
|
{
|
||||||
@ -78,11 +82,6 @@ public class SubmissionsTabViewModel : RoutableScreen
|
|||||||
await _windowService.ShowDialogAsync<SubmissionWizardViewModel>();
|
await _windowService.ShowDialogAsync<SubmissionWizardViewModel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExecuteNavigateToEntry(IGetSubmittedEntries_SubmittedEntries entry, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
await _router.Navigate($"workshop/library/submissions/{entry.Id}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task GetEntries(CancellationToken ct)
|
private async Task GetEntries(CancellationToken ct)
|
||||||
{
|
{
|
||||||
IsLoading = true;
|
IsLoading = true;
|
||||||
|
|||||||
@ -10,8 +10,8 @@ using Artemis.UI.Shared.Services;
|
|||||||
using Artemis.UI.Shared.Services.Builders;
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
using Artemis.WebClient.Workshop.DownloadHandlers;
|
using Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
|
||||||
using Artemis.WebClient.Workshop.DownloadHandlers.Implementations;
|
using Artemis.WebClient.Workshop.Handlers.InstallationHandlers.Implementations;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using StrawberryShake;
|
using StrawberryShake;
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ public class ProfileDetailsViewModel : RoutableScreen<WorkshopDetailParameters>
|
|||||||
if (!confirm)
|
if (!confirm)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EntryInstallResult<ProfileConfiguration> result = await _installationHandler.InstallProfileAsync(Entry, Entry.LatestRelease.Id, new Progress<StreamProgress>(), cancellationToken);
|
EntryInstallResult result = await _installationHandler.InstallAsync(Entry, Entry.LatestRelease.Id, new Progress<StreamProgress>(), cancellationToken);
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
_notificationService.CreateNotification().WithTitle("Profile installed").WithSeverity(NotificationSeverity.Success).Show();
|
_notificationService.CreateNotification().WithTitle("Profile installed").WithSeverity(NotificationSeverity.Success).Show();
|
||||||
else
|
else
|
||||||
|
|||||||
@ -8,8 +8,8 @@ using Artemis.UI.Shared.Services;
|
|||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
using Artemis.WebClient.Workshop.Exceptions;
|
using Artemis.WebClient.Workshop.Exceptions;
|
||||||
|
using Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||||
using Artemis.WebClient.Workshop.Services;
|
using Artemis.WebClient.Workshop.Services;
|
||||||
using Artemis.WebClient.Workshop.UploadHandlers;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using StrawberryShake;
|
using StrawberryShake;
|
||||||
|
|
||||||
|
|||||||
@ -48,4 +48,8 @@
|
|||||||
<Generator>MSBuild:GenerateGraphQLCode</Generator>
|
<Generator>MSBuild:GenerateGraphQLCode</Generator>
|
||||||
</GraphQL>
|
</GraphQL>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Handlers\" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
using Artemis.Web.Workshop.Entities;
|
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.DownloadHandlers;
|
|
||||||
|
|
||||||
public class EntryInstallResult<T>
|
|
||||||
{
|
|
||||||
public bool IsSuccess { get; set; }
|
|
||||||
public string? Message { get; set; }
|
|
||||||
public T? Result { get; set; }
|
|
||||||
|
|
||||||
public static EntryInstallResult<T> FromFailure(string? message)
|
|
||||||
{
|
|
||||||
return new EntryInstallResult<T>
|
|
||||||
{
|
|
||||||
IsSuccess = false,
|
|
||||||
Message = message
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EntryInstallResult<T> FromSuccess(T installationResult)
|
|
||||||
{
|
|
||||||
return new EntryInstallResult<T>
|
|
||||||
{
|
|
||||||
IsSuccess = true,
|
|
||||||
Result = installationResult
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
using Artemis.UI.Shared.Utilities;
|
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.DownloadHandlers;
|
|
||||||
|
|
||||||
public interface IEntryInstallationHandler
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -1,10 +1,10 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Artemis.WebClient.Workshop.DownloadHandlers;
|
|
||||||
using Artemis.WebClient.Workshop.Extensions;
|
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.Repositories;
|
||||||
using Artemis.WebClient.Workshop.Services;
|
using Artemis.WebClient.Workshop.Services;
|
||||||
using Artemis.WebClient.Workshop.State;
|
using Artemis.WebClient.Workshop.State;
|
||||||
using Artemis.WebClient.Workshop.UploadHandlers;
|
|
||||||
using DryIoc;
|
using DryIoc;
|
||||||
using DryIoc.Microsoft.DependencyInjection;
|
using DryIoc.Microsoft.DependencyInjection;
|
||||||
using IdentityModel.Client;
|
using IdentityModel.Client;
|
||||||
|
|||||||
@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<ProfileEntryInstallationHandler>(),
|
||||||
|
_ => throw new NotSupportedException($"EntryType '{entryType}' is not supported.")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
using Artemis.UI.Shared.Utilities;
|
||||||
|
using Artemis.WebClient.Workshop.Services;
|
||||||
|
|
||||||
|
namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
|
||||||
|
|
||||||
|
public interface IEntryInstallationHandler
|
||||||
|
{
|
||||||
|
Task<EntryInstallResult> InstallAsync(IGetEntryById_Entry entry, Guid releaseId, Progress<StreamProgress> progress, CancellationToken cancellationToken);
|
||||||
|
Task<EntryUninstallResult> UninstallAsync(InstalledEntry installedEntry, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
@ -4,7 +4,7 @@ using Artemis.UI.Shared.Extensions;
|
|||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
using Artemis.WebClient.Workshop.Services;
|
using Artemis.WebClient.Workshop.Services;
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.DownloadHandlers.Implementations;
|
namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers.Implementations;
|
||||||
|
|
||||||
public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
||||||
{
|
{
|
||||||
@ -19,7 +19,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
|||||||
_workshopService = workshopService;
|
_workshopService = workshopService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<EntryInstallResult<ProfileConfiguration>> InstallProfileAsync(IGetEntryById_Entry entry, Guid releaseId, Progress<StreamProgress> progress, CancellationToken cancellationToken)
|
public async Task<EntryInstallResult> InstallAsync(IGetEntryById_Entry entry, Guid releaseId, Progress<StreamProgress> progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
using MemoryStream stream = new();
|
using MemoryStream stream = new();
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
return EntryInstallResult<ProfileConfiguration>.FromFailure(e.Message);
|
return EntryInstallResult.FromFailure(e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find existing installation to potentially replace the profile
|
// Find existing installation to potentially replace the profile
|
||||||
@ -46,7 +46,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
|||||||
|
|
||||||
// Update the release and return the profile configuration
|
// Update the release and return the profile configuration
|
||||||
UpdateRelease(releaseId, installedEntry);
|
UpdateRelease(releaseId, installedEntry);
|
||||||
return EntryInstallResult<ProfileConfiguration>.FromSuccess(overwritten);
|
return EntryInstallResult.FromSuccess(overwritten);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,33 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
|
|||||||
|
|
||||||
// Update the release and return the profile configuration
|
// Update the release and return the profile configuration
|
||||||
UpdateRelease(releaseId, installedEntry);
|
UpdateRelease(releaseId, installedEntry);
|
||||||
return EntryInstallResult<ProfileConfiguration>.FromSuccess(imported);
|
return EntryInstallResult.FromSuccess(imported);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<EntryUninstallResult> 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)
|
private void UpdateRelease(Guid releaseId, InstalledEntry installedEntry)
|
||||||
@ -1,7 +1,7 @@
|
|||||||
using Artemis.WebClient.Workshop.UploadHandlers.Implementations;
|
using Artemis.WebClient.Workshop.Handlers.UploadHandlers.Implementations;
|
||||||
using DryIoc;
|
using DryIoc;
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.UploadHandlers;
|
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||||
|
|
||||||
public class EntryUploadHandlerFactory
|
public class EntryUploadHandlerFactory
|
||||||
{
|
{
|
||||||
@ -1,6 +1,6 @@
|
|||||||
using Artemis.Web.Workshop.Entities;
|
using Artemis.Web.Workshop.Entities;
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.UploadHandlers;
|
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||||
|
|
||||||
public class EntryUploadResult
|
public class EntryUploadResult
|
||||||
{
|
{
|
||||||
@ -1,6 +1,6 @@
|
|||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.UploadHandlers;
|
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||||
|
|
||||||
public interface IEntryUploadHandler
|
public interface IEntryUploadHandler
|
||||||
{
|
{
|
||||||
@ -1,4 +1,4 @@
|
|||||||
namespace Artemis.WebClient.Workshop.UploadHandlers;
|
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||||
|
|
||||||
public class ImageUploadResult
|
public class ImageUploadResult
|
||||||
{
|
{
|
||||||
@ -1,6 +1,6 @@
|
|||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.UploadHandlers.Implementations;
|
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers.Implementations;
|
||||||
|
|
||||||
public class LayoutEntryUploadHandler : IEntryUploadHandler
|
public class LayoutEntryUploadHandler : IEntryUploadHandler
|
||||||
{
|
{
|
||||||
@ -1,12 +1,11 @@
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.Storage.Repositories.Interfaces;
|
|
||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
using Artemis.Web.Workshop.Entities;
|
using Artemis.Web.Workshop.Entities;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.UploadHandlers.Implementations;
|
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers.Implementations;
|
||||||
|
|
||||||
public class ProfileEntryUploadHandler : IEntryUploadHandler
|
public class ProfileEntryUploadHandler : IEntryUploadHandler
|
||||||
{
|
{
|
||||||
@ -20,7 +20,6 @@ public class InstalledEntry
|
|||||||
|
|
||||||
Author = entry.Author;
|
Author = entry.Author;
|
||||||
Name = entry.Name;
|
Name = entry.Name;
|
||||||
Summary = entry.Summary;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid EntryId { get; set; }
|
public Guid EntryId { get; set; }
|
||||||
@ -28,7 +27,6 @@ public class InstalledEntry
|
|||||||
|
|
||||||
public string Author { get; set; } = string.Empty;
|
public string Author { get; set; } = string.Empty;
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public string Summary { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public Guid ReleaseId { get; set; }
|
public Guid ReleaseId { get; set; }
|
||||||
public string ReleaseVersion { get; set; } = string.Empty;
|
public string ReleaseVersion { get; set; } = string.Empty;
|
||||||
@ -45,7 +43,6 @@ public class InstalledEntry
|
|||||||
|
|
||||||
Author = Entity.Author;
|
Author = Entity.Author;
|
||||||
Name = Entity.Name;
|
Name = Entity.Name;
|
||||||
Summary = Entity.Summary;
|
|
||||||
|
|
||||||
ReleaseId = Entity.ReleaseId;
|
ReleaseId = Entity.ReleaseId;
|
||||||
ReleaseVersion = Entity.ReleaseVersion;
|
ReleaseVersion = Entity.ReleaseVersion;
|
||||||
@ -61,7 +58,6 @@ public class InstalledEntry
|
|||||||
|
|
||||||
Entity.Author = Author;
|
Entity.Author = Author;
|
||||||
Entity.Name = Name;
|
Entity.Name = Name;
|
||||||
Entity.Summary = Summary;
|
|
||||||
|
|
||||||
Entity.ReleaseId = ReleaseId;
|
Entity.ReleaseId = ReleaseId;
|
||||||
Entity.ReleaseVersion = ReleaseVersion;
|
Entity.ReleaseVersion = ReleaseVersion;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
using Artemis.WebClient.Workshop.UploadHandlers;
|
using Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.Services;
|
namespace Artemis.WebClient.Workshop.Services;
|
||||||
|
|
||||||
@ -14,7 +14,9 @@ public interface IWorkshopService
|
|||||||
List<InstalledEntry> GetInstalledEntries();
|
List<InstalledEntry> GetInstalledEntries();
|
||||||
InstalledEntry? GetInstalledEntry(IGetEntryById_Entry entry);
|
InstalledEntry? GetInstalledEntry(IGetEntryById_Entry entry);
|
||||||
InstalledEntry CreateInstalledEntry(IGetEntryById_Entry entry);
|
InstalledEntry CreateInstalledEntry(IGetEntryById_Entry entry);
|
||||||
|
void RemoveInstalledEntry(InstalledEntry installedEntry);
|
||||||
void SaveInstalledEntry(InstalledEntry entry);
|
void SaveInstalledEntry(InstalledEntry entry);
|
||||||
|
|
||||||
|
|
||||||
public record WorkshopStatus(bool IsReachable, string Message);
|
public record WorkshopStatus(bool IsReachable, string Message);
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@ using Artemis.Storage.Entities.Workshop;
|
|||||||
using Artemis.Storage.Repositories.Interfaces;
|
using Artemis.Storage.Repositories.Interfaces;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
using Artemis.WebClient.Workshop.UploadHandlers;
|
using Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||||
|
|
||||||
namespace Artemis.WebClient.Workshop.Services;
|
namespace Artemis.WebClient.Workshop.Services;
|
||||||
|
|
||||||
@ -124,6 +124,12 @@ public class WorkshopService : IWorkshopService
|
|||||||
return new InstalledEntry(entry);
|
return new InstalledEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void RemoveInstalledEntry(InstalledEntry installedEntry)
|
||||||
|
{
|
||||||
|
_entryRepository.Remove(installedEntry.Entity);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void SaveInstalledEntry(InstalledEntry entry)
|
public void SaveInstalledEntry(InstalledEntry entry)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user