mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 21:38:38 +00:00
Workshop - Manage entries after installing them
Workshop - Auto-enable plugins after installing them Workshop - Show the latest release above the details page
This commit is contained in:
parent
966ca47335
commit
86f78940b1
@ -50,7 +50,7 @@ public interface IRouter
|
|||||||
/// Asynchronously navigates upwards to the parent route.
|
/// Asynchronously navigates upwards to the parent route.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> GoUp();
|
Task<bool> GoUp(RouterNavigationOptions? options = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears the navigation history.
|
/// Clears the navigation history.
|
||||||
|
|||||||
@ -8,9 +8,10 @@ namespace Artemis.UI.Shared.Routing;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class NavigationArguments
|
public class NavigationArguments
|
||||||
{
|
{
|
||||||
internal NavigationArguments(IRouter router, string path, object[] routeParameters)
|
internal NavigationArguments(IRouter router, RouterNavigationOptions options, string path, object[] routeParameters)
|
||||||
{
|
{
|
||||||
Router = router;
|
Router = router;
|
||||||
|
Options = options;
|
||||||
Path = path;
|
Path = path;
|
||||||
RouteParameters = routeParameters;
|
RouteParameters = routeParameters;
|
||||||
SegmentParameters = Array.Empty<object>();
|
SegmentParameters = Array.Empty<object>();
|
||||||
@ -21,6 +22,11 @@ public class NavigationArguments
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IRouter Router { get; }
|
public IRouter Router { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the options that are being used for this navigation.
|
||||||
|
/// </summary>
|
||||||
|
public RouterNavigationOptions Options { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the path of the route that is being navigated to.
|
/// Gets the path of the route that is being navigated to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -114,7 +114,7 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationArguments args = new(this, resolution.Path, resolution.GetAllParameters());
|
NavigationArguments args = new(this, options, resolution.Path, resolution.GetAllParameters());
|
||||||
|
|
||||||
if (!await RequestClose(_root, args))
|
if (!await RequestClose(_root, args))
|
||||||
return;
|
return;
|
||||||
@ -169,7 +169,7 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<bool> GoUp()
|
public async Task<bool> GoUp(RouterNavigationOptions? options = null)
|
||||||
{
|
{
|
||||||
string? currentPath = _currentRouteSubject.Value;
|
string? currentPath = _currentRouteSubject.Value;
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable
|
|||||||
RouteResolution resolution = Resolve(parentPath);
|
RouteResolution resolution = Resolve(parentPath);
|
||||||
if (resolution.Success)
|
if (resolution.Success)
|
||||||
{
|
{
|
||||||
await Navigate(parentPath, new RouterNavigationOptions {AddToHistory = false});
|
await Navigate(parentPath, options);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,11 @@ public class RouterNavigationOptions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EnableLogging { get; set; } = true;
|
public bool EnableLogging { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets any additional arguments to pass to the screen.
|
||||||
|
/// </summary>
|
||||||
|
public object? AdditionalArguments { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the given two paths are considered equal using these navigation options.
|
/// Determines whether the given two paths are considered equal using these navigation options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -249,7 +249,7 @@ public partial class PluginViewModel : ActivatableViewModelBase
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// If the plugin or any of its features has uninstall actions, offer to run these
|
// If the plugin or any of its features has uninstall actions, offer to run these
|
||||||
await ExecuteRemovePrerequisites(true);
|
await ExecuteRemovePrerequisites(true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -264,7 +264,7 @@ public partial class PluginViewModel : ActivatableViewModelBase
|
|||||||
InstalledEntry? entry = _workshopService.GetInstalledEntries().FirstOrDefault(e => e.TryGetMetadata("PluginId", out Guid pluginId) && pluginId == Plugin.Guid);
|
InstalledEntry? entry = _workshopService.GetInstalledEntries().FirstOrDefault(e => e.TryGetMetadata("PluginId", out Guid pluginId) && pluginId == Plugin.Guid);
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
_workshopService.RemoveInstalledEntry(entry);
|
_workshopService.RemoveInstalledEntry(entry);
|
||||||
|
|
||||||
_notificationService.CreateNotification().WithTitle("Removed plugin.").Show();
|
_notificationService.CreateNotification().WithTitle("Removed plugin.").Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,4 +303,19 @@ public partial class PluginViewModel : ActivatableViewModelBase
|
|||||||
_settingsWindow?.Close();
|
_settingsWindow?.Close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task AutoEnable()
|
||||||
|
{
|
||||||
|
if (IsEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await UpdateEnabled(true);
|
||||||
|
|
||||||
|
// If enabling failed, don't offer to show the settings
|
||||||
|
if (!IsEnabled || Plugin.ConfigurationDialog == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (await _windowService.ShowConfirmContentDialog("Open plugin settings", "This plugin has settings, would you like to view them?", "Yes", "No"))
|
||||||
|
ExecuteOpenSettings();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,111 @@
|
|||||||
|
<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:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
|
xmlns:entryReleases="clr-namespace:Artemis.UI.Screens.Workshop.EntryReleases"
|
||||||
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
|
xmlns:converters1="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.EntryReleases.EntryReleaseInfoView"
|
||||||
|
x:DataType="entryReleases:EntryReleaseInfoViewModel">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
||||||
|
<converters1:BytesToStringConverter x:Key="BytesToStringConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<UserControl.Styles>
|
||||||
|
<Style Selector="Grid.info-container">
|
||||||
|
<Setter Property="Margin" Value="10" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="avalonia|MaterialIcon.info-icon">
|
||||||
|
<Setter Property="VerticalAlignment" Value="Top" />
|
||||||
|
<Setter Property="Margin" Value="0 3 10 0" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="TextBlock.info-title">
|
||||||
|
<Setter Property="Margin" Value="0 0 0 5" />
|
||||||
|
<Setter Property="Opacity" Value="0.8" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="TextBlock.info-body">
|
||||||
|
</Style>
|
||||||
|
<Style Selector="TextBlock.info-link">
|
||||||
|
<Setter Property="Cursor" Value="Hand" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource SystemAccentColorLight3}" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="TextBlock.info-link:pointerover">
|
||||||
|
<Setter Property="Cursor" Value="Hand" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource SystemAccentColorLight1}" />
|
||||||
|
</Style>
|
||||||
|
</UserControl.Styles>
|
||||||
|
<StackPanel>
|
||||||
|
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||||
|
<Button Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Classes="icon-button" Margin="0 0 5 0" Command="{CompiledBinding Close}" IsVisible="{CompiledBinding InDetailsScreen}">
|
||||||
|
<avalonia:MaterialIcon Kind="ArrowBack" />
|
||||||
|
</Button>
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="1" Theme="{StaticResource SubtitleTextBlockStyle}" IsVisible="{CompiledBinding InDetailsScreen}">Release info</TextBlock>
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="1" Theme="{StaticResource SubtitleTextBlockStyle}" IsVisible="{CompiledBinding !InDetailsScreen}">Latest release</TextBlock>
|
||||||
|
<StackPanel Grid.Column="2">
|
||||||
|
<!-- Install progress -->
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
Spacing="5"
|
||||||
|
IsVisible="{CompiledBinding InstallationInProgress}">
|
||||||
|
<ProgressBar VerticalAlignment="Center"
|
||||||
|
Width="300"
|
||||||
|
Value="{CompiledBinding InstallProgress, FallbackValue=0}">
|
||||||
|
</ProgressBar>
|
||||||
|
<Button
|
||||||
|
Classes="accent"
|
||||||
|
Margin="15 0 0 0"
|
||||||
|
Width="80"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Command="{CompiledBinding Cancel}">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Install button -->
|
||||||
|
<Panel IsVisible="{CompiledBinding !InstallationInProgress}" HorizontalAlignment="Right">
|
||||||
|
<Button IsVisible="{CompiledBinding !IsCurrentVersion}" Classes="accent" Width="80" Command="{CompiledBinding Install}">
|
||||||
|
Install
|
||||||
|
</Button>
|
||||||
|
<StackPanel IsVisible="{CompiledBinding IsCurrentVersion}" Orientation="Horizontal" Spacing="10">
|
||||||
|
<Button Classes="accent" Width="80" Command="{CompiledBinding Reinstall}">
|
||||||
|
Re-install
|
||||||
|
</Button>
|
||||||
|
<Button Width="80" Command="{CompiledBinding Uninstall}">Uninstall</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Panel>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
<Border Classes="card-separator" />
|
||||||
|
<Grid Margin="-5 -10" ColumnDefinitions="*,*,*">
|
||||||
|
<Grid Grid.Column="0" ColumnDefinitions="*,*" RowDefinitions="*,*" Classes="info-container" HorizontalAlignment="Left">
|
||||||
|
<avalonia:MaterialIcon Kind="TickNetworkOutline" Grid.Column="0" Grid.RowSpan="2" Classes="info-icon" />
|
||||||
|
<TextBlock Grid.Column="1" Grid.Row="0" Classes="info-title">Version</TextBlock>
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
Classes="info-body"
|
||||||
|
Cursor="Hand"
|
||||||
|
Text="{CompiledBinding Release.Version}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid Grid.Column="1" ColumnDefinitions="*,*" RowDefinitions="*,*,*" Classes="info-container" HorizontalAlignment="Center">
|
||||||
|
<avalonia:MaterialIcon Kind="Calendar" Grid.Column="0" Grid.RowSpan="2" Classes="info-icon" />
|
||||||
|
<TextBlock Grid.Column="1" Grid.Row="0" Classes="info-title">Release date</TextBlock>
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
Classes="info-body"
|
||||||
|
Text="{CompiledBinding Release.CreatedAt, Converter={StaticResource DateTimeConverter}}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid Grid.Column="2" ColumnDefinitions="*,*" RowDefinitions="*,*" Classes="info-container" HorizontalAlignment="Right">
|
||||||
|
<avalonia:MaterialIcon Kind="File" Grid.Column="0" Grid.RowSpan="2" Classes="info-icon" />
|
||||||
|
<TextBlock Grid.Column="1" Grid.Row="0" Classes="info-title">File size</TextBlock>
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
Classes="info-body"
|
||||||
|
Text="{CompiledBinding Release.DownloadSize, Converter={StaticResource BytesToStringConverter}, Mode=OneWay}" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.EntryReleases;
|
||||||
|
|
||||||
|
public partial class EntryReleaseInfoView : ReactiveUserControl<EntryReleaseInfoViewModel>
|
||||||
|
{
|
||||||
|
public EntryReleaseInfoView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,173 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.DryIoc.Factories;
|
||||||
|
using Artemis.UI.Screens.Plugins;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Routing;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
|
using Artemis.UI.Shared.Utilities;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
using Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
|
||||||
|
using Artemis.WebClient.Workshop.Models;
|
||||||
|
using Artemis.WebClient.Workshop.Services;
|
||||||
|
using Humanizer;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.EntryReleases;
|
||||||
|
|
||||||
|
public partial class EntryReleaseInfoViewModel : ActivatableViewModelBase
|
||||||
|
{
|
||||||
|
private readonly IRouter _router;
|
||||||
|
private readonly INotificationService _notificationService;
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
|
private readonly IWorkshopService _workshopService;
|
||||||
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
|
private readonly EntryInstallationHandlerFactory _factory;
|
||||||
|
private readonly ISettingsVmFactory _settingsVmFactory;
|
||||||
|
private readonly Progress<StreamProgress> _progress = new();
|
||||||
|
private readonly ObservableAsPropertyHelper<bool> _isCurrentVersion;
|
||||||
|
|
||||||
|
[Notify] private IReleaseDetails? _release;
|
||||||
|
[Notify] private float _installProgress;
|
||||||
|
[Notify] private bool _installationInProgress;
|
||||||
|
[Notify] private bool _inDetailsScreen;
|
||||||
|
|
||||||
|
private CancellationTokenSource? _cts;
|
||||||
|
|
||||||
|
public EntryReleaseInfoViewModel(IRouter router,
|
||||||
|
INotificationService notificationService,
|
||||||
|
IWindowService windowService,
|
||||||
|
IWorkshopService workshopService,
|
||||||
|
IPluginManagementService pluginManagementService,
|
||||||
|
EntryInstallationHandlerFactory factory,
|
||||||
|
ISettingsVmFactory settingsVmFactory)
|
||||||
|
{
|
||||||
|
_router = router;
|
||||||
|
_notificationService = notificationService;
|
||||||
|
_windowService = windowService;
|
||||||
|
_workshopService = workshopService;
|
||||||
|
_pluginManagementService = pluginManagementService;
|
||||||
|
_factory = factory;
|
||||||
|
_settingsVmFactory = settingsVmFactory;
|
||||||
|
_progress.ProgressChanged += (_, f) => InstallProgress = f.ProgressPercentage;
|
||||||
|
|
||||||
|
_isCurrentVersion = this.WhenAnyValue(vm => vm.Release, vm => vm.InstallationInProgress, (release, _) => release)
|
||||||
|
.Select(r => r != null && _workshopService.GetInstalledEntry(r.Entry.Id)?.ReleaseId == r.Id)
|
||||||
|
.ToProperty(this, vm => vm.IsCurrentVersion);
|
||||||
|
|
||||||
|
InDetailsScreen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCurrentVersion => _isCurrentVersion.Value;
|
||||||
|
|
||||||
|
public async Task Close()
|
||||||
|
{
|
||||||
|
await _router.GoUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Install()
|
||||||
|
{
|
||||||
|
if (Release == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the entry has missing dependencies, show a dialog
|
||||||
|
foreach (IGetEntryById_Entry_LatestRelease_Dependencies dependency in Release.Dependencies)
|
||||||
|
{
|
||||||
|
if (_workshopService.GetInstalledEntry(dependency.Id) == null)
|
||||||
|
{
|
||||||
|
if (await _windowService.ShowConfirmContentDialog("Missing dependencies",
|
||||||
|
$"One or more dependencies are missing, this {Release.Entry.EntryType.Humanize(LetterCasing.LowerCase)} won't work without them", "View dependencies"))
|
||||||
|
await _router.GoUp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_cts = new CancellationTokenSource();
|
||||||
|
InstallProgress = 0;
|
||||||
|
InstallationInProgress = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IEntryInstallationHandler handler = _factory.CreateHandler(Release.Entry.EntryType);
|
||||||
|
EntryInstallResult result = await handler.InstallAsync(Release.Entry, Release, _progress, _cts.Token);
|
||||||
|
if (result.IsSuccess)
|
||||||
|
{
|
||||||
|
_notificationService.CreateNotification().WithTitle("Installation succeeded").WithSeverity(NotificationSeverity.Success).Show();
|
||||||
|
InstallationInProgress = false;
|
||||||
|
await Manage();
|
||||||
|
}
|
||||||
|
else if (!_cts.IsCancellationRequested)
|
||||||
|
_notificationService.CreateNotification().WithTitle("Installation failed").WithMessage(result.Message).WithSeverity(NotificationSeverity.Error).Show();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_windowService.ShowExceptionDialog("Failed to install workshop entry", e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
InstallationInProgress = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Manage()
|
||||||
|
{
|
||||||
|
if (Release?.Entry.EntryType != EntryType.Profile)
|
||||||
|
await _router.Navigate("../../manage", new RouterNavigationOptions {AdditionalArguments = true});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Reinstall()
|
||||||
|
{
|
||||||
|
if (await _windowService.ShowConfirmContentDialog("Reinstall entry", "Are you sure you want to reinstall this entry?"))
|
||||||
|
await Install();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Uninstall()
|
||||||
|
{
|
||||||
|
InstalledEntry? installedEntry = _workshopService.GetInstalledEntry(Release!.Entry.Id);
|
||||||
|
if (installedEntry == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
InstallationInProgress = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool confirmed = await _windowService.ShowConfirmContentDialog("Do you want to uninstall this entry?", "Both the entry and its contents will be removed.");
|
||||||
|
if (!confirmed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Ideally the installation handler does this but it doesn't have access to the required view models
|
||||||
|
if (installedEntry.EntryType == EntryType.Plugin)
|
||||||
|
await UninstallPluginPrerequisites(installedEntry);
|
||||||
|
|
||||||
|
IEntryInstallationHandler handler = _factory.CreateHandler(installedEntry.EntryType);
|
||||||
|
await handler.UninstallAsync(installedEntry, CancellationToken.None);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
InstallationInProgress = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Cancel()
|
||||||
|
{
|
||||||
|
_cts?.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UninstallPluginPrerequisites(InstalledEntry installedEntry)
|
||||||
|
{
|
||||||
|
if (!installedEntry.TryGetMetadata("PluginId", out Guid pluginId))
|
||||||
|
return;
|
||||||
|
Plugin? plugin = _pluginManagementService.GetAllPlugins().FirstOrDefault(p => p.Guid == pluginId);
|
||||||
|
if (plugin == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PluginViewModel pluginViewModel = _settingsVmFactory.PluginViewModel(plugin, ReactiveCommand.Create(() => { }));
|
||||||
|
await pluginViewModel.ExecuteRemovePrerequisites(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,110 +4,12 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight"
|
xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight"
|
||||||
xmlns:entryReleases="clr-namespace:Artemis.UI.Screens.Workshop.EntryReleases"
|
xmlns:entryReleases="clr-namespace:Artemis.UI.Screens.Workshop.EntryReleases"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
|
||||||
xmlns:sharedConverters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Workshop.EntryReleases.EntryReleaseView"
|
x:Class="Artemis.UI.Screens.Workshop.EntryReleases.EntryReleaseView"
|
||||||
x:DataType="entryReleases:EntryReleaseViewModel">
|
x:DataType="entryReleases:EntryReleaseViewModel">
|
||||||
<UserControl.Resources>
|
|
||||||
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
|
||||||
<sharedConverters:BytesToStringConverter x:Key="BytesToStringConverter" />
|
|
||||||
</UserControl.Resources>
|
|
||||||
<UserControl.Styles>
|
|
||||||
<Style Selector="Grid.info-container">
|
|
||||||
<Setter Property="Margin" Value="10" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="avalonia|MaterialIcon.info-icon">
|
|
||||||
<Setter Property="VerticalAlignment" Value="Top" />
|
|
||||||
<Setter Property="Margin" Value="0 3 10 0" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="TextBlock.info-title">
|
|
||||||
<Setter Property="Margin" Value="0 0 0 5" />
|
|
||||||
<Setter Property="Opacity" Value="0.8" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="TextBlock.info-body">
|
|
||||||
</Style>
|
|
||||||
<Style Selector="TextBlock.info-link">
|
|
||||||
<Setter Property="Cursor" Value="Hand" />
|
|
||||||
<Setter Property="Foreground" Value="{DynamicResource SystemAccentColorLight3}" />
|
|
||||||
</Style>
|
|
||||||
<Style Selector="TextBlock.info-link:pointerover">
|
|
||||||
<Setter Property="Cursor" Value="Hand" />
|
|
||||||
<Setter Property="Foreground" Value="{DynamicResource SystemAccentColorLight1}" />
|
|
||||||
</Style>
|
|
||||||
</UserControl.Styles>
|
|
||||||
|
|
||||||
<Grid RowDefinitions="Auto,Auto">
|
<Grid RowDefinitions="Auto,Auto">
|
||||||
<Border Grid.Row="0" Classes="card" Margin="0 0 0 10">
|
<Border Grid.Row="0" Classes="card" Margin="0 0 0 10">
|
||||||
<StackPanel>
|
<ContentControl Content="{CompiledBinding EntryReleaseInfoViewModel}"/>
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
|
||||||
<Button Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Classes="icon-button" Margin="0 0 5 0" Command="{CompiledBinding Close}">
|
|
||||||
<avalonia:MaterialIcon Kind="ArrowBack" />
|
|
||||||
</Button>
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="1" Theme="{StaticResource SubtitleTextBlockStyle}">Release info</TextBlock>
|
|
||||||
<StackPanel Grid.Column="2">
|
|
||||||
<!-- Install progress -->
|
|
||||||
<StackPanel Orientation="Horizontal"
|
|
||||||
Spacing="5"
|
|
||||||
IsVisible="{CompiledBinding InstallationInProgress}">
|
|
||||||
<ProgressBar VerticalAlignment="Center"
|
|
||||||
Width="300"
|
|
||||||
Value="{CompiledBinding InstallProgress, FallbackValue=0}">
|
|
||||||
</ProgressBar>
|
|
||||||
<Button
|
|
||||||
Classes="accent"
|
|
||||||
Margin="15 0 0 0"
|
|
||||||
Width="80"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Command="{CompiledBinding Cancel}">
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<!-- Install button -->
|
|
||||||
<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="*,*,*">
|
|
||||||
<Grid Grid.Column="0" ColumnDefinitions="*,*" RowDefinitions="*,*" Classes="info-container" HorizontalAlignment="Left">
|
|
||||||
<avalonia:MaterialIcon Kind="TickNetworkOutline" Grid.Column="0" Grid.RowSpan="2" Classes="info-icon" />
|
|
||||||
<TextBlock Grid.Column="1" Grid.Row="0" Classes="info-title">Version</TextBlock>
|
|
||||||
<TextBlock Grid.Column="1"
|
|
||||||
Grid.Row="1"
|
|
||||||
Classes="info-body"
|
|
||||||
Cursor="Hand"
|
|
||||||
Text="{CompiledBinding Release.Version}" />
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid Grid.Column="1" ColumnDefinitions="*,*" RowDefinitions="*,*,*" Classes="info-container" HorizontalAlignment="Center">
|
|
||||||
<avalonia:MaterialIcon Kind="Calendar" Grid.Column="0" Grid.RowSpan="2" Classes="info-icon" />
|
|
||||||
<TextBlock Grid.Column="1" Grid.Row="0" Classes="info-title">Release date</TextBlock>
|
|
||||||
<TextBlock Grid.Column="1"
|
|
||||||
Grid.Row="1"
|
|
||||||
Classes="info-body"
|
|
||||||
Text="{CompiledBinding Release.CreatedAt, Converter={StaticResource DateTimeConverter}}" />
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid Grid.Column="2" ColumnDefinitions="*,*" RowDefinitions="*,*" Classes="info-container" HorizontalAlignment="Right">
|
|
||||||
<avalonia:MaterialIcon Kind="File" Grid.Column="0" Grid.RowSpan="2" Classes="info-icon" />
|
|
||||||
<TextBlock Grid.Column="1" Grid.Row="0" Classes="info-title">File size</TextBlock>
|
|
||||||
<TextBlock Grid.Column="1"
|
|
||||||
Grid.Row="1"
|
|
||||||
Classes="info-body"
|
|
||||||
Text="{CompiledBinding Release.DownloadSize, Converter={StaticResource BytesToStringConverter}, Mode=OneWay}" />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Grid.Row="1" Classes="card">
|
<Border Grid.Row="1" Classes="card">
|
||||||
|
|||||||
@ -1,14 +1,9 @@
|
|||||||
using System;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Screens.Workshop.Parameters;
|
using Artemis.UI.Screens.Workshop.Parameters;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Artemis.UI.Shared.Services.Builders;
|
|
||||||
using Artemis.UI.Shared.Utilities;
|
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
using Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
|
|
||||||
using Artemis.WebClient.Workshop.Services;
|
|
||||||
using PropertyChanged.SourceGenerator;
|
using PropertyChanged.SourceGenerator;
|
||||||
using StrawberryShake;
|
using StrawberryShake;
|
||||||
|
|
||||||
@ -17,89 +12,27 @@ namespace Artemis.UI.Screens.Workshop.EntryReleases;
|
|||||||
public partial class EntryReleaseViewModel : RoutableScreen<ReleaseDetailParameters>
|
public partial class EntryReleaseViewModel : RoutableScreen<ReleaseDetailParameters>
|
||||||
{
|
{
|
||||||
private readonly IWorkshopClient _client;
|
private readonly IWorkshopClient _client;
|
||||||
private readonly IRouter _router;
|
|
||||||
private readonly INotificationService _notificationService;
|
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 IGetReleaseById_Release? _release;
|
||||||
[Notify] private float _installProgress;
|
|
||||||
[Notify] private bool _installationInProgress;
|
|
||||||
[Notify] private bool _isCurrentVersion;
|
|
||||||
|
|
||||||
private CancellationTokenSource? _cts;
|
public EntryReleaseViewModel(IWorkshopClient client, INotificationService notificationService, EntryReleaseInfoViewModel entryReleaseInfoViewModel)
|
||||||
|
|
||||||
public EntryReleaseViewModel(IWorkshopClient client, IRouter router, INotificationService notificationService, IWindowService windowService, IWorkshopService workshopService,
|
|
||||||
EntryInstallationHandlerFactory factory)
|
|
||||||
{
|
{
|
||||||
|
EntryReleaseInfoViewModel = entryReleaseInfoViewModel;
|
||||||
|
|
||||||
_client = client;
|
_client = client;
|
||||||
_router = router;
|
|
||||||
_notificationService = notificationService;
|
_notificationService = notificationService;
|
||||||
_windowService = windowService;
|
|
||||||
_workshopService = workshopService;
|
|
||||||
_factory = factory;
|
|
||||||
_progress.ProgressChanged += (_, f) => InstallProgress = f.ProgressPercentage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Close()
|
|
||||||
{
|
|
||||||
await _router.GoUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Install()
|
|
||||||
{
|
|
||||||
if (Release == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_cts = new CancellationTokenSource();
|
|
||||||
InstallProgress = 0;
|
|
||||||
InstallationInProgress = true;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IEntryInstallationHandler handler = _factory.CreateHandler(Release.Entry.EntryType);
|
|
||||||
EntryInstallResult result = await handler.InstallAsync(Release.Entry, Release, _progress, _cts.Token);
|
|
||||||
if (result.IsSuccess)
|
|
||||||
{
|
|
||||||
_notificationService.CreateNotification().WithTitle("Installation succeeded").WithSeverity(NotificationSeverity.Success).Show();
|
|
||||||
IsCurrentVersion = true;
|
|
||||||
InstallationInProgress = false;
|
|
||||||
await Manage();
|
|
||||||
}
|
|
||||||
else if (!_cts.IsCancellationRequested)
|
|
||||||
_notificationService.CreateNotification().WithTitle("Installation failed").WithMessage(result.Message).WithSeverity(NotificationSeverity.Error).Show();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
InstallationInProgress = false;
|
|
||||||
_windowService.ShowExceptionDialog("Failed to install workshop entry", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Manage()
|
|
||||||
{
|
|
||||||
if (Release?.Entry.EntryType != EntryType.Profile)
|
|
||||||
await _router.Navigate("../../manage");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Reinstall()
|
|
||||||
{
|
|
||||||
if (await _windowService.ShowConfirmContentDialog("Reinstall entry", "Are you sure you want to reinstall this entry?"))
|
|
||||||
await Install();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Cancel()
|
|
||||||
{
|
|
||||||
_cts?.Cancel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EntryReleaseInfoViewModel EntryReleaseInfoViewModel { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task OnNavigating(ReleaseDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
public override async Task OnNavigating(ReleaseDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
IOperationResult<IGetReleaseByIdResult> result = await _client.GetReleaseById.ExecuteAsync(parameters.ReleaseId, cancellationToken);
|
IOperationResult<IGetReleaseByIdResult> result = await _client.GetReleaseById.ExecuteAsync(parameters.ReleaseId, cancellationToken);
|
||||||
|
|
||||||
Release = result.Data?.Release;
|
Release = result.Data?.Release;
|
||||||
IsCurrentVersion = Release != null && _workshopService.GetInstalledEntry(Release.Entry.Id)?.ReleaseId == Release.Id;
|
EntryReleaseInfoViewModel.Release = Release;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Overrides of RoutableScreen
|
#region Overrides of RoutableScreen
|
||||||
@ -107,7 +40,7 @@ public partial class EntryReleaseViewModel : RoutableScreen<ReleaseDetailParamet
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Task OnClosing(NavigationArguments args)
|
public override Task OnClosing(NavigationArguments args)
|
||||||
{
|
{
|
||||||
if (!InstallationInProgress)
|
if (!EntryReleaseInfoViewModel.InstallationInProgress)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
|
|||||||
@ -8,6 +8,10 @@
|
|||||||
x:Class="Artemis.UI.Screens.Workshop.Layout.LayoutDescriptionView"
|
x:Class="Artemis.UI.Screens.Workshop.Layout.LayoutDescriptionView"
|
||||||
x:DataType="layout:LayoutDescriptionViewModel">
|
x:DataType="layout:LayoutDescriptionViewModel">
|
||||||
<StackPanel Spacing="10">
|
<StackPanel Spacing="10">
|
||||||
|
<Border Classes="card">
|
||||||
|
<ContentControl Content="{CompiledBinding ReleaseInfoViewModel}"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<Border Classes="card">
|
<Border Classes="card">
|
||||||
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
||||||
<mdxaml:MarkdownScrollViewer.Styles>
|
<mdxaml:MarkdownScrollViewer.Styles>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
using Artemis.UI.Screens.Workshop.EntryReleases;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
using PropertyChanged.SourceGenerator;
|
using PropertyChanged.SourceGenerator;
|
||||||
@ -7,4 +8,12 @@ namespace Artemis.UI.Screens.Workshop.Layout;
|
|||||||
public partial class LayoutDescriptionViewModel : RoutableScreen
|
public partial class LayoutDescriptionViewModel : RoutableScreen
|
||||||
{
|
{
|
||||||
[Notify] private IEntryDetails? _entry;
|
[Notify] private IEntryDetails? _entry;
|
||||||
|
|
||||||
|
public LayoutDescriptionViewModel(EntryReleaseInfoViewModel releaseInfoViewModel)
|
||||||
|
{
|
||||||
|
ReleaseInfoViewModel = releaseInfoViewModel;
|
||||||
|
ReleaseInfoViewModel.InDetailsScreen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntryReleaseInfoViewModel ReleaseInfoViewModel { get; }
|
||||||
}
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Reactive.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Screens.Workshop.Entries.Details;
|
using Artemis.UI.Screens.Workshop.Entries.Details;
|
||||||
@ -7,6 +8,7 @@ using Artemis.UI.Screens.Workshop.Parameters;
|
|||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
using PropertyChanged.SourceGenerator;
|
using PropertyChanged.SourceGenerator;
|
||||||
|
using ReactiveUI;
|
||||||
using StrawberryShake;
|
using StrawberryShake;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.Layout;
|
namespace Artemis.UI.Screens.Workshop.Layout;
|
||||||
@ -31,7 +33,7 @@ public partial class LayoutDetailsViewModel : RoutableHostScreen<RoutableScreen,
|
|||||||
_layoutDescriptionViewModel = layoutDescriptionViewModel;
|
_layoutDescriptionViewModel = layoutDescriptionViewModel;
|
||||||
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
_getEntryReleasesViewModel = getEntryReleasesViewModel;
|
||||||
_getEntryImagesViewModel = getEntryImagesViewModel;
|
_getEntryImagesViewModel = getEntryImagesViewModel;
|
||||||
|
|
||||||
RecycleScreen = false;
|
RecycleScreen = false;
|
||||||
EntryInfoViewModel = entryInfoViewModel;
|
EntryInfoViewModel = entryInfoViewModel;
|
||||||
}
|
}
|
||||||
@ -60,5 +62,6 @@ public partial class LayoutDetailsViewModel : RoutableHostScreen<RoutableScreen,
|
|||||||
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
EntryReleasesViewModel = Entry != null ? _getEntryReleasesViewModel(Entry) : null;
|
||||||
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
||||||
_layoutDescriptionViewModel.Entry = Entry;
|
_layoutDescriptionViewModel.Entry = Entry;
|
||||||
|
_layoutDescriptionViewModel.ReleaseInfoViewModel.Release = result.Data?.Entry?.LatestRelease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8,6 +8,10 @@
|
|||||||
x:Class="Artemis.UI.Screens.Workshop.Plugins.PluginDescriptionView"
|
x:Class="Artemis.UI.Screens.Workshop.Plugins.PluginDescriptionView"
|
||||||
x:DataType="plugins:PluginDescriptionViewModel">
|
x:DataType="plugins:PluginDescriptionViewModel">
|
||||||
<StackPanel Spacing="10">
|
<StackPanel Spacing="10">
|
||||||
|
<Border Classes="card">
|
||||||
|
<ContentControl Content="{CompiledBinding ReleaseInfoViewModel}"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<Border Classes="card">
|
<Border Classes="card">
|
||||||
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
|
||||||
<mdxaml:MarkdownScrollViewer.Styles>
|
<mdxaml:MarkdownScrollViewer.Styles>
|
||||||
|
|||||||
@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Screens.Workshop.Entries.List;
|
using Artemis.UI.Screens.Workshop.Entries.List;
|
||||||
|
using Artemis.UI.Screens.Workshop.EntryReleases;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
using PropertyChanged.SourceGenerator;
|
using PropertyChanged.SourceGenerator;
|
||||||
@ -18,12 +19,16 @@ public partial class PluginDescriptionViewModel : RoutableScreen
|
|||||||
private readonly IWorkshopClient _client;
|
private readonly IWorkshopClient _client;
|
||||||
private readonly Func<IEntrySummary, EntryListItemViewModel> _getEntryListViewModel;
|
private readonly Func<IEntrySummary, EntryListItemViewModel> _getEntryListViewModel;
|
||||||
|
|
||||||
public PluginDescriptionViewModel(IWorkshopClient client, Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
public PluginDescriptionViewModel(IWorkshopClient client, EntryReleaseInfoViewModel releaseInfoViewModel, Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_getEntryListViewModel = getEntryListViewModel;
|
_getEntryListViewModel = getEntryListViewModel;
|
||||||
|
ReleaseInfoViewModel = releaseInfoViewModel;
|
||||||
|
ReleaseInfoViewModel.InDetailsScreen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EntryReleaseInfoViewModel ReleaseInfoViewModel { get; }
|
||||||
|
|
||||||
public async Task SetEntry(IEntryDetails? entry, CancellationToken cancellationToken)
|
public async Task SetEntry(IEntryDetails? entry, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Entry = entry;
|
Entry = entry;
|
||||||
|
|||||||
@ -64,5 +64,6 @@ public partial class PluginDetailsViewModel : RoutableHostScreen<RoutableScreen,
|
|||||||
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
||||||
|
|
||||||
await _pluginDescriptionViewModel.SetEntry(Entry, cancellationToken);
|
await _pluginDescriptionViewModel.SetEntry(Entry, cancellationToken);
|
||||||
|
_pluginDescriptionViewModel.ReleaseInfoViewModel.Release = result.Data?.Entry?.LatestRelease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,5 +73,11 @@ public partial class PluginManageViewModel : RoutableScreen<WorkshopDetailParame
|
|||||||
|
|
||||||
PluginViewModel = _settingsVmFactory.PluginViewModel(plugin, ReactiveCommand.Create(() => { }));
|
PluginViewModel = _settingsVmFactory.PluginViewModel(plugin, ReactiveCommand.Create(() => { }));
|
||||||
PluginFeatures = new ObservableCollection<PluginFeatureViewModel>(plugin.Features.Select(f => _settingsVmFactory.PluginFeatureViewModel(f, false)));
|
PluginFeatures = new ObservableCollection<PluginFeatureViewModel>(plugin.Features.Select(f => _settingsVmFactory.PluginFeatureViewModel(f, false)));
|
||||||
|
|
||||||
|
// If additional arguments were provided and it is a boolean, auto-enable the plugin
|
||||||
|
if (args.Options.AdditionalArguments is true)
|
||||||
|
{
|
||||||
|
await PluginViewModel.AutoEnable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8,6 +8,10 @@
|
|||||||
x:Class="Artemis.UI.Screens.Workshop.Profile.ProfileDescriptionView"
|
x:Class="Artemis.UI.Screens.Workshop.Profile.ProfileDescriptionView"
|
||||||
x:DataType="profile:ProfileDescriptionViewModel">
|
x:DataType="profile:ProfileDescriptionViewModel">
|
||||||
<StackPanel Spacing="10">
|
<StackPanel Spacing="10">
|
||||||
|
<Border Classes="card">
|
||||||
|
<ContentControl Content="{CompiledBinding ReleaseInfoViewModel}"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<Border Classes="card">
|
<Border Classes="card">
|
||||||
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia" Name="MarkdownScrollViewer" >
|
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia" Name="MarkdownScrollViewer" >
|
||||||
<mdxaml:MarkdownScrollViewer.Styles>
|
<mdxaml:MarkdownScrollViewer.Styles>
|
||||||
|
|||||||
@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Screens.Workshop.Entries.List;
|
using Artemis.UI.Screens.Workshop.Entries.List;
|
||||||
|
using Artemis.UI.Screens.Workshop.EntryReleases;
|
||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.WebClient.Workshop;
|
using Artemis.WebClient.Workshop;
|
||||||
using PropertyChanged.SourceGenerator;
|
using PropertyChanged.SourceGenerator;
|
||||||
@ -18,12 +19,16 @@ public partial class ProfileDescriptionViewModel : RoutableScreen
|
|||||||
[Notify] private IEntryDetails? _entry;
|
[Notify] private IEntryDetails? _entry;
|
||||||
[Notify] private List<EntryListItemViewModel>? _dependencies;
|
[Notify] private List<EntryListItemViewModel>? _dependencies;
|
||||||
|
|
||||||
public ProfileDescriptionViewModel(IWorkshopClient client, Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
public ProfileDescriptionViewModel(IWorkshopClient client, EntryReleaseInfoViewModel releaseInfoViewModel, Func<IEntrySummary, EntryListItemViewModel> getEntryListViewModel)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
_getEntryListViewModel = getEntryListViewModel;
|
_getEntryListViewModel = getEntryListViewModel;
|
||||||
|
ReleaseInfoViewModel = releaseInfoViewModel;
|
||||||
|
ReleaseInfoViewModel.InDetailsScreen = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EntryReleaseInfoViewModel ReleaseInfoViewModel { get; }
|
||||||
|
|
||||||
public async Task SetEntry(IEntryDetails? entry, CancellationToken cancellationToken)
|
public async Task SetEntry(IEntryDetails? entry, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
Entry = entry;
|
Entry = entry;
|
||||||
|
|||||||
@ -65,5 +65,6 @@ public partial class ProfileDetailsViewModel : RoutableHostScreen<RoutableScreen
|
|||||||
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
EntryImagesViewModel = Entry != null ? _getEntryImagesViewModel(Entry) : null;
|
||||||
|
|
||||||
await _profileDescriptionViewModel.SetEntry(Entry, cancellationToken);
|
await _profileDescriptionViewModel.SetEntry(Entry, cancellationToken);
|
||||||
|
_profileDescriptionViewModel.ReleaseInfoViewModel.Release = result.Data?.Entry?.LatestRelease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,6 +70,17 @@ fragment release on Release {
|
|||||||
createdAt
|
createdAt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fragment releaseDetails on Release {
|
||||||
|
...release
|
||||||
|
changelog
|
||||||
|
entry {
|
||||||
|
...entrySummary
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
...entrySummary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fragment pluginInfo on PluginInfo {
|
fragment pluginInfo on PluginInfo {
|
||||||
requiresAdmin
|
requiresAdmin
|
||||||
supportsWindows
|
supportsWindows
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
query GetEntryById($id: Long!) {
|
query GetEntryById($id: Long!) {
|
||||||
entry(id: $id) {
|
entry(id: $id) {
|
||||||
...entryDetails
|
...entryDetails
|
||||||
|
latestRelease {
|
||||||
|
...releaseDetails
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9,7 +12,10 @@ query GetPluginEntryById($id: Long!) {
|
|||||||
...entryDetails
|
...entryDetails
|
||||||
pluginInfo {
|
pluginInfo {
|
||||||
...pluginInfo
|
...pluginInfo
|
||||||
}
|
}
|
||||||
|
latestRelease {
|
||||||
|
...releaseDetails
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
query GetReleaseById($id: Long!) {
|
query GetReleaseById($id: Long!) {
|
||||||
release(id: $id) {
|
release(id: $id) {
|
||||||
...release
|
...releaseDetails
|
||||||
changelog
|
|
||||||
entry {
|
|
||||||
...entrySummary
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user