mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Images WIP
This commit is contained in:
1 parent
6b4e84c95a
commit
0667d58ed8
56 files changed
+783
-454
No files matched your search
@@ -15,7 +15,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||
<PackageReference Include="ReactiveUI" Version="19.5.1" />
|
||||
<PackageReference Include="StrawberryShake.Server" Version="13.6.0-preview.31" />
|
||||
<PackageReference Include="StrawberryShake.Server" Version="13.7.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
|
||||
<PackageReference Include="System.Reactive" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
+1
@@ -16,6 +16,7 @@ public class EntryInstallationHandlerFactory
|
||||
return entryType switch
|
||||
{
|
||||
EntryType.Profile => _container.Resolve<ProfileEntryInstallationHandler>(),
|
||||
EntryType.Layout => _container.Resolve<LayoutEntryInstallationHandler>(),
|
||||
_ => throw new NotSupportedException($"EntryType '{entryType}' is not supported.")
|
||||
};
|
||||
}
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
using Artemis.UI.Shared.Extensions;
|
||||
using Artemis.UI.Shared.Utilities;
|
||||
using Artemis.WebClient.Workshop.Services;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
|
||||
|
||||
public class LayoutEntryInstallationHandler : IEntryInstallationHandler
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IWorkshopService _workshopService;
|
||||
|
||||
public LayoutEntryInstallationHandler(IHttpClientFactory httpClientFactory, IWorkshopService workshopService)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_workshopService = workshopService;
|
||||
}
|
||||
|
||||
public async Task<EntryInstallResult> InstallAsync(IGetEntryById_Entry entry, long releaseId, Progress<StreamProgress> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
using MemoryStream stream = new();
|
||||
|
||||
// Download the provided release
|
||||
try
|
||||
{
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME);
|
||||
await client.DownloadDataAsync($"releases/download/{releaseId}", stream, progress, cancellationToken);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return EntryInstallResult.FromFailure(e.Message);
|
||||
}
|
||||
|
||||
// return EntryInstallResult.FromSuccess();
|
||||
}
|
||||
|
||||
public async Task<EntryUninstallResult> UninstallAsync(InstalledEntry installedEntry, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
if (!Guid.TryParse(installedEntry.LocalReference, out Guid profileId))
|
||||
return EntryUninstallResult.FromFailure("Local reference does not contain a GUID");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||
|
||||
public class ImageUploadRequest
|
||||
{
|
||||
public ImageUploadRequest(Stream file, string name, string? description)
|
||||
{
|
||||
File = file;
|
||||
Name = name.Length > 50 ? name.Substring(0, 50) : name;
|
||||
if (description != null)
|
||||
Description = description.Length > 150 ? description.Substring(0, 150) : description;
|
||||
}
|
||||
|
||||
public Stream File { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
+29
-6
@@ -1,13 +1,23 @@
|
||||
using System.IO.Compression;
|
||||
using System.Net.Http.Headers;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared.Utilities;
|
||||
using Artemis.WebClient.Workshop.Entities;
|
||||
using Artemis.WebClient.Workshop.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
using RGB.NET.Layout;
|
||||
|
||||
namespace Artemis.WebClient.Workshop.Handlers.UploadHandlers;
|
||||
|
||||
public class LayoutEntryUploadHandler : IEntryUploadHandler
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public LayoutEntryUploadHandler(IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<EntryUploadResult> CreateReleaseAsync(long entryId, IEntrySource entrySource, Progress<StreamProgress> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -46,15 +56,28 @@ public class LayoutEntryUploadHandler : IEntryUploadHandler
|
||||
}
|
||||
|
||||
archiveStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
string filePath = Path.Combine(desktopPath, "layout-test.zip");
|
||||
await using (FileStream fileStream = new(filePath, FileMode.Create, FileAccess.Write))
|
||||
await using (FileStream fileStream = new(@"C:\Users\Robert\Desktop\layout-test.zip", FileMode.OpenOrCreate))
|
||||
{
|
||||
archiveStream.WriteTo(fileStream);
|
||||
await archiveStream.CopyToAsync(fileStream, cancellationToken);
|
||||
}
|
||||
archiveStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Submit the archive
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME);
|
||||
|
||||
return new EntryUploadResult();
|
||||
// Construct the request
|
||||
MultipartFormDataContent content = new();
|
||||
ProgressableStreamContent streamContent = new(archiveStream, progress);
|
||||
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
|
||||
content.Add(streamContent, "file", "file.zip");
|
||||
|
||||
// Submit
|
||||
HttpResponseMessage response = await client.PostAsync("releases/upload/" + entryId, content, cancellationToken);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
return EntryUploadResult.FromFailure($"{response.StatusCode} - {await response.Content.ReadAsStringAsync(cancellationToken)}");
|
||||
|
||||
Release? release = JsonConvert.DeserializeObject<Release>(await response.Content.ReadAsStringAsync(cancellationToken));
|
||||
return release != null ? EntryUploadResult.FromSuccess(release) : EntryUploadResult.FromFailure("Failed to deserialize response");
|
||||
}
|
||||
|
||||
private static void CopyImage(string layoutPath, string? imagePath, ZipArchive archive)
|
||||
|
||||
@@ -3,6 +3,12 @@ fragment category on Category {
|
||||
icon
|
||||
}
|
||||
|
||||
fragment image on Image {
|
||||
id
|
||||
name
|
||||
description
|
||||
}
|
||||
|
||||
fragment layoutInfo on LayoutInfo {
|
||||
id
|
||||
deviceProvider
|
||||
@@ -20,4 +26,28 @@ fragment submittedEntry on Entry {
|
||||
entryType
|
||||
downloads
|
||||
createdAt
|
||||
}
|
||||
|
||||
fragment entryDetails on Entry {
|
||||
id
|
||||
author
|
||||
name
|
||||
summary
|
||||
entryType
|
||||
downloads
|
||||
createdAt
|
||||
description
|
||||
categories {
|
||||
...category
|
||||
}
|
||||
latestRelease {
|
||||
id
|
||||
version
|
||||
downloadSize
|
||||
md5Hash
|
||||
createdAt
|
||||
}
|
||||
images {
|
||||
...image
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,5 @@
|
||||
query GetEntryById($id: Long!) {
|
||||
entry(id: $id) {
|
||||
id
|
||||
author
|
||||
name
|
||||
summary
|
||||
entryType
|
||||
downloads
|
||||
createdAt
|
||||
description
|
||||
categories {
|
||||
...category
|
||||
}
|
||||
latestRelease {
|
||||
id
|
||||
version
|
||||
downloadSize
|
||||
md5Hash
|
||||
createdAt
|
||||
}
|
||||
...entryDetails
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ public interface IWorkshopService
|
||||
{
|
||||
Task<Stream?> GetEntryIcon(long entryId, CancellationToken cancellationToken);
|
||||
Task<ImageUploadResult> SetEntryIcon(long entryId, Progress<StreamProgress> progress, Stream icon, CancellationToken cancellationToken);
|
||||
Task<ImageUploadResult> UploadEntryImage(long entryId, Progress<StreamProgress> progress, Stream image, CancellationToken cancellationToken);
|
||||
Task<ImageUploadResult> UploadEntryImage(long entryId, ImageUploadRequest request, Progress<StreamProgress> progress, CancellationToken cancellationToken);
|
||||
Task<WorkshopStatus> GetWorkshopStatus(CancellationToken cancellationToken);
|
||||
Task<bool> ValidateWorkshopStatus(CancellationToken cancellationToken);
|
||||
Task NavigateToEntry(long entryId, EntryType entryType);
|
||||
|
||||
@@ -57,19 +57,19 @@ public class WorkshopService : IWorkshopService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ImageUploadResult> UploadEntryImage(long entryId, Progress<StreamProgress> progress, Stream image, CancellationToken cancellationToken)
|
||||
public async Task<ImageUploadResult> UploadEntryImage(long entryId, ImageUploadRequest request, Progress<StreamProgress> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
image.Seek(0, SeekOrigin.Begin);
|
||||
request.File.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
// Submit the archive
|
||||
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.WORKSHOP_CLIENT_NAME);
|
||||
|
||||
// Construct the request
|
||||
MultipartFormDataContent content = new();
|
||||
ProgressableStreamContent streamContent = new(image, progress);
|
||||
ProgressableStreamContent streamContent = new(request.File, progress);
|
||||
streamContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
|
||||
content.Add(streamContent, "file", "file.png");
|
||||
|
||||
|
||||
// Submit
|
||||
HttpResponseMessage response = await client.PostAsync($"entries/{entryId}/image", content, cancellationToken);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
|
||||
@@ -5,6 +5,8 @@ schema {
|
||||
mutation: Mutation
|
||||
}
|
||||
|
||||
directive @tag(name: String!) on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
||||
|
||||
type Category {
|
||||
icon: String!
|
||||
id: Long!
|
||||
@@ -50,8 +52,13 @@ type Entry {
|
||||
}
|
||||
|
||||
type Image {
|
||||
description: String
|
||||
height: Int!
|
||||
id: UUID!
|
||||
mimeType: String!
|
||||
name: String!
|
||||
size: Long!
|
||||
width: Int!
|
||||
}
|
||||
|
||||
type LayoutInfo {
|
||||
@@ -252,14 +259,39 @@ input EntryTypeOperationFilterInput {
|
||||
|
||||
input ImageFilterInput {
|
||||
and: [ImageFilterInput!]
|
||||
description: StringOperationFilterInput
|
||||
height: IntOperationFilterInput
|
||||
id: UuidOperationFilterInput
|
||||
mimeType: StringOperationFilterInput
|
||||
name: StringOperationFilterInput
|
||||
or: [ImageFilterInput!]
|
||||
size: LongOperationFilterInput
|
||||
width: IntOperationFilterInput
|
||||
}
|
||||
|
||||
input ImageSortInput {
|
||||
description: SortEnumType
|
||||
height: SortEnumType
|
||||
id: SortEnumType
|
||||
mimeType: SortEnumType
|
||||
name: SortEnumType
|
||||
size: SortEnumType
|
||||
width: SortEnumType
|
||||
}
|
||||
|
||||
input IntOperationFilterInput {
|
||||
eq: Int
|
||||
gt: Int
|
||||
gte: Int
|
||||
in: [Int]
|
||||
lt: Int
|
||||
lte: Int
|
||||
neq: Int
|
||||
ngt: Int
|
||||
ngte: Int
|
||||
nin: [Int]
|
||||
nlt: Int
|
||||
nlte: Int
|
||||
}
|
||||
|
||||
input LayoutInfoFilterInput {
|
||||
|
||||
Reference in new issue
Block a user