1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-12 13:28:33 +00:00

Workshop - Fix library virtualization

Workshop - Tweak screenshots scaling
This commit is contained in:
Robert 2024-01-14 20:38:17 +01:00
parent 28edabae89
commit 8b4b5d8810
13 changed files with 92 additions and 37 deletions

View File

@ -14,7 +14,7 @@
<TextBlock Text="Current layout" />
<TextBlock Classes="subtitle" FontSize="12" Text="Loading the layout from a workshop entry" TextWrapping="Wrap" />
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center">
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Spacing="5">
<StackPanel.Styles>
<Style Selector="ComboBox.layoutProvider /template/ ContentControl#ContentPresenter">
<Setter Property="ContentTemplate">
@ -40,6 +40,7 @@
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button HorizontalAlignment="Right" Click="Button_OnClick">Browse workshop layouts</Button>
</StackPanel>
</Grid>
</StackPanel>

View File

@ -1,4 +1,6 @@
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
@ -9,4 +11,10 @@ public partial class WorkshopLayoutView : ReactiveUserControl<WorkshopLayoutView
{
InitializeComponent();
}
private async void Button_OnClick(object? sender, RoutedEventArgs e)
{
if (ViewModel != null && await ViewModel.BrowseLayouts())
(VisualRoot as Window)?.Close();
}
}

View File

@ -2,10 +2,13 @@
using System;
using System.Linq;
using System.Reactive.Disposables;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Providers;
using Artemis.Core.Services;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
using Artemis.WebClient.Workshop;
using Artemis.WebClient.Workshop.Providers;
using Artemis.WebClient.Workshop.Services;
@ -19,11 +22,16 @@ public partial class WorkshopLayoutViewModel : ActivatableViewModelBase, ILayout
[Notify] private InstalledEntry? _selectedEntry;
private readonly WorkshopLayoutProvider _layoutProvider;
private readonly IDeviceService _deviceService;
private readonly IWindowService _windowService;
private readonly IRouter _router;
public WorkshopLayoutViewModel(WorkshopLayoutProvider layoutProvider, IWorkshopService workshopService, IDeviceService deviceService)
public WorkshopLayoutViewModel(WorkshopLayoutProvider layoutProvider, IWorkshopService workshopService, IDeviceService deviceService, IWindowService windowService, IRouter router)
{
_layoutProvider = layoutProvider;
_deviceService = deviceService;
_windowService = windowService;
_router = router;
Entries = new ObservableCollection<InstalledEntry>(workshopService.GetInstalledEntries().Where(e => e.EntryType == EntryType.Layout));
this.WhenAnyValue(vm => vm.SelectedEntry).Subscribe(ApplyEntry);
@ -50,6 +58,15 @@ public partial class WorkshopLayoutViewModel : ActivatableViewModelBase, ILayout
Save();
}
public async Task<bool> BrowseLayouts()
{
if (!await _windowService.ShowConfirmContentDialog("Open workshop", "Do you want to close this window and view the workshop?"))
return false;
await _router.Navigate("workshop/entries/layouts/1");
return true;
}
private void ApplyEntry(InstalledEntry? entry)
{
if (entry == null || Device.LayoutSelection.Parameter == entry.EntryId.ToString())

View File

@ -8,13 +8,9 @@
x:Class="Artemis.UI.Screens.Workshop.Entries.Details.EntryImageView"
x:DataType="details:EntryImageViewModel">
<Border Classes="card" Padding="0">
<Grid RowDefinitions="230,*">
<Grid RowDefinitions="Auto,*">
<Border Grid.Row="0" ClipToBounds="True" CornerRadius="4 4 0 0" Padding="0">
<Rectangle RenderOptions.BitmapInterpolationMode="HighQuality">
<Rectangle.Fill>
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{CompiledBinding ThumbnailUrl}" Stretch="UniformToFill" />
</Rectangle.Fill>
</Rectangle>
<Image asyncImageLoader:ImageLoader.Source="{CompiledBinding ThumbnailUrl}" Stretch="Uniform" HorizontalAlignment="Stretch" MaxHeight="250" />
</Border>
<Border Grid.Row="1" ClipToBounds="True" CornerRadius="0 0 4 4" Background="{DynamicResource ControlFillColorDefaultBrush}">
<StackPanel Margin="16">

View File

@ -8,5 +8,5 @@
x:Class="Artemis.UI.Screens.Workshop.Entries.Details.EntryImagesDialogView"
x:DataType="details:EntryImagesDialogViewModel"
Margin="-25 -63 -25 -25">
<Image asyncImageLoader:ImageLoader.Source="{CompiledBinding CurrentImage.Url}" Stretch="None"/>
<Image asyncImageLoader:ImageLoader.Source="{CompiledBinding CurrentImage.Url}" Stretch="Uniform"/>
</UserControl>

View File

@ -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 Humanizer;
using ReactiveUI;
@ -32,6 +33,8 @@ public class EntryReleasesViewModel : ViewModelBase
public IGetEntryById_Entry Entry { get; }
public ReactiveCommand<Unit, Unit> DownloadLatestRelease { get; }
public Func<InstalledEntry, Task>? OnInstallationFinished { get; set; }
private async Task ExecuteDownloadLatestRelease(CancellationToken cancellationToken)
{
if (Entry.LatestRelease == null)
@ -46,8 +49,12 @@ public class EntryReleasesViewModel : ViewModelBase
IEntryInstallationHandler installationHandler = _factory.CreateHandler(Entry.EntryType);
EntryInstallResult result = await installationHandler.InstallAsync(Entry, Entry.LatestRelease, new Progress<StreamProgress>(), cancellationToken);
if (result.IsSuccess)
if (result.IsSuccess && result.Entry != null)
{
if (OnInstallationFinished != null)
await OnInstallationFinished(result.Entry);
_notificationService.CreateNotification().WithTitle($"{Entry.EntryType.Humanize(LetterCasing.Sentence)} installed").WithSeverity(NotificationSeverity.Success).Show();
}
else
{
_notificationService.CreateNotification()

View File

@ -8,7 +8,7 @@
x:Class="Artemis.UI.Screens.Workshop.Layout.LayoutDetailsView"
x:DataType="layout:LayoutDetailsViewModel">
<Grid ColumnDefinitions="300,*, 300" RowDefinitions="Auto,*">
<StackPanel Grid.Row="1" Grid.Column="0" Margin="0 0 10 0" Spacing="10">
<StackPanel Grid.Row="1" Grid.Column="0" Spacing="10">
<Border Classes="card" VerticalAlignment="Top">
<ContentControl Content="{CompiledBinding EntryInfoViewModel}" />
</Border>
@ -17,7 +17,7 @@
</Border>
</StackPanel>
<Border Classes="card" Grid.Row="1" Grid.Column="1">
<Border Classes="card" Grid.Row="1" Grid.Column="1" Margin="10 0">
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Entry.Description}" MarkdownStyleName="FluentAvalonia">
<mdxaml:MarkdownScrollViewer.Styles>
<StyleInclude Source="/Styles/Markdown.axaml" />
@ -25,8 +25,6 @@
</mdxaml:MarkdownScrollViewer>
</Border>
<StackPanel Grid.Row="1" Grid.Column="2" IsVisible="{CompiledBinding Entry.Images.Count}">
<ContentControl Content="{CompiledBinding EntryImagesViewModel}" />
</StackPanel>
<ContentControl Grid.Row="1" Grid.Column="2" IsVisible="{CompiledBinding Entry.Images.Count}" Content="{CompiledBinding EntryImagesViewModel}" />
</Grid>
</UserControl>

View File

@ -1,10 +1,12 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Artemis.Core.Services;
using Artemis.UI.Screens.Workshop.Entries.Details;
using Artemis.UI.Screens.Workshop.Parameters;
using Artemis.UI.Shared.Routing;
using Artemis.WebClient.Workshop;
using Artemis.WebClient.Workshop.Services;
using PropertyChanged.SourceGenerator;
using StrawberryShake;
@ -13,6 +15,7 @@ namespace Artemis.UI.Screens.Workshop.Layout;
public partial class LayoutDetailsViewModel : RoutableScreen<WorkshopDetailParameters>
{
private readonly IWorkshopClient _client;
private readonly IDeviceService _deviceService;
private readonly Func<IGetEntryById_Entry, EntryInfoViewModel> _getEntryInfoViewModel;
private readonly Func<IGetEntryById_Entry, EntryReleasesViewModel> _getEntryReleasesViewModel;
private readonly Func<IGetEntryById_Entry, EntryImagesViewModel> _getEntryImagesViewModel;
@ -22,11 +25,13 @@ public partial class LayoutDetailsViewModel : RoutableScreen<WorkshopDetailParam
[Notify] private EntryImagesViewModel? _entryImagesViewModel;
public LayoutDetailsViewModel(IWorkshopClient client,
IDeviceService deviceService,
Func<IGetEntryById_Entry, EntryInfoViewModel> getEntryInfoViewModel,
Func<IGetEntryById_Entry, EntryReleasesViewModel> getEntryReleasesViewModel,
Func<IGetEntryById_Entry, EntryImagesViewModel> getEntryImagesViewModel)
{
_client = client;
_deviceService = deviceService;
_getEntryInfoViewModel = getEntryInfoViewModel;
_getEntryReleasesViewModel = getEntryReleasesViewModel;
_getEntryImagesViewModel = getEntryImagesViewModel;
@ -54,6 +59,17 @@ public partial class LayoutDetailsViewModel : RoutableScreen<WorkshopDetailParam
EntryInfoViewModel = _getEntryInfoViewModel(Entry);
EntryReleasesViewModel = _getEntryReleasesViewModel(Entry);
EntryImagesViewModel = _getEntryImagesViewModel(Entry);
EntryReleasesViewModel.OnInstallationFinished = OnInstallationFinished;
}
}
private Task OnInstallationFinished(InstalledEntry installedEntry)
{
// Find compatible devices
// If any are found, offer to apply
return Task.CompletedTask;
}
}

View File

@ -26,13 +26,18 @@
</StackPanel>
<ScrollViewer IsVisible="{CompiledBinding !Empty}">
<ItemsRepeater ItemsSource="{CompiledBinding InstalledEntries}">
<ItemsRepeater.ItemTemplate>
<ItemsControl ItemsSource="{CompiledBinding InstalledEntries}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{CompiledBinding}"/>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Panel>

View File

@ -37,13 +37,18 @@
</StackPanel>
<ScrollViewer IsVisible="{CompiledBinding Entries.Count}">
<ItemsRepeater ItemsSource="{CompiledBinding Entries}">
<ItemsRepeater.ItemTemplate>
<ItemsControl ItemsSource="{CompiledBinding Entries}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{CompiledBinding}"/>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Panel>
</Panel>

View File

@ -1,10 +1,12 @@
namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
using Artemis.WebClient.Workshop.Services;
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 InstalledEntry? Entry { get; set; }
public static EntryInstallResult FromFailure(string? message)
{
@ -15,12 +17,12 @@ public class EntryInstallResult
};
}
public static EntryInstallResult FromSuccess(object installationResult)
public static EntryInstallResult FromSuccess(InstalledEntry installedEntry)
{
return new EntryInstallResult
{
IsSuccess = true,
Result = installationResult
Entry = installedEntry
};
}
}

View File

@ -41,28 +41,28 @@ public class LayoutEntryInstallationHandler : IEntryInstallationHandler
// Ensure there is an installed entry
InstalledEntry installedEntry = _workshopService.GetInstalledEntry(entry) ?? new InstalledEntry(entry, release);
DirectoryInfo entryDirectory = installedEntry.GetReleaseDirectory(release);
DirectoryInfo releaseDirectory = installedEntry.GetReleaseDirectory(release);
// If the folder already exists, remove it so that if the layout now contains less files, old things dont stick around
if (entryDirectory.Exists)
entryDirectory.Delete(true);
entryDirectory.Create();
if (releaseDirectory.Exists)
releaseDirectory.Delete(true);
releaseDirectory.Create();
// Extract the archive, we could go through the hoops of keeping track of progress but this should be so quick it doesn't matter
stream.Seek(0, SeekOrigin.Begin);
using ZipArchive archive = new(stream);
archive.ExtractToDirectory(entryDirectory.FullName);
archive.ExtractToDirectory(releaseDirectory.FullName);
ArtemisLayout layout = new(Path.Combine(entryDirectory.FullName, "layout.xml"));
ArtemisLayout layout = new(Path.Combine(releaseDirectory.FullName, "layout.xml"));
if (layout.IsValid)
{
installedEntry.ApplyRelease(release);
_workshopService.SaveInstalledEntry(installedEntry);
return EntryInstallResult.FromSuccess(layout);
return EntryInstallResult.FromSuccess(installedEntry);
}
// If the layout ended up being invalid yoink it out again, shoooo
entryDirectory.Delete(true);
releaseDirectory.Delete(true);
_workshopService.RemoveInstalledEntry(installedEntry);
return EntryInstallResult.FromFailure("Layout failed to load because it is invalid");
}

View File

@ -46,7 +46,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
// Update the release and return the profile configuration
UpdateRelease(installedEntry, release);
return EntryInstallResult.FromSuccess(overwritten);
return EntryInstallResult.FromSuccess(installedEntry);
}
}
@ -60,7 +60,7 @@ public class ProfileEntryInstallationHandler : IEntryInstallationHandler
// Update the release and return the profile configuration
UpdateRelease(installedEntry, release);
return EntryInstallResult.FromSuccess(imported);
return EntryInstallResult.FromSuccess(installedEntry);
}
public async Task<EntryUninstallResult> UninstallAsync(InstalledEntry installedEntry, CancellationToken cancellationToken)