Added layout archive generation

This commit is contained in:
RobertBeekman committed 2023-11-02 22:29:42 +01:00
1 parent 59fe1df40f
commit 6b4e84c95a
18 files changed
+224 -68

No files matched your search

@@ -14,6 +14,7 @@ namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
public class ImagesStepViewModel : SubmissionViewModel
{
private const long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
private readonly IWindowService _windowService;
private readonly SourceList<Stream> _imageStreams;
@@ -60,7 +61,14 @@ public class ImagesStepViewModel : SubmissionViewModel
if (_imageStreams.Items.Any(i => i is FileStream fs && fs.Name == path))
continue;
FileStream stream = new(path, FileMode.Open);
FileStream stream = new(path, FileMode.Open, FileAccess.Read);
if (stream.Length > MAX_FILE_SIZE)
{
await _windowService.ShowConfirmContentDialog("File too big", $"File {path} exceeds maximum file size of 10 MB", "Skip file", null);
await stream.DisposeAsync();
continue;
}
_imageStreams.Add(stream);
State.Images.Add(stream);
}
@@ -85,40 +85,15 @@ public partial class LayoutInfoStepViewModel : SubmissionViewModel
return;
layoutEntrySource.PhysicalLayout = PhysicalLayout;
// layoutEntrySource.LayoutInfo = new List<LayoutInfo>(LayoutInfo.Select(i => i.ToLayoutInfo()));
layoutEntrySource.LayoutInfo = new List<LayoutInfo>(LayoutInfo.Select(i => i.ToLayoutInfo()));
if (string.IsNullOrWhiteSpace(State.Name))
State.Name = layoutEntrySource.Layout.RgbLayout.Name ?? "";
if (string.IsNullOrWhiteSpace(State.Summary))
{
State.Summary = !string.IsNullOrWhiteSpace(layoutEntrySource.Layout.RgbLayout.Vendor)
? $"{layoutEntrySource.Layout.RgbLayout.Vendor} {layoutEntrySource.Layout.RgbLayout.Type} device layout"
: $"{layoutEntrySource.Layout.RgbLayout.Type} device layout";
}
if (string.IsNullOrWhiteSpace(State.Description))
{
State.Description = $@"### Layout properties
**Name**
{layoutEntrySource.Layout.RgbLayout.Name ?? "N/A"}
**Description**
{layoutEntrySource.Layout.RgbLayout.Description ?? "N/A"}
**Author**
{layoutEntrySource.Layout.RgbLayout.Author ?? "N/A"}
**Type**
{layoutEntrySource.Layout.RgbLayout.Type}
**Vendor**
{layoutEntrySource.Layout.RgbLayout.Vendor ?? "N/A"}
**Model**
{layoutEntrySource.Layout.RgbLayout.Model ?? "N/A"}
**Shape**
{layoutEntrySource.Layout.RgbLayout.Shape}
**Width**
{layoutEntrySource.Layout.RgbLayout.Width}mm
**Height**
{layoutEntrySource.Layout.RgbLayout.Height}mm";
}
State.Categories = new List<long> {8}; // Device category, yes this could change but why would it
if (State.EntryId == null)
State.ChangeScreen<SpecificationsStepViewModel>();
@@ -9,6 +9,7 @@ using System.IO;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Artemis.UI.Exceptions;
using Artemis.UI.Screens.Workshop.SubmissionWizard.Models;
using Artemis.UI.Shared.Extensions;
using Artemis.UI.Shared.Services;
@@ -60,15 +61,23 @@ public partial class LayoutSelectionStepViewModel : SubmissionViewModel
if (selected == null || selected.Length != 1)
return;
ArtemisLayout layout = new(selected[0], LayoutSource.User);
if (!layout.IsValid)
try
{
await _windowService.ShowConfirmContentDialog("Invalid layout file", "The selected file does not appear to be a valid RGB.NET layout file", cancel: null);
return;
}
ArtemisLayout layout = new(selected[0], LayoutSource.User);
if (!layout.IsValid)
{
await _windowService.ShowConfirmContentDialog("Failed to load layout", "The selected file does not appear to be a valid RGB.NET layout file.", "Close", null);
return;
}
SelectedDevice = null;
Layout = layout;
SelectedDevice = null;
Layout = layout;
}
catch (Exception e)
{
await _windowService.ShowConfirmContentDialog("Failed to load layout", "The selected file does not appear to be a valid RGB.NET layout file.\r\n" + e.Message, "Close", null);
throw;
}
}
private void CreatePreviewDevice(ArtemisLayout? layout)
@@ -87,25 +96,69 @@ public partial class LayoutSelectionStepViewModel : SubmissionViewModel
{
if (Layout == null)
return;
if (!await ValidateLayout(Layout))
return;
State.EntrySource = new LayoutEntrySource(Layout);
await Dispatcher.UIThread.InvokeAsync(SetDeviceImages, DispatcherPriority.Background);
State.ChangeScreen<LayoutInfoStepViewModel>();
}
private async Task<bool> ValidateLayout(ArtemisLayout? layout)
{
if (layout == null)
return true;
string? layoutPath = Path.GetDirectoryName(layout.FilePath);
if (layoutPath == null)
throw new ArtemisUIException($"Could not determine directory of {layout.FilePath}");
if (layout.LayoutCustomDeviceData.DeviceImage != null && !File.Exists(Path.Combine(layoutPath, layout.LayoutCustomDeviceData.DeviceImage)))
{
await _windowService.ShowConfirmContentDialog(
"Device image not found",
$"{Path.Combine(layoutPath, layout.LayoutCustomDeviceData.DeviceImage)} does not exist.",
"Close",
null
);
return false;
}
foreach (ArtemisLedLayout ledLayout in layout.Leds)
{
if (ledLayout.LayoutCustomLedData.LogicalLayouts == null)
continue;
foreach (LayoutCustomLedDataLogicalLayout customData in ledLayout.LayoutCustomLedData.LogicalLayouts)
{
if (customData.Image == null || File.Exists(Path.Combine(layoutPath, customData.Image)))
continue;
await _windowService.ShowConfirmContentDialog(
$"Image not found for LED {ledLayout.RgbLayout.Id} ({customData.Name})",
$"{Path.Combine(layoutPath, customData.Image)} does not exist.",
"Close",
null
);
return false;
}
}
return true;
}
private void SetDeviceImages()
{
if (Layout == null)
return;
MemoryStream deviceWithoutLeds = new();
MemoryStream deviceWithLeds = new();
using (RenderTargetBitmap image = Layout.RenderLayout(false))
{
image.Save(deviceWithoutLeds);
deviceWithoutLeds.Seek(0, SeekOrigin.Begin);
}
using (RenderTargetBitmap image = Layout.RenderLayout(true))
{
image.Save(deviceWithLeds);
@@ -116,7 +169,7 @@ public partial class LayoutSelectionStepViewModel : SubmissionViewModel
foreach (Stream stateImage in State.Images)
stateImage.Dispose();
State.Images.Clear();
// Go through the hassle of resizing the image to 128x128 without losing aspect ratio, padding is added for this
State.Icon = ResizeImage(deviceWithoutLeds, 128);
State.Images.Add(deviceWithoutLeds);
@@ -126,11 +179,11 @@ public partial class LayoutSelectionStepViewModel : SubmissionViewModel
private Stream ResizeImage(Stream image, int size)
{
MemoryStream output = new();
using MemoryStream input = new();
using MemoryStream input = new();
image.CopyTo(input);
input.Seek(0, SeekOrigin.Begin);
using SKBitmap? sourceBitmap = SKBitmap.Decode(input);
int sourceWidth = sourceBitmap.Width;
int sourceHeight = sourceBitmap.Height;
@@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
@@ -131,12 +132,34 @@ public partial class UploadStepViewModel : SubmissionViewModel
State.ChangeScreen<SubmitStepViewModel>();
return null;
}
foreach (Stream image in State.Images.ToList())
{
// Upload image
try
{
ImageUploadResult imageUploadResult = await _workshopService.UploadEntryImage(entryId.Value, _progress, image, cancellationToken);
if (!imageUploadResult.IsSuccess)
throw new ArtemisWorkshopException(imageUploadResult.Message);
State.Images.Remove(image);
}
catch (Exception e)
{
// It's not critical if this fails
await _windowService.ShowConfirmContentDialog("Failed to upload image", "Your submission will continue, you can try upload a new image afterwards\r\n" + e.Message, "Continue", null);
}
if (cancellationToken.IsCancellationRequested)
{
State.ChangeScreen<SubmitStepViewModel>();
return null;
}
}
if (State.Icon == null)
return entryId;
// Upload image
// Upload icon
try
{
ImageUploadResult imageUploadResult = await _workshopService.SetEntryIcon(entryId.Value, _progress, State.Icon, cancellationToken);
@@ -146,12 +169,7 @@ public partial class UploadStepViewModel : SubmissionViewModel
catch (Exception e)
{
// It's not critical if this fails
await _windowService.ShowConfirmContentDialog(
"Failed to upload icon",
"Your submission will continue, you can try upload a new image afterwards\r\n" + e.Message,
"Continue",
null
);
await _windowService.ShowConfirmContentDialog("Failed to upload icon", "Your submission will continue, you can try upload a new image afterwards\r\n" + e.Message, "Continue", null);
}
return entryId;