@page "/admin/system/customisation" @using System.Text.Json @using Microsoft.AspNetCore.Authorization @using MoonCore.Blazor.FlyonUi.Common @using MoonCore.Blazor.FlyonUi.Grid @using MoonCore.Blazor.FlyonUi.Grid.Columns @using MoonCore.Blazor.FlyonUi.Grid.ToolbarItems @using MoonCore.Blazor.FlyonUi.Helpers @using MoonCore.Common @using MoonCore.Helpers @using Moonlight.Client.Models @using Moonlight.Client.Services @using Moonlight.Shared.Http.Requests.Admin.Sys.Theme @using Moonlight.Shared.Http.Responses.Admin @attribute [Authorize(Policy = "permissions:admin.system.theme")] @inject ThemeService ThemeService @inject AlertService AlertService @inject ToastService ToastService @inject HttpApiClient ApiClient @inject DownloadService DownloadService @inject ILogger Logger Themes
@context.Name @if (context.IsEnabled) { }
@if (!string.IsNullOrEmpty(context.DonateUrl)) { Donate } @if (!string.IsNullOrEmpty(context.UpdateUrl)) { Update } Export
Images & Logos @code { private DataGrid Grid; private ItemSource ItemSource => ItemSourceFactory.From(LoadItemsAsync); private async Task> LoadItemsAsync( int startIndex, int count, string? filter, SortOption? sortOption ) { var query = $"?startIndex={startIndex}&count={count}"; if (sortOption != null) { var dir = sortOption.Direction == SortDirection.Descending ? "desc" : "asc"; query += $"&orderBy={sortOption.Column}&orderByDir={dir}"; } if (!string.IsNullOrEmpty(filter)) query += $"&filter={filter}"; return await ApiClient.GetJson>($"api/admin/system/customisation/themes{query}"); } private async Task ImportAsync(InputFileChangeEventArgs eventArgs) { if (eventArgs.FileCount < 1) return; var files = eventArgs.GetMultipleFiles(); var maxFileSize = ByteConverter.FromMegaBytes(1).Bytes; foreach (var file in files) { try { if (!file.Name.EndsWith(".json")) { await ToastService.ErrorAsync($"Unable to import {file.Name}", "Only .json files are supported"); continue; } if (file.Size > maxFileSize) { await ToastService.ErrorAsync($"Unable to import {file.Name}", "Exceeded the maximum file limit of 1MB"); continue; } await using var stream = file.OpenReadStream(maxFileSize); var themeTransfer = await JsonSerializer.DeserializeAsync(stream); stream.Close(); if (themeTransfer == null) { await ToastService.ErrorAsync($"Unable to import {file.Name}", "Failed to deserialize the content"); continue; } var theme = await ThemeService.CreateAsync(new CreateThemeRequest() { Name = themeTransfer.Name, Author = themeTransfer.Author, Content = themeTransfer.Content, DonateUrl = themeTransfer.DonateUrl, UpdateUrl = themeTransfer.UpdateUrl, Version = themeTransfer.Version }); await ToastService.SuccessAsync("Successfully imported theme", theme.Name); await Grid.RefreshAsync(); } catch (Exception e) { Logger.LogError(e, "An unhandled error occured while importing file {file} as theme", file.Name); } } } private async Task ExportAsync(ThemeResponse theme) { var transfer = new ThemeTransferModel() { Name = theme.Name, Author = theme.Author, Content = theme.Content, DonateUrl = theme.DonateUrl, UpdateUrl = theme.UpdateUrl, Version = theme.Version }; var json = JsonSerializer.Serialize(transfer, new JsonSerializerOptions() { WriteIndented = true }); var fileName = $"{transfer.Name.Replace(" ", string.Empty).Trim()}.json"; await DownloadService.DownloadAsync(fileName, json); } private async Task DeleteAsync(ThemeResponse response) { await AlertService.ConfirmDangerAsync( "Theme deletion", $"Do you really want to delete the theme: {response.Name}", async () => { await ThemeService.DeleteAsync(response.Id); await ToastService.SuccessAsync("Successfully deleted theme"); await Grid.RefreshAsync(); } ); } }