diff --git a/GC-local-server-rewrite/backports/JsonDataAttribute.cs b/GC-local-server-rewrite/backports/JsonDataAttribute.cs new file mode 100644 index 0000000..f14696f --- /dev/null +++ b/GC-local-server-rewrite/backports/JsonDataAttribute.cs @@ -0,0 +1,41 @@ +using System; +using System.Threading.Tasks; + +namespace EmbedIO.WebApi +{ + /// + /// Specifies that a parameter of a controller method will receive + /// an object obtained by deserializing the request body as JSON. + /// The received object will be + /// only if the deserialized object is null. + /// If the request body is not valid JSON, + /// or if it cannot be deserialized to the type of the parameter, + /// a 400 Bad Request response will be sent to the client. + /// This class cannot be inherited. + /// + /// + /// + [AttributeUsage(AttributeTargets.Parameter)] + public class JsonDataAttribute : Attribute, IRequestDataAttribute + { + /// + public async Task GetRequestDataAsync(WebApiController controller, Type type, string parameterName) + { + string body; + + using (var reader = controller.HttpContext.OpenRequestText()) + { + body = await reader.ReadToEndAsync().ConfigureAwait(false); + } + + try + { + return Swan.Formatters.Json.Deserialize(body, type); + } + catch (FormatException) + { + throw HttpException.BadRequest($"Expected request body to be deserializable to {type.FullName}."); + } + } + } +} \ No newline at end of file diff --git a/GC-local-server-rewrite/common/Configs.cs b/GC-local-server-rewrite/common/Configs.cs index b2bb00f..66f30a8 100644 --- a/GC-local-server-rewrite/common/Configs.cs +++ b/GC-local-server-rewrite/common/Configs.cs @@ -122,6 +122,16 @@ public static class Configs public const string RANK_STATUS_XPATH = $"{ROOT_XPATH}/ranking_status"; + public const int CONFIG_PCOL1 = 0; + public const int CONFIG_PCOL2 = 0; + public const int CONFIG_PCOL3 = 0; + + public const int FAVORITE_PCOL1 = 10; + + public const int COUNT_PCOL1 = 20; + + public const int SCORE_PCOL1 = 21; + public static readonly List DOMAINS = new() { "localhost", diff --git a/GC-local-server-rewrite/controllers/ApiController.cs b/GC-local-server-rewrite/controllers/ApiController.cs index 8f0295b..2a13769 100644 --- a/GC-local-server-rewrite/controllers/ApiController.cs +++ b/GC-local-server-rewrite/controllers/ApiController.cs @@ -1,5 +1,4 @@ -using ChoETL; -using EmbedIO; +using EmbedIO; using EmbedIO.Routing; using EmbedIO.WebApi; using GCLocalServerRewrite.common; @@ -39,6 +38,54 @@ public class ApiController : WebApiController return result; } + [Route(HttpVerbs.Post, "/UserDetail/SetMusicFavorite")] + // ReSharper disable once UnusedMember.Global + public bool SetFavorite([JsonData] MusicFavoriteData data) + { + var existing = cardSqLiteConnection.Table() + .Where(detail => detail.CardId == data.CardId + && detail.Pcol1 == Configs.FAVORITE_PCOL1 + && detail.Pcol2 == data.MusicId); + + if (!existing.Any()) + { + $"Trying to update non existing song's favorite! Card id {data.CardId}, music id {data.MusicId}".Warn(); + return false; + } + + var cardDetail = existing.First(); + cardDetail.Fcol1 = data.IsFavorite ? 1 : 0; + var result = cardSqLiteConnection.Update(cardDetail); + + return result == 1; + } + + [Route(HttpVerbs.Post, "/UserDetail/SetPlayOption")] + // ReSharper disable once UnusedMember.Global + public bool SetPlayOption([JsonData] PlayOption data) + { + var existing = cardSqLiteConnection.Table() + .Where(detail => detail.CardId == data.CardId + && detail.Pcol1 == Configs.CONFIG_PCOL1 + && detail.Pcol2 == Configs.CONFIG_PCOL2 + && detail.Pcol3 == Configs.CONFIG_PCOL3); + + if (!existing.Any()) + { + $"Trying to update non existing card's config! Card id {data.CardId}".Warn(); + + return false; + } + + var cardDetail = existing.First(); + cardDetail.ScoreUi1 = (long)data.FastSlowIndicator; + cardDetail.ScoreUi2 = (long)data.FeverTrance; + + var result = cardSqLiteConnection.Update(cardDetail); + + return result == 1; + } + [Route(HttpVerbs.Get, "/UserDetail/{cardId}")] // ReSharper disable once UnusedMember.Global public UserDetail? GetUserDetail(long cardId) @@ -47,6 +94,7 @@ public class ApiController : WebApiController if (!cardResult.Any()) { + $"Getting detail for non exisisting card! Card id is {cardId}".Warn(); return null; } @@ -229,6 +277,7 @@ public class ApiController : WebApiController { Artist = musicData.Artist ?? string.Empty, Title = musicData.Title ?? string.Empty, + MusicId = musicId, SongPlaySubDataList = new SongPlayDetailData[4] }; diff --git a/MudAdmin/Pages/FavoriteDialog.razor b/MudAdmin/Pages/FavoriteDialog.razor new file mode 100644 index 0000000..639da68 --- /dev/null +++ b/MudAdmin/Pages/FavoriteDialog.razor @@ -0,0 +1,57 @@ +@using SharedProject.models +@inject HttpClient Client +@inject ILogger Logger + + + + @if (!Data.IsFavorite) + { + + + Add to favorite? + + } + else + { + + + Remove from favorite? + + } + + + + + + + Cancel + Confirm + + +@code { + [CascadingParameter] + MudDialogInstance MudDialog { get; set; } = null!; + + [Parameter] + public SongPlayData Data { get; set; } = null!; + + [Parameter] + public long CardId { get; set; } + + async void Submit() + { + var postData = new MusicFavoriteData + { + CardId = CardId, + IsFavorite = !Data.IsFavorite, + MusicId = Data.MusicId + }; + Logger.LogInformation("Data is {cardId}, {musicId}", CardId, Data.MusicId); + var response = await Client.PostAsJsonAsync("api/UserDetail/SetMusicFavorite", postData); + var result = await response.Content.ReadFromJsonAsync(); + Logger.LogInformation("Favorite result is {result}", result); + MudDialog.Close(DialogResult.Ok(result)); + } + + void Cancel() => MudDialog.Cancel(); +} \ No newline at end of file diff --git a/MudAdmin/Pages/FetchData.razor b/MudAdmin/Pages/FetchData.razor deleted file mode 100644 index 0db80ca..0000000 --- a/MudAdmin/Pages/FetchData.razor +++ /dev/null @@ -1,61 +0,0 @@ -@page "/fetchdata" -@inject HttpClient Http - -Weather forecast - -Weather forecast -This component demonstrates fetching data from the server. -@if (forecasts == null) -{ - -} -else -{ - - - - Date - - - Temp. (C) - - - Temp. (F) - - - Summary - - - - @context.Date - @context.TemperatureC - @context.TemperatureF - @context.Summary - - - - - -} - - -@code { - private WeatherForecast[]? forecasts; - - protected override async Task OnInitializedAsync() - { - forecasts = await Http.GetFromJsonAsync("sample-data/weather.json"); - } - - public class WeatherForecast - { - public DateTime Date { get; set; } - - public int TemperatureC { get; set; } - - public string? Summary { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - } - -} \ No newline at end of file diff --git a/MudAdmin/Pages/User.razor b/MudAdmin/Pages/User.razor index 6c32fa4..a109dd5 100644 --- a/MudAdmin/Pages/User.razor +++ b/MudAdmin/Pages/User.razor @@ -1,14 +1,17 @@ @page "/user/{CardId:long}" @using SharedProject.models -@using MudAdmin.Utils @using SharedProject.enums @inject HttpClient Client +@inject IDialogService DialogService +@inject ILogger Logger User - + @if (userDetail == null) { - + + + } else { @@ -57,12 +60,12 @@ else - + Played Songs - + @@ -70,22 +73,17 @@ else - + - - - - - @CalculateTotalPlayCount(context.Item) - - - + @if (context.ShowDetails) @@ -99,7 +97,7 @@ else - + Difficulty Clear State @@ -132,6 +130,7 @@ else } + @code { @@ -177,7 +176,13 @@ else private async Task SaveOptions() { isSavingOptions = true; - await Task.Delay(2000); + var postData = new PlayOption + { + CardId = CardId, + FastSlowIndicator = fastSlowIndicator, + FeverTrance = feverTranceShow + }; + var result = await Client.PostAsJsonAsync("api/UserDetail/SetPlayOption", postData); isSavingOptions = false; } @@ -195,14 +200,29 @@ else return grade; } - private void OnFavoriteToggled(SongPlayData data) + private async Task OnFavoriteToggled(SongPlayData data) { - data.IsFavorite = !data.IsFavorite; - } + var options = new DialogOptions + { + CloseOnEscapeKey = false, + DisableBackdropClick = true, + FullWidth = true + }; + var parameters = new DialogParameters(); + parameters.Add("Data", data); + parameters.Add("CardId", CardId); + var dialog = DialogService.Show("Favorite", parameters, options); + var result = await dialog.Result; - private static int CalculateTotalPlayCount(SongPlayData data) - { - return data.SongPlaySubDataList - .Sum(detailData => detailData.PlayCount); + if (result.Cancelled) + { + return; + } + + if ((bool)result.Data) + { + Logger.LogInformation("Changed!"); + data.IsFavorite = !data.IsFavorite; + } } } \ No newline at end of file diff --git a/MudAdmin/Pages/Users.razor b/MudAdmin/Pages/Users.razor index 08d7257..a486c2b 100644 --- a/MudAdmin/Pages/Users.razor +++ b/MudAdmin/Pages/Users.razor @@ -5,31 +5,64 @@ Users - - @foreach (var user in users) + + @if (users is null) { - - - - - @user.PlayerName - - - - Card ID - @user.CardId - - - Test - - - + + @for (var i = 0; i < 5; i++) + { + + + + + + + + + + + + + + + + + } + } - + else if (!(users.Count == 0)) + { + + @foreach (var user in users) + { + + + + + @user.PlayerName + + + + Card ID + @user.CardId + + + Check detail + + + + } + + } + else + { + No Data + } + @code { - private List users = new(); - + private List? users; + protected override async Task OnInitializedAsync() { @@ -41,4 +74,5 @@ { NavigationManager.NavigateTo($"user/{user.CardId}"); } + } \ No newline at end of file diff --git a/MudAdmin/Program.cs b/MudAdmin/Program.cs index 441cf5a..11f979d 100644 --- a/MudAdmin/Program.cs +++ b/MudAdmin/Program.cs @@ -1,3 +1,4 @@ +using System.Text.Json; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MudAdmin; diff --git a/MudAdmin/Shared/NavMenu.razor b/MudAdmin/Shared/NavMenu.razor index b3c37b3..9b23ec3 100644 --- a/MudAdmin/Shared/NavMenu.razor +++ b/MudAdmin/Shared/NavMenu.razor @@ -1,6 +1,5 @@  Home Counter - Fetch data Users \ No newline at end of file diff --git a/SharedProject/enums/ClearState.cs b/SharedProject/enums/ClearState.cs index 7530662..a9376ce 100644 --- a/SharedProject/enums/ClearState.cs +++ b/SharedProject/enums/ClearState.cs @@ -2,6 +2,7 @@ public enum ClearState { + NotPlayed = 0, Failed, Clear, NoMiss, diff --git a/SharedProject/models/MusicFavoriteData.cs b/SharedProject/models/MusicFavoriteData.cs new file mode 100644 index 0000000..2054155 --- /dev/null +++ b/SharedProject/models/MusicFavoriteData.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace SharedProject.models; + +public class MusicFavoriteData +{ + [JsonPropertyName(nameof(CardId))] + public long CardId { get; set; } + + [JsonPropertyName(nameof(MusicId))] + public int MusicId { get; set; } + + [JsonPropertyName(nameof(IsFavorite))] + public bool IsFavorite { get; set; } +} \ No newline at end of file diff --git a/SharedProject/models/PlayOption.cs b/SharedProject/models/PlayOption.cs index 1c3bf5a..0795e68 100644 --- a/SharedProject/models/PlayOption.cs +++ b/SharedProject/models/PlayOption.cs @@ -1,12 +1,16 @@ -using SharedProject.enums; +using System.Text.Json.Serialization; +using SharedProject.enums; namespace SharedProject.models; public class PlayOption { + [JsonPropertyName(nameof(CardId))] public long CardId { get; set; } + [JsonPropertyName(nameof(FastSlowIndicator))] public PlayOptions.FastSlowIndicator FastSlowIndicator { get; set; } + [JsonPropertyName(nameof(FeverTrance))] public PlayOptions.FeverTranceShow FeverTrance { get; set; } } \ No newline at end of file diff --git a/SharedProject/models/SongPlayData.cs b/SharedProject/models/SongPlayData.cs index 4f56ae9..41744a1 100644 --- a/SharedProject/models/SongPlayData.cs +++ b/SharedProject/models/SongPlayData.cs @@ -1,14 +1,27 @@ -namespace SharedProject.models; +using System.Text.Json.Serialization; + +namespace SharedProject.models; public class SongPlayData { public string Title { get; set; } = string.Empty; public string Artist { get; set; } = string.Empty; + + public int MusicId { get; set; } public SongPlayDetailData[] SongPlaySubDataList { get; set; } = new SongPlayDetailData[4]; public bool IsFavorite { get; set; } public bool ShowDetails { get; set; } + + [JsonIgnore] + public int TotalPlayCount + { + get + { + return SongPlaySubDataList.Sum(data => data.PlayCount); + } + } } \ No newline at end of file