mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Workshop - Reworked installation management
This commit is contained in:
1 parent
d6f1ba9aad
commit
6b4ed48d05
28 files changed
+514
-197
No files matched your search
@@ -0,0 +1,34 @@
|
||||
<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: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"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Workshop.EntryReleases.EntryReleaseItemView"
|
||||
x:DataType="entryReleases:EntryReleaseItemViewModel">
|
||||
<UserControl.Resources>
|
||||
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
||||
</UserControl.Resources>
|
||||
<UserControl.Styles>
|
||||
<Style Selector="avalonia|MaterialIcon.status-icon">
|
||||
<Setter Property="Width" Value="20" />
|
||||
<Setter Property="Height" Value="20" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource SystemAccentColorLight1}" />
|
||||
</Style>
|
||||
</UserControl.Styles>
|
||||
|
||||
<Grid ColumnDefinitions="Auto,*" Margin="0 5">
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="{CompiledBinding Release.Version}"></TextBlock>
|
||||
<TextBlock Classes="subtitle" ToolTip.Tip="{CompiledBinding Release.CreatedAt, Converter={StaticResource DateTimeConverter}}">
|
||||
<avalonia:MaterialIcon Kind="Calendar" />
|
||||
<Run>Created</Run>
|
||||
<Run Text="{CompiledBinding Release.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter='humanize'}"></Run>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<avalonia:MaterialIcon Classes="status-icon" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right" Kind="CheckCircle" ToolTip.Tip="Current version" IsVisible="{CompiledBinding IsCurrentVersion}" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,11 @@
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Workshop.EntryReleases;
|
||||
|
||||
public partial class EntryReleaseItemView : ReactiveUserControl<EntryReleaseItemViewModel>
|
||||
{
|
||||
public EntryReleaseItemView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.WebClient.Workshop;
|
||||
using Artemis.WebClient.Workshop.Models;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
using PropertyChanged.SourceGenerator;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Workshop.EntryReleases;
|
||||
|
||||
public partial class EntryReleaseItemViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly IWorkshopService _workshopService;
|
||||
private readonly IEntryDetails _entry;
|
||||
[Notify] private bool _isCurrentVersion;
|
||||
|
||||
public EntryReleaseItemViewModel(IWorkshopService workshopService, IEntryDetails entry, IRelease release)
|
||||
{
|
||||
_workshopService = workshopService;
|
||||
_entry = entry;
|
||||
|
||||
Release = release;
|
||||
UpdateIsCurrentVersion();
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
Observable.FromEventPattern<InstalledEntry>(x => _workshopService.OnInstalledEntrySaved += x, x => _workshopService.OnInstalledEntrySaved -= x)
|
||||
.Subscribe(_ => UpdateIsCurrentVersion())
|
||||
.DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public IRelease Release { get; }
|
||||
|
||||
private void UpdateIsCurrentVersion()
|
||||
{
|
||||
IsCurrentVersion = _workshopService.GetInstalledEntry(_entry.Id)?.ReleaseId == Release.Id;
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@
|
||||
<avalonia:MaterialIcon Kind="ArrowBack" />
|
||||
</Button>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Classes="h4 no-margin">Release info</TextBlock>
|
||||
<Panel Grid.Column="2">
|
||||
<StackPanel Grid.Column="2">
|
||||
<!-- Install progress -->
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="5"
|
||||
@@ -66,14 +66,15 @@
|
||||
</StackPanel>
|
||||
|
||||
<!-- Install button -->
|
||||
<Button IsVisible="{CompiledBinding !InstallationInProgress}"
|
||||
HorizontalAlignment="Right"
|
||||
Classes="accent"
|
||||
Width="80"
|
||||
Command="{CompiledBinding Install}">
|
||||
Install
|
||||
</Button>
|
||||
</Panel>
|
||||
<Panel IsVisible="{CompiledBinding !InstallationInProgress}" HorizontalAlignment="Right">
|
||||
<Button IsVisible="{CompiledBinding !IsCurrentVersion}" Classes="accent" Width="80" Command="{CompiledBinding Install}">
|
||||
Install
|
||||
</Button>
|
||||
<Button IsVisible="{CompiledBinding IsCurrentVersion}" Classes="accent" Width="80" Command="{CompiledBinding Reinstall}">
|
||||
Re-install
|
||||
</Button>
|
||||
</Panel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Border Classes="card-separator" />
|
||||
<Grid Margin="-5 -10" ColumnDefinitions="*,*,*">
|
||||
|
||||
@@ -8,6 +8,7 @@ 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;
|
||||
|
||||
@@ -19,21 +20,25 @@ public partial class EntryReleaseViewModel : RoutableScreen<ReleaseDetailParamet
|
||||
private readonly IRouter _router;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly IWindowService _windowService;
|
||||
private readonly IWorkshopService _workshopService;
|
||||
private readonly EntryInstallationHandlerFactory _factory;
|
||||
private readonly Progress<StreamProgress> _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, EntryInstallationHandlerFactory factory)
|
||||
public EntryReleaseViewModel(IWorkshopClient client, IRouter router, INotificationService notificationService, IWindowService windowService, IWorkshopService workshopService,
|
||||
EntryInstallationHandlerFactory factory)
|
||||
{
|
||||
_client = client;
|
||||
_router = router;
|
||||
_notificationService = notificationService;
|
||||
_windowService = windowService;
|
||||
_workshopService = workshopService;
|
||||
_factory = factory;
|
||||
_progress.ProgressChanged += (_, f) => InstallProgress = f.ProgressPercentage;
|
||||
}
|
||||
@@ -56,18 +61,32 @@ public partial class EntryReleaseViewModel : RoutableScreen<ReleaseDetailParamet
|
||||
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);
|
||||
}
|
||||
finally
|
||||
{
|
||||
InstallationInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -80,6 +99,7 @@ public partial class EntryReleaseViewModel : RoutableScreen<ReleaseDetailParamet
|
||||
{
|
||||
IOperationResult<IGetReleaseByIdResult> result = await _client.GetReleaseById.ExecuteAsync(parameters.ReleaseId, cancellationToken);
|
||||
Release = result.Data?.Release;
|
||||
IsCurrentVersion = Release != null && _workshopService.GetInstalledEntry(Release.Entry.Id)?.ReleaseId == Release.Id;
|
||||
}
|
||||
|
||||
#region Overrides of RoutableScreen
|
||||
|
||||
@@ -2,38 +2,12 @@
|
||||
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:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:sharedConverters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:workshop="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop"
|
||||
xmlns:entryReleases="clr-namespace:Artemis.UI.Screens.Workshop.EntryReleases"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Workshop.EntryReleases.EntryReleasesView"
|
||||
x:DataType="entryReleases:EntryReleasesViewModel">
|
||||
<UserControl.Resources>
|
||||
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
||||
<sharedConverters:BytesToStringConverter x:Key="BytesToStringConverter" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<StackPanel>
|
||||
x:DataType="entryReleases:EntryReleasesViewModel"><StackPanel>
|
||||
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">Releases</TextBlock>
|
||||
<Border Classes="card-separator" />
|
||||
|
||||
<ListBox ItemsSource="{CompiledBinding Releases}" SelectedItem="{CompiledBinding SelectedRelease}" Classes="release-list">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="workshop:IRelease">
|
||||
<Grid ColumnDefinitions="Auto,*" Margin="0 5">
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="{CompiledBinding Version}"></TextBlock>
|
||||
<TextBlock Classes="subtitle" ToolTip.Tip="{CompiledBinding CreatedAt, Converter={StaticResource DateTimeConverter}}">
|
||||
<avalonia:MaterialIcon Kind="Calendar" />
|
||||
<Run>Created</Run>
|
||||
<Run Text="{CompiledBinding CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter='humanize'}"></Run>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<ListBox ItemsSource="{CompiledBinding Releases}" SelectedItem="{CompiledBinding SelectedRelease}"/>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -16,38 +16,34 @@ namespace Artemis.UI.Screens.Workshop.EntryReleases;
|
||||
public partial class EntryReleasesViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly IRouter _router;
|
||||
[Notify] private IRelease? _selectedRelease;
|
||||
[Notify] private EntryReleaseItemViewModel? _selectedRelease;
|
||||
|
||||
public EntryReleasesViewModel(IEntryDetails entry, IRouter router)
|
||||
public EntryReleasesViewModel(IEntryDetails entry, IRouter router, Func<IRelease, EntryReleaseItemViewModel> getEntryReleaseItemViewModel)
|
||||
{
|
||||
_router = router;
|
||||
|
||||
Entry = entry;
|
||||
Releases = Entry.Releases.OrderByDescending(r => r.CreatedAt).Take(5).Cast<IRelease>().ToList();
|
||||
Releases = Entry.Releases.OrderByDescending(r => r.CreatedAt).Take(5).Select(r => getEntryReleaseItemViewModel(r)).ToList();
|
||||
NavigateToRelease = ReactiveCommand.CreateFromTask<IRelease>(ExecuteNavigateToRelease);
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
router.CurrentPath.Subscribe(p => SelectedRelease = p != null && p.Contains("releases") && float.TryParse(p.Split('/').Last(), out float releaseId)
|
||||
? Releases.FirstOrDefault(r => r.Id == releaseId)
|
||||
? Releases.FirstOrDefault(r => r.Release.Id == releaseId)
|
||||
: null)
|
||||
.DisposeWith(d);
|
||||
|
||||
this.WhenAnyValue(vm => vm.SelectedRelease)
|
||||
.WhereNotNull()
|
||||
.Subscribe(s => ExecuteNavigateToRelease(s))
|
||||
.Subscribe(s => ExecuteNavigateToRelease(s.Release))
|
||||
.DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public IEntryDetails Entry { get; }
|
||||
public List<IRelease> Releases { get; }
|
||||
|
||||
public List<EntryReleaseItemViewModel> Releases { get; }
|
||||
public ReactiveCommand<IRelease, Unit> NavigateToRelease { get; }
|
||||
|
||||
public Func<IEntryDetails, IRelease, Task<bool>> OnInstallationStarted { get; set; }
|
||||
public Func<InstalledEntry, Task>? OnInstallationFinished { get; set; }
|
||||
|
||||
private async Task ExecuteNavigateToRelease(IRelease release)
|
||||
{
|
||||
switch (Entry.EntryType)
|
||||
|
||||
Reference in new issue
Block a user