diff --git a/Application/Game/Card/Management/CardRegisterCommand.cs b/Application/Game/Card/Management/CardRegisterCommand.cs index df9b14c..870bc3f 100644 --- a/Application/Game/Card/Management/CardRegisterCommand.cs +++ b/Application/Game/Card/Management/CardRegisterCommand.cs @@ -1,23 +1,31 @@ -namespace Application.Game.Card.Management; +using Application.Common.Helpers; +using Microsoft.Extensions.Logging; + +namespace Application.Game.Card.Management; public record CardRegisterCommand(long CardId, string Data) : IRequestWrapper; public class RegisterCommandHandler : RequestHandlerBase { - public RegisterCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) + private readonly ILogger logger; + public RegisterCommandHandler(ICardDependencyAggregate aggregate, ILogger logger) : base(aggregate) { + this.logger = logger; } public override async Task> Handle(CardRegisterCommand request, CancellationToken cancellationToken) { var exists = CardDbContext.CardMains.Any(card => card.CardId == request.CardId); - if (!exists) + if (exists) { return ServiceResult.Failed(ServiceError.CustomMessage($"Card {request.CardId} already exists!")); } var card = request.Data.DeserializeCardData().CardDtoToCardMain(); card.CardId = request.CardId; + card.Created = TimeHelper.CurrentTimeToString(); + card.Modified = card.Created; + logger.LogInformation("New card {{Id: {Id}, Player Name: {Name}}} registered", card.CardId, card.PlayerName); CardDbContext.CardMains.Add(card); await CardDbContext.SaveChangesAsync(cancellationToken); diff --git a/Application/Game/Card/Read/ReadCardQuery.cs b/Application/Game/Card/Read/ReadCardQuery.cs index 963f9f7..80858f3 100644 --- a/Application/Game/Card/Read/ReadCardQuery.cs +++ b/Application/Game/Card/Read/ReadCardQuery.cs @@ -18,7 +18,7 @@ public class ReadQueryHandler : RequestHandlerBase var card = await CardDbContext.CardMains.FirstOrDefaultAsync(card => card.CardId == request.CardId, cancellationToken: cancellationToken); if (card is null) { - logger.LogInformation("Card with {CardId} does not exist! Registering a new one...", request.CardId); + logger.LogInformation("Card of id: {CardId} does not exist! Registering a new one...", request.CardId); return ServiceResult.Failed(new ServiceError($"Card id: {request.CardId} does not exist!", (int)CardReturnCode.CardNotRegistered)); } diff --git a/Application/Game/Card/Write/WriteCardCommand.cs b/Application/Game/Card/Write/WriteCardCommand.cs index d2d3ce3..7173480 100644 --- a/Application/Game/Card/Write/WriteCardCommand.cs +++ b/Application/Game/Card/Write/WriteCardCommand.cs @@ -26,6 +26,7 @@ public class WriteCommandHandler : RequestHandlerBase logger.LogInformation("Creating new card {CardId}", request.CardId); card = dto.CardDtoToCardMain(); card.Created = TimeHelper.CurrentTimeToString(); + card.Modified = TimeHelper.CurrentTimeToString(); CardDbContext.CardMains.Add(card); } else diff --git a/Application/Game/Server/GetDataQuery.cs b/Application/Game/Server/GetDataQuery.cs index 10552f2..dafb05e 100644 --- a/Application/Game/Server/GetDataQuery.cs +++ b/Application/Game/Server/GetDataQuery.cs @@ -17,7 +17,7 @@ public class GetDataQueryHandler : IRequestHandler public Task Handle(GetDataQuery request, CancellationToken cancellationToken) { var response = "count=0\n" + - "nexttime=0\n"; + "nexttime=180\n"; if (!eventManagerService.UseEvents()) { return Task.FromResult(response); @@ -38,7 +38,7 @@ public class GetDataQueryHandler : IRequestHandler } response = $"count={count}\n" + - "nexttime=1\n" + + "nexttime=180\n" + $"{dataString}"; return Task.FromResult(response); diff --git a/Domain/Config/GameConfig.cs b/Domain/Config/GameConfig.cs index c7a5c00..c6c154d 100644 --- a/Domain/Config/GameConfig.cs +++ b/Domain/Config/GameConfig.cs @@ -16,7 +16,5 @@ public class GameConfig public int TitleCount { get; set; } - public List UnlockableSongIds { get; set; } = new(); - public List UnlockRewards { get; set; } = new(); } \ No newline at end of file diff --git a/Domain/Domain.csproj b/Domain/Domain.csproj index 6836c68..d21f3bd 100644 --- a/Domain/Domain.csproj +++ b/Domain/Domain.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/Domain/Enums/CardReturnCode.cs b/Domain/Enums/CardReturnCode.cs index 982386d..4e41482 100644 --- a/Domain/Enums/CardReturnCode.cs +++ b/Domain/Enums/CardReturnCode.cs @@ -23,5 +23,5 @@ public enum CardReturnCode /// /// Server side validation error /// - Unknown = -1 + Unknown = 9999 } \ No newline at end of file diff --git a/Domain/Enums/ShowFastSlowOption.cs b/Domain/Enums/ShowFastSlowOption.cs index f7f7f91..db01d19 100644 --- a/Domain/Enums/ShowFastSlowOption.cs +++ b/Domain/Enums/ShowFastSlowOption.cs @@ -1,8 +1,20 @@ -namespace Domain.Enums; +using System.ComponentModel.DataAnnotations; +using NetEscapades.EnumGenerators; +namespace Domain.Enums; + +[EnumExtensions] public enum ShowFastSlowOption : long { + [Display(Name = "Default option")] + Default = 0, + + [Display(Name = "Show fast/slow near avatars")] NearAvatar = 1, + + [Display(Name = "Show fast/show near judgement text")] NearJudgement = 2, + + [Display(Name = "Do not show fast/slow")] NotShow = 3 } \ No newline at end of file diff --git a/Domain/Enums/ShowFeverTranceOption.cs b/Domain/Enums/ShowFeverTranceOption.cs index 37c4f95..03ef22b 100644 --- a/Domain/Enums/ShowFeverTranceOption.cs +++ b/Domain/Enums/ShowFeverTranceOption.cs @@ -1,7 +1,17 @@ -namespace Domain.Enums; +using System.ComponentModel.DataAnnotations; +using NetEscapades.EnumGenerators; +namespace Domain.Enums; + +[EnumExtensions] public enum ShowFeverTranceOption : long { + [Display(Name = "Default option")] + Default = 0, + + [Display(Name = "Show fever/trance")] Show = 1, + + [Display(Name = "Do not show fever/trance")] NotShow = 2 } \ No newline at end of file diff --git a/MainServer/Configurations/database.json b/MainServer/Configurations/database.json index ae84581..3c9ff35 100644 --- a/MainServer/Configurations/database.json +++ b/MainServer/Configurations/database.json @@ -1,4 +1,4 @@ { - "CardDbName": "card1.db3", + "CardDbName": "card.db3", "MusicDbName": "music471omni.db3" } \ No newline at end of file diff --git a/MainServer/Configurations/game.json b/MainServer/Configurations/game.json index ffa6224..84a2676 100644 --- a/MainServer/Configurations/game.json +++ b/MainServer/Configurations/game.json @@ -6,13 +6,6 @@ "SkinCount": 21, "SeCount": 26, "TitleCount": 5530, - "UnlockableSongIds": - [ - 11, 13, 149, 273, 291, 320, 321, 371, 378, 384, 464, 471, 474, 475, 492, - 494, 498, 520, 548, 551, 558, 561, 565, 570, 577, 583, 612, 615, 622, - 632, 659, 666, 668, 670, 672, 676, 680, 682, 685, 686, 697, 700, 701, - 711, 720, 749, 875, 876, 877 - ], "UnlockRewards": [ { "RewardId" : 1, diff --git a/MainServer/Controllers/API/PlayOptionController.cs b/MainServer/Controllers/API/PlayOptionController.cs index 67e6f7d..c825c4d 100644 --- a/MainServer/Controllers/API/PlayOptionController.cs +++ b/MainServer/Controllers/API/PlayOptionController.cs @@ -9,14 +9,14 @@ namespace MainServer.Controllers.API; public class PlayOptionController : BaseController { [HttpGet("{cardId:long}")] - public async Task>> GetPlayOptionById(long cardId) + public async Task> GetPlayOptionById(long cardId) { var result = await Mediator.Send(new GetPlayOptionQuery(cardId)); return result; } [HttpPost] - public async Task>> SetPlayOption(PlayOptionData data) + public async Task> SetPlayOption(PlayOptionData data) { var result = await Mediator.Send(new SetPlayOptionCommand(data)); return result; diff --git a/MainServer/Controllers/API/ProfilesController.cs b/MainServer/Controllers/API/ProfilesController.cs index f3130ff..d71ff37 100644 --- a/MainServer/Controllers/API/ProfilesController.cs +++ b/MainServer/Controllers/API/ProfilesController.cs @@ -10,28 +10,28 @@ namespace MainServer.Controllers.API; public class ProfilesController : BaseController { [HttpGet] - public async Task>>> GetAllCards() + public async Task>> GetAllCards() { var result = await Mediator.Send(new GetCardsQuery()); return result; } [HttpGet("{cardId:long}")] - public async Task>> GetCardTotalResultById(long cardId) + public async Task> GetCardTotalResultById(long cardId) { var result = await Mediator.Send(new GetTotalResultQuery(cardId)); return result; } [HttpPost("Favorite")] - public async Task>> SetFavoriteMusic(MusicDetailDto detail) + public async Task> SetFavoriteMusic(MusicDetailDto detail) { var result = await Mediator.Send(new SetFavoriteMusicCommand(detail)); return result; } [HttpPost("PlayerName")] - public async Task>> SetPlayerName(ClientCardDto card) + public async Task> SetPlayerName(ClientCardDto card) { var result = await Mediator.Send(new SetPlayerNameCommand(card)); return result; diff --git a/MainServer/Filters/ApiExceptionFilterAttributes.cs b/MainServer/Filters/ApiExceptionFilterAttributes.cs index 4bb35c2..644ef71 100644 --- a/MainServer/Filters/ApiExceptionFilterAttributes.cs +++ b/MainServer/Filters/ApiExceptionFilterAttributes.cs @@ -47,6 +47,7 @@ public class ApiExceptionFilterService : ExceptionFilterAttribute return; } + logger.LogError(context.Exception, "An unknown exception happens"); HandleUnknownException(context); } diff --git a/MainServer/Program.cs b/MainServer/Program.cs index d0020b2..8da4f60 100644 --- a/MainServer/Program.cs +++ b/MainServer/Program.cs @@ -8,10 +8,10 @@ using Infrastructure.Persistence; using MainServer.Filters; using Microsoft.AspNetCore.StaticFiles; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.FileProviders; using Serilog; using Serilog.Extensions.Logging; using Throw; +using Shared.SerializerContexts; Log.Logger = new LoggerConfiguration() .WriteTo.Console() @@ -57,7 +57,8 @@ try }); builder.Services.AddControllers(options => - options.Filters.Add()); + options.Filters.Add()) + .AddJsonOptions(options => options.JsonSerializerOptions.AddContext()); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); @@ -99,6 +100,7 @@ try { app.UseSwagger(); app.UseSwaggerUI(); + app.UseWebAssemblyDebugging(); } // Add content type for .cmp and .evt files as static files with unknown file extensions return 404 by default diff --git a/MainServer/Properties/launchSettings.json b/MainServer/Properties/launchSettings.json index a202104..8ca3350 100644 --- a/MainServer/Properties/launchSettings.json +++ b/MainServer/Properties/launchSettings.json @@ -12,7 +12,7 @@ "MainServer": { "commandName": "Project", "dotnetRunMessages": true, - "launchBrowser": true, + "launchBrowser": false, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", "applicationUrl": "http://localhost:5107", "environmentVariables": { diff --git a/Shared/SerializerContexts/SourceGenerationContext.cs b/Shared/SerializerContexts/SourceGenerationContext.cs new file mode 100644 index 0000000..47144e1 --- /dev/null +++ b/Shared/SerializerContexts/SourceGenerationContext.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; +using Shared.Dto.Api; +using Shared.Models; + +namespace Shared.SerializerContexts; + +[JsonSourceGenerationOptions(WriteIndented = true, GenerationMode = JsonSourceGenerationMode.Metadata)] +[JsonSerializable(typeof(ServiceResult>))] +[JsonSerializable(typeof(ServiceResult))] +[JsonSerializable(typeof(ServiceResult))] +[JsonSerializable(typeof(ServiceResult))] +[JsonSerializable(typeof(ServiceResult))] +public partial class SourceGenerationContext : JsonSerializerContext +{ + +} \ No newline at end of file diff --git a/WebUI/Common/MainLayout.razor b/WebUI/Common/MainLayout.razor index f5dccc1..042c52e 100644 --- a/WebUI/Common/MainLayout.razor +++ b/WebUI/Common/MainLayout.razor @@ -7,7 +7,7 @@ + OnClick="@DrawerToggle"/> - - -@code { - bool drawerOpen = true; - - public bool IsDarkMode { get; set; } - - public MudThemeProvider MudThemeProvider { get; set; } = null!; - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - IsDarkMode = await MudThemeProvider.GetSystemPreference(); - StateHasChanged(); - } - } - - void DrawerToggle() - { - drawerOpen = !drawerOpen; - } - -} \ No newline at end of file + \ No newline at end of file diff --git a/WebUI/Common/MainLayout.razor.cs b/WebUI/Common/MainLayout.razor.cs new file mode 100644 index 0000000..99876b0 --- /dev/null +++ b/WebUI/Common/MainLayout.razor.cs @@ -0,0 +1,26 @@ +using MudBlazor; + +namespace WebUI.Common; + +public partial class MainLayout +{ + bool drawerOpen = true; + + public bool IsDarkMode { get; set; } + + public MudThemeProvider MudThemeProvider { get; set; } = null!; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + IsDarkMode = await MudThemeProvider.GetSystemPreference(); + StateHasChanged(); + } + } + + void DrawerToggle() + { + drawerOpen = !drawerOpen; + } +} \ No newline at end of file diff --git a/WebUI/Common/SerializerContexts/SourceGenerationContext.cs b/WebUI/Common/SerializerContexts/SourceGenerationContext.cs deleted file mode 100644 index e2dab72..0000000 --- a/WebUI/Common/SerializerContexts/SourceGenerationContext.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Text.Json.Serialization; -using WebUI.Common.Models; - -namespace WebUI.Common.SerializerContexts; - -[JsonSourceGenerationOptions(WriteIndented = true)] -[JsonSerializable(typeof(List))] -[JsonSerializable(typeof(List))] -[JsonSerializable(typeof(List))] -internal partial class SourceGenerationContext : JsonSerializerContext -{ - -} \ No newline at end of file diff --git a/WebUI/GlobalUsings.cs b/WebUI/GlobalUsings.cs new file mode 100644 index 0000000..099b2c7 --- /dev/null +++ b/WebUI/GlobalUsings.cs @@ -0,0 +1,3 @@ +// Global using directives + +global using MudBlazor; \ No newline at end of file diff --git a/WebUI/Pages/Cards.razor b/WebUI/Pages/Cards.razor index 016eba9..9a2b66b 100644 --- a/WebUI/Pages/Cards.razor +++ b/WebUI/Pages/Cards.razor @@ -1,73 +1,91 @@ @page "/Cards" <PageTitle>Cards</PageTitle> +<h1>Cards</h1> + +@if (ErrorMessage != string.Empty) +{ + <MudText Color="Color.Error" Typo="Typo.h3">@ErrorMessage</MudText> + return; +} +<MudGrid Class="my-8"> -<MudContainer> - @if (ErrorMessage != string.Empty) - { - <MudText Color="Color.Error" Typo="Typo.h3">@ErrorMessage</MudText> - return; - } - @if (CardDtos is null) { - <MudGrid> - @for (var i = 0; i < 5; i++) - { - <MudItem> - <MudCard> - <MudCardHeader> - <CardHeaderContent> - <MudSkeleton SkeletonType="SkeletonType.Rectangle" Height="32px"/> - </CardHeaderContent> - </MudCardHeader> - <MudCardContent> - <MudSkeleton Width="80px" Height="32px"/> - <MudSkeleton Width="147px" Height="28px"/> - </MudCardContent> - <MudCardActions> - <MudSkeleton SkeletonType="SkeletonType.Rectangle" Width="99px" Height="25px" Class="ml-2"/> - </MudCardActions> - </MudCard> - </MudItem> - } - </MudGrid> + @for (var i = 0; i < 3; i++) + { + <MudItem xs="12" md="6" lg="4"> + <MudCard Outlined="true"> + <MudCardHeader> + <CardHeaderContent> + <MudSkeleton Width="30%" Height="32px;" Class="mb-5"/> + </CardHeaderContent> + </MudCardHeader> + <MudCardContent> + <MudSkeleton Width="60%"/> + <MudSkeleton Width="100%"/> + </MudCardContent> + <MudCardActions> + <MudStack Row="true" Style="width:100%" Spacing="4" Justify="Justify.FlexEnd"> + <MudSkeleton Width="128px" Height="32px"/> + <MudSkeleton Width="148px" Height="32px"/> + </MudStack> + </MudCardActions> + </MudCard> + </MudItem> + } return; } - + @if (CardDtos.Count != 0) { - <MudGrid> - @foreach (var card in CardDtos) - { - <MudItem> - <MudCard> - <MudCardHeader> - <CardHeaderContent> - <MudText Typo="Typo.h5">@card.PlayerName</MudText> - </CardHeaderContent> - <CardHeaderActions> - <MudIconButton Icon="@Icons.Material.Filled.Edit" Color="Color.Default" - OnClick="() => OnEditPlayerNameClicked(card)"/> - </CardHeaderActions> - </MudCardHeader> - <MudCardContent> - <MudText Style="font-weight: bold">Card ID</MudText> - <MudText>@card.CardId</MudText> - </MudCardContent> - <MudCardActions> - <MudButton Variant="Variant.Text" Color="Color.Primary"> - Check detail + @foreach (var card in CardDtos) + { + <MudItem xs="12" md="6" lg="4"> + <MudCard> + <MudCardHeader> + <CardHeaderContent> + <MudText Typo="Typo.h5">@card.PlayerName</MudText> + </CardHeaderContent> + <CardHeaderActions> + <MudIconButton Icon="@Icons.Material.Filled.Edit" Color="Color.Default" + OnClick="() => OnEditPlayerNameClicked(card)"/> + </CardHeaderActions> + </MudCardHeader> + <MudCardContent> + <MudText Style="font-weight: bold">Card ID</MudText> + <MudText Style="font-family:monospace">@card.CardId</MudText> + </MudCardContent> + <MudCardActions> + <MudStack Row="true" Style="width:100%" Spacing="4" Justify="Justify.FlexEnd"> + <MudButton Href="@($"Cards/Option/{card.CardId}")" + Variant="Variant.Text" + StartIcon="@Icons.Material.Filled.DisplaySettings" + Color="Color.Primary"> + Edit Options </MudButton> - </MudCardActions> - </MudCard> - </MudItem> - } - </MudGrid> + <MudMenu Dense="true" + Color="Color.Primary" + Label="View Play Data" + StartIcon="@Icons.Material.Filled.FeaturedPlayList" + EndIcon="@Icons.Material.Filled.KeyboardArrowDown" + FullWidth="true" + AnchorOrigin="Origin.BottomCenter" + TransformOrigin="Origin.TopCenter"> + <MudMenuItem Href="@($"Cards/TotalResult/{card.CardId}")">Total Result</MudMenuItem> + <MudMenuItem Href="@($"Cards/Results/{card.CardId}")">Song Play Results</MudMenuItem> + </MudMenu> + </MudStack> + </MudCardActions> + </MudCard> + </MudItem> + } return; } - - <MudText Align="Align.Center" Typo="Typo.h3"> - No Data - </MudText> -</MudContainer> \ No newline at end of file + + <MudItem xs="12"> + <MudText Align="Align.Center" Typo="Typo.h3"> + No Data + </MudText> + </MudItem> +</MudGrid> \ No newline at end of file diff --git a/WebUI/Pages/Cards.razor.cs b/WebUI/Pages/Cards.razor.cs index 07d0da8..119958f 100644 --- a/WebUI/Pages/Cards.razor.cs +++ b/WebUI/Pages/Cards.razor.cs @@ -1,8 +1,10 @@ using System.Net.Http.Json; using Microsoft.AspNetCore.Components; -using MudBlazor; using Shared.Dto.Api; using Shared.Models; +using Throw; +using Shared.SerializerContexts; +using WebUI.Pages.Dialogs; namespace WebUI.Pages; @@ -14,6 +16,9 @@ public partial class Cards [Inject] public required IDialogService DialogService { get; set; } + [Inject] + public required ILogger<Cards> Logger { get; set; } + private List<ClientCardDto>? CardDtos { get; set; } private string ErrorMessage { get; set; } = string.Empty; @@ -21,12 +26,11 @@ public partial class Cards protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); + await Task.Delay(3000); var result = await Client.GetFromJsonAsync<ServiceResult<List<ClientCardDto>>>("api/Profiles"); - if (result is null) - { - ErrorMessage = "Parse result failed"; - return; - } + result.ThrowIfNull(); + + Logger.LogInformation("Result: {Result}", result.Data); if (!result.Succeeded) { @@ -46,6 +50,7 @@ public partial class Cards }; var parameters = new DialogParameters { { "Data", card } }; var dialog = await DialogService.ShowAsync<ChangePlayerNameDialog>("Favorite", parameters, options); + // ReSharper disable once UnusedVariable var result = await dialog.Result; } } \ No newline at end of file diff --git a/WebUI/Pages/ChangePlayerNameDialog.razor b/WebUI/Pages/Dialogs/ChangePlayerNameDialog.razor similarity index 94% rename from WebUI/Pages/ChangePlayerNameDialog.razor rename to WebUI/Pages/Dialogs/ChangePlayerNameDialog.razor index f83a6c7..ab17b50 100644 --- a/WebUI/Pages/ChangePlayerNameDialog.razor +++ b/WebUI/Pages/Dialogs/ChangePlayerNameDialog.razor @@ -50,6 +50,12 @@ async Task Submit() { + if (originalName.Equals(Data.PlayerName)) + { + MudDialog.Close(DialogResult.Ok(true)); + return; + } + Logger.LogInformation("Data is {CardId}, {Name}", Data.CardId, Data.PlayerName); var response = await Client.PostAsJsonAsync("api/Profiles/PlayerName", Data); var result = await response.Content.ReadFromJsonAsync<ServiceResult<bool>>(); diff --git a/WebUI/Pages/Option.razor b/WebUI/Pages/Option.razor new file mode 100644 index 0000000..f84210d --- /dev/null +++ b/WebUI/Pages/Option.razor @@ -0,0 +1,61 @@ +@page "/Cards/Option/{cardId:long}" +@using Domain.Enums + + +<MudBreadcrumbs Items="breadcrumbs" Class="px-0"></MudBreadcrumbs> + +<PageTitle>Option</PageTitle> +<h1>Play Options</h1> +@if (playOptionData is null) +{ + <MudStack> + <MudSkeleton Width="100%"/> + <MudSkeleton Width="100%"/> + <MudSkeleton Width="100%"/> + <MudSkeleton Width="100%"/> + <MudSkeleton Width="100%"/> + <MudSkeleton Width="100%"/> + </MudStack> + return; +} + +@if (errorMessage != string.Empty) +{ + <MudText Color="Color.Error" Typo="Typo.h3">@errorMessage</MudText> + return; +} +<MudStack> + <MudStack Row="true"> + <MudField Label="Avatar">@GetAvatarName((uint)playOptionData.OptionPart1.AvatarId)</MudField> + <MudButton Variant="Variant.Text">Change Avatar</MudButton> + </MudStack> + + <MudStack Row="true"> + <MudField Label="Title">@GetTitleName((uint)playOptionData.OptionPart1.TitleId)</MudField> + <MudButton Variant="Variant.Text">Change Title</MudButton> + </MudStack> + + <MudStack Row="true"> + <MudField Label="Navigator">@GetNavigatorName((uint)playOptionData.OptionPart2.NavigatorId)</MudField> + <MudButton Variant="Variant.Text">Change Navigator</MudButton> + </MudStack> + + + <MudSelect T="ShowFastSlowOption" Label="Fast/Slow option" Variant="Variant.Outlined" + @bind-Value="@playOptionData.OptionPart1.ShowFastSlowOption"> + @foreach (var item in ShowFastSlowOptionExtensions.GetValues()) + { + <MudSelectItem Value="item">@item.ToStringFast()</MudSelectItem> + } + </MudSelect> + + <MudSelect T="ShowFeverTranceOption" Label="Fever/Trance option" Variant="Variant.Outlined" + @bind-Value="@playOptionData.OptionPart1.ShowFeverTranceOption"> + @foreach (var item in ShowFeverTranceOptionExtensions.GetValues()) + { + <MudSelectItem Value="item">@item.ToStringFast()</MudSelectItem> + } + </MudSelect> + + <MudButton Color="Color.Info" Variant="Variant.Filled">Save Options</MudButton> +</MudStack> \ No newline at end of file diff --git a/WebUI/Pages/Option.razor.cs b/WebUI/Pages/Option.razor.cs new file mode 100644 index 0000000..670b435 --- /dev/null +++ b/WebUI/Pages/Option.razor.cs @@ -0,0 +1,72 @@ +using System.Net.Http.Json; +using Microsoft.AspNetCore.Components; +using Shared.Models; +using Throw; +using WebUI.Services; +using SourceGenerationContext = Shared.SerializerContexts.SourceGenerationContext; + +namespace WebUI.Pages; + +public partial class Option +{ + [Parameter] + public long CardId { get; set; } + + [Inject] + public required HttpClient Client { get; set; } + + [Inject] + public required IDialogService DialogService { get; set; } + + [Inject] + public required IDataService DataService { get; set; } + + private readonly List<BreadcrumbItem> breadcrumbs = new() + { + new BreadcrumbItem("Cards", href: "/Cards"), + }; + + private PlayOptionData? playOptionData; + + private string errorMessage = string.Empty; + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + breadcrumbs.Add(new BreadcrumbItem($"Card: {CardId}", href:null, disabled:true)); + breadcrumbs.Add(new BreadcrumbItem("Option", href: $"/Cards/Option/{CardId}", disabled: false)); + + await Task.Delay(3000); + var result = await Client.GetFromJsonAsync<ServiceResult<PlayOptionData>>($"api/PlayOption/{CardId}"); + result.ThrowIfNull(); + + if (!result.Succeeded) + { + errorMessage = result.Error!.Message; + return; + } + + playOptionData = result.Data; + } + + private string GetNavigatorName(uint navigatorId) + { + var navigator = DataService.GetNavigators().GetValueOrDefault(navigatorId); + + return navigator?.NavigatorName ?? "Navigator id unknown"; + } + + private string GetAvatarName(uint avatarId) + { + var avatar = DataService.GetAvatars().GetValueOrDefault(avatarId); + + return avatar?.AvatarName ?? "Avatar id unknown"; + } + + private string GetTitleName(uint titleId) + { + var title = DataService.GetTitles().GetValueOrDefault(titleId); + + return title?.TitleName ?? "Title id unknown"; + } +} \ No newline at end of file diff --git a/WebUI/Services/DataService.cs b/WebUI/Services/DataService.cs index 042de51..54cb84c 100644 --- a/WebUI/Services/DataService.cs +++ b/WebUI/Services/DataService.cs @@ -1,8 +1,8 @@ using System.Collections.ObjectModel; using System.Net.Http.Json; +using System.Text.Json.Serialization; using Throw; using WebUI.Common.Models; -using SourceGenerationContext = WebUI.Common.SerializerContexts.SourceGenerationContext; namespace WebUI.Services; @@ -50,4 +50,12 @@ public class DataService : IDataService { return new ReadOnlyDictionary<uint, Title>(titles); } +} + +[JsonSerializable(typeof(List<Avatar>))] +[JsonSerializable(typeof(List<Navigator>))] +[JsonSerializable(typeof(List<Title>))] +internal partial class SourceGenerationContext : JsonSerializerContext +{ + } \ No newline at end of file diff --git a/doc/card_detail.md b/doc/card_detail.md index b9f3c9e..be7c28f 100644 --- a/doc/card_detail.md +++ b/doc/card_detail.md @@ -6,7 +6,7 @@ card_id, pcol1, pcol2, pcol3 are primary keys | :---: | :-----: | :--------: | :----------------------------------------------------------: | | 0 | 0 | 0 | score_i1:**avatar** score_ui1:**fast/slow** score_ui2:**fever/trance** fcol1: fcol2:**title** fcol3:**sound** | | 1 | 0 | 0 | score_i1:**navigator** fcol3:**unknown** | -| 10 | song id | 0 | score_i1:**skin** score_ui2/score_ui6: **Unknown used when the song need to be and is unlocked**, fcol1:**Favorite song** | +| 10 | song id | 0 | score_i1:**skin** score_ui2s:**Whether the song is unlocked** , core_ui6: **The song need to be unlocked**, fcol1:**Favorite song** | | 20 | song id | difficulty | score_ui1:**play count** score_ui2:**clear count** score_ui3:**no miss or higher count** score_ui4: **full_chain or higher count** score_ui5: **S+ or higher count** score_ui6: **perfect count** | | 21 | song id | difficulty | score_ui1/score_ui5: **highest score**, score_ui2/score_ui6:**highest_score time** score_ui3:**max_chain** score_ui4: **max chain time** fcol1:**max hit adlib count** fcol2:**time for fcol1** | | 30 | 0 | 0 | score_ui2:**Unknown, looks like some sort of count** |