diff --git a/SharedProject/Enums/DanBorderType.cs b/SharedProject/Enums/DanBorderType.cs new file mode 100644 index 0000000..29f339c --- /dev/null +++ b/SharedProject/Enums/DanBorderType.cs @@ -0,0 +1,7 @@ +namespace SharedProject.Enums; + +public enum DanBorderType +{ + All = 1, + PerSong = 2 +} \ No newline at end of file diff --git a/SharedProject/Enums/DanConditionType.cs b/SharedProject/Enums/DanConditionType.cs new file mode 100644 index 0000000..14cf8a6 --- /dev/null +++ b/SharedProject/Enums/DanConditionType.cs @@ -0,0 +1,13 @@ +namespace SharedProject.Enums; + +public enum DanConditionType +{ + SoulGauge = 1, + GoodCount = 2, + OkCount = 3, + BadCount = 4, + ComboCount = 5, + DrumrollCount = 6, + Score = 7, + TotalHitCount = 8 +} \ No newline at end of file diff --git a/SharedProject/Models/DanBestData.cs b/SharedProject/Models/DanBestData.cs new file mode 100644 index 0000000..3b0b321 --- /dev/null +++ b/SharedProject/Models/DanBestData.cs @@ -0,0 +1,16 @@ +using SharedProject.Enums; + +namespace SharedProject.Models; + +public class DanBestData +{ + public uint DanId { get; set; } + + public DanClearState ClearState { get; set; } + + public uint SoulGaugeTotal { get; set; } + + public uint ComboCountTotal { get; set; } + + public List DanBestStageDataList { get; set; } = new(); +} \ No newline at end of file diff --git a/SharedProject/Models/DanBestStageData.cs b/SharedProject/Models/DanBestStageData.cs new file mode 100644 index 0000000..58980ae --- /dev/null +++ b/SharedProject/Models/DanBestStageData.cs @@ -0,0 +1,20 @@ +namespace SharedProject.Models; + +public class DanBestStageData +{ + public uint SongNumber { get; set; } + + public uint PlayScore { get; set; } + + public uint GoodCount { get; set; } + + public uint OkCount { get; set; } + + public uint BadCount { get; set; } + + public uint DrumrollCount { get; set; } + + public uint TotalHitCount { get; set; } + + public uint ComboCount { get; set; } +} \ No newline at end of file diff --git a/TaikoLocalServer/Models/OdaiData.cs b/SharedProject/Models/DanData.cs similarity index 96% rename from TaikoLocalServer/Models/OdaiData.cs rename to SharedProject/Models/DanData.cs index 620d3b7..583e8bf 100644 --- a/TaikoLocalServer/Models/OdaiData.cs +++ b/SharedProject/Models/DanData.cs @@ -1,8 +1,8 @@ using System.Text.Json.Serialization; -namespace TaikoLocalServer.Models; +namespace SharedProject.Models; -public class OdaiData +public class DanData { [JsonPropertyName("danId")] public uint DanId { get; set; } diff --git a/SharedProject/Models/Responses/DanBestDataResponse.cs b/SharedProject/Models/Responses/DanBestDataResponse.cs new file mode 100644 index 0000000..933a9d4 --- /dev/null +++ b/SharedProject/Models/Responses/DanBestDataResponse.cs @@ -0,0 +1,6 @@ +namespace SharedProject.Models.Responses; + +public class DanBestDataResponse +{ + public List DanBestDataList { get; set; } = new(); +} \ No newline at end of file diff --git a/TaikoLocalServer/Common/Utils/DanOdaiDataManager.cs b/TaikoLocalServer/Common/Utils/DanOdaiDataManager.cs index 19991e6..111b2d1 100644 --- a/TaikoLocalServer/Common/Utils/DanOdaiDataManager.cs +++ b/TaikoLocalServer/Common/Utils/DanOdaiDataManager.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using System.Text.Json; +using SharedProject.Models; using Swan.Mapping; namespace TaikoLocalServer.Common.Utils; @@ -16,7 +17,7 @@ public class DanOdaiDataManager var filePath = Path.Combine(dataPath, Constants.DAN_DATA_FILE_NAME); var jsonString = File.ReadAllText(filePath); - var result = JsonSerializer.Deserialize>(jsonString); + var result = JsonSerializer.Deserialize>(jsonString); if (result is null) { @@ -25,7 +26,7 @@ public class DanOdaiDataManager OdaiDataList = result.ToImmutableDictionary(data => data.DanId, ToResponseOdaiData); } - private GetDanOdaiResponse.OdaiData ToResponseOdaiData(OdaiData data) + private GetDanOdaiResponse.OdaiData ToResponseOdaiData(DanData data) { var responseOdaiData = new GetDanOdaiResponse.OdaiData { diff --git a/TaikoLocalServer/Controllers/Api/DanBestDataController.cs b/TaikoLocalServer/Controllers/Api/DanBestDataController.cs new file mode 100644 index 0000000..d286cb5 --- /dev/null +++ b/TaikoLocalServer/Controllers/Api/DanBestDataController.cs @@ -0,0 +1,36 @@ +using SharedProject.Models; +using SharedProject.Models.Responses; +using Swan.Mapping; +using TaikoLocalServer.Services.Interfaces; + +namespace TaikoLocalServer.Controllers.Api; + +[ApiController] +[Route("api/[controller]")] +public class DanBestDataController : BaseController +{ + private readonly IDanScoreDatumService danScoreDatumService; + + public DanBestDataController(IDanScoreDatumService danScoreDatumService) { + this.danScoreDatumService = danScoreDatumService; + } + + [HttpGet("{baid}")] + public async Task GetDanBestData(uint baid) + { + var danScores = await danScoreDatumService.GetDanScoreDatumByBaid(baid); + var danDataList = new List(); + + foreach (var danScore in danScores) + { + var danData = danScore.CopyPropertiesToNew(); + danData.DanBestStageDataList = danScore.DanStageScoreData.Select(datum => datum.CopyPropertiesToNew()).ToList(); + danDataList.Add(danData); + } + + return Ok(new DanBestDataResponse + { + DanBestDataList = danDataList + }); + } +} \ No newline at end of file diff --git a/TaikoLocalServer/Properties/launchSettings.json b/TaikoLocalServer/Properties/launchSettings.json index eaf9c09..bfaa94a 100644 --- a/TaikoLocalServer/Properties/launchSettings.json +++ b/TaikoLocalServer/Properties/launchSettings.json @@ -14,7 +14,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:7232;http://localhost:5090", + "applicationUrl": "http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/TaikoLocalServer/TaikoLocalServer.csproj b/TaikoLocalServer/TaikoLocalServer.csproj index 0af6054..2a79ab9 100644 --- a/TaikoLocalServer/TaikoLocalServer.csproj +++ b/TaikoLocalServer/TaikoLocalServer.csproj @@ -45,7 +45,7 @@ - + diff --git a/TaikoWebUI/GlobalUsings.cs b/TaikoWebUI/GlobalUsings.cs new file mode 100644 index 0000000..b6996c5 --- /dev/null +++ b/TaikoWebUI/GlobalUsings.cs @@ -0,0 +1,17 @@ +// Global using directives +global using System.Net.Http; +global using System.Net.Http.Json; +global using Microsoft.AspNetCore.Components; +global using Microsoft.AspNetCore.Components.Forms; +global using Microsoft.AspNetCore.Components.Routing; +global using Microsoft.AspNetCore.Components.Web; +global using Microsoft.AspNetCore.Components.Web.Virtualization; +global using Microsoft.AspNetCore.Components.WebAssembly.Http; +global using MudBlazor; +global using TaikoWebUI; +global using TaikoWebUI.Shared; +global using TaikoWebUI.Services; +global using SharedProject.Models; +global using SharedProject.Models.Requests; +global using SharedProject.Enums; +global using Throw; \ No newline at end of file diff --git a/TaikoWebUI/Pages/Cards.razor b/TaikoWebUI/Pages/Cards.razor index 8f0ae41..1f5df44 100644 --- a/TaikoWebUI/Pages/Cards.razor +++ b/TaikoWebUI/Pages/Cards.razor @@ -1,6 +1,5 @@ -@using SharedProject.Models.Responses -@using TaikoWebUI.Pages.Dialogs -@using SharedProject.Models +@using TaikoWebUI.Pages.Dialogs +@using SharedProject.Models.Responses @inject HttpClient Client @inject IDialogService DialogService diff --git a/TaikoWebUI/Pages/DaniDojo.razor b/TaikoWebUI/Pages/DaniDojo.razor index d1d37ca..fc4c703 100644 --- a/TaikoWebUI/Pages/DaniDojo.razor +++ b/TaikoWebUI/Pages/DaniDojo.razor @@ -1,10 +1,4 @@ -@using TaikoWebUI.Services -@using SharedProject.Models.Responses -@using SharedProject.Models -@using SharedProject.Models.Requests -@using SharedProject.Enums -@using Throw -@inject IGameDataService GameDataService +@inject IGameDataService GameDataService @inject HttpClient Client @page "/Cards/{baid:int}/DaniDojo" @@ -13,10 +7,59 @@

Dani Dojo

Card: @Baid + + + @for (uint i = 1; i <= 19; i++) + { + var danId = i; + var danData = GameDataService.GetDanDataById(danId); + + @foreach (var data in danData.OdaiBorderList) + { + @DanRequirementToString(data) + } + @if (bestDataMap.ContainsKey(danId)) + { + var danBestData = bestDataMap[danId]; + Clear state: @danBestData.ClearState + Best Soul gauge: @danBestData.SoulGaugeTotal + Best Total Combo: @danBestData.ComboCountTotal + + @foreach (var bestStage in danBestData.DanBestStageDataList) + { + var songNumber = bestStage.SongNumber; + var danDataOdaiSong = danData.OdaiSongList[(int)songNumber]; + + Song Number: @songNumber + + Song Name: + @GameDataService.GetMusicNameBySongId(danDataOdaiSong.SongNo) + + Song Difficulty: @((Difficulty)danDataOdaiSong.Level) + + Song play detail
+ Good : @bestStage.GoodCount
+ Ok : @bestStage.OkCount
+ Bad : @bestStage.BadCount
+ Combo : @bestStage.ComboCount
+ Drumroll : @bestStage.DrumrollCount
+ Total hit : @bestStage.TotalHitCount +
+
+ } +
- - - + } + else + { + + This dan course hasn't been played + + } +
+ } +
+
@code { @@ -24,9 +67,9 @@ [Parameter] public int Baid { get; set; } - private SongBestResponse? response; + private DanBestDataResponse? response; - private const string ICON_STYLE = "width:25px; height:25px;"; + private Dictionary bestDataMap = new(); private readonly List breadcrumbs = new() { @@ -36,15 +79,24 @@ protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - response = await Client.GetFromJsonAsync($"api/PlayData/{Baid}"); + response = await Client.GetFromJsonAsync($"api/DanBestData/{Baid}"); response.ThrowIfNull(); - response.SongBestData.Sort((data1, data2) => - { - return GameDataService.GetMusicIndexBySongId(data1.SongId) - .CompareTo(GameDataService.GetMusicIndexBySongId(data2.SongId)); - }); + bestDataMap = response.DanBestDataList.ToDictionary(data => data.DanId); breadcrumbs.Add(new BreadcrumbItem($"Card: {Baid}", href: null, disabled: true)); breadcrumbs.Add(new BreadcrumbItem("Dani Dojo", href: $"/Cards/{Baid}/DaniDojo", disabled: false)); } + + private static string DanRequirementToString(DanData.OdaiBorder data) + { + var danConditionType = (DanConditionType)data.OdaiType; + return (DanBorderType)data.BorderType switch + { + DanBorderType.All => $"{danConditionType}, Pass: {data.RedBorderTotal}, Gold: {data.GoldBorderTotal} ", + DanBorderType.PerSong => $"{danConditionType}, " + + $"Pass 1: {data.RedBorder1}, Pass 2: {data.RedBorder2}, Pass 3: {data.RedBorder3}" + + $"Gold 1: {data.GoldBorder1}, Gold 2: {data.GoldBorder1}, Pass 3: {data.GoldBorder1}", + _ => throw new ArgumentOutOfRangeException() + }; + } } \ No newline at end of file diff --git a/TaikoWebUI/Pages/Dashboard.razor b/TaikoWebUI/Pages/Dashboard.razor index f503c33..ef5573a 100644 --- a/TaikoWebUI/Pages/Dashboard.razor +++ b/TaikoWebUI/Pages/Dashboard.razor @@ -1,50 +1,7 @@ -@using SharedProject.Models.Responses -@using TaikoWebUI.Pages.Dialogs -@using SharedProject.Models -@inject HttpClient Client -@inject NavigationManager UriHelper -@inject IDialogService DialogService - -@page "/" +@page "/"

Dashboard

Welcome to TaikoWebUI! - - - -@code { - private DashboardResponse? response; - - protected override async Task OnInitializedAsync() - { - await base.OnInitializedAsync(); - response = await Client.GetFromJsonAsync("api/Dashboard"); - } - - - private void NavigateToProfile(uint baid) - { - UriHelper.NavigateTo($"/Card/{baid}"); - } - - private async Task DeleteCard(User user) - { - var parameters = new DialogParameters - { - ["user"] = user - }; - - var dialog = DialogService.Show("Delete Card", parameters); - var result = await dialog.Result; - - if (result.Cancelled) - { - return; - } - - response = await Client.GetFromJsonAsync("api/Dashboard"); - } - -} \ No newline at end of file + \ No newline at end of file diff --git a/TaikoWebUI/Pages/Dialogs/CardDeleteConfirmDialog.razor b/TaikoWebUI/Pages/Dialogs/CardDeleteConfirmDialog.razor index c827bfd..86391a0 100644 --- a/TaikoWebUI/Pages/Dialogs/CardDeleteConfirmDialog.razor +++ b/TaikoWebUI/Pages/Dialogs/CardDeleteConfirmDialog.razor @@ -1,5 +1,4 @@ -@using SharedProject.Models -@inject HttpClient Client +@inject HttpClient Client @inject ISnackbar Snackbar diff --git a/TaikoWebUI/Pages/Profile.razor b/TaikoWebUI/Pages/Profile.razor index 18ec3a9..a70d29e 100644 --- a/TaikoWebUI/Pages/Profile.razor +++ b/TaikoWebUI/Pages/Profile.razor @@ -1,6 +1,4 @@ @page "/Cards/{baid:int}/Profile" -@using SharedProject.Enums -@using SharedProject.Models @inject HttpClient Client @@ -113,61 +111,4 @@ -} - -@code { - - [Parameter] - public int Baid { get; set; } - - private UserSetting? response; - - private bool isSavingOptions; - - private readonly string[] speedStrings = - { - "1.0", "1.1", "1.2", "1.3", "1.4", - "1.5", "1.6", "1.7", "1.8", "1.9", - "2.0", "2.5", "3.0", "3.5", "4.0" - }; - - private readonly string[] notePositionStrings = { "-5", "-4", "-3", "-2", "-1", "0", "+1", "+2", "+3", "+4", "+5" }; - - private readonly string[] toneStrings = - { - "Taiko", "Festival", "Dogs & Cats", "Deluxe", - "Drumset", "Tambourine", "Don Wada", "Clapping", - "Conga", "8-Bit", "Heave-ho", "Mecha", - "Bujain", "Rap", "Hosogai", "Akemi", - "Synth Drum", "Shuriken", "Bubble Pop", "Electric Guitar" - }; - - private readonly string[] titlePlateStrings = - { - "Wood", "Rainbow", "Gold", "Purple", - "AI 1", "AI 2", "AI 3", "AI 4" - }; - - private List breadcrumbs = new() - { - new BreadcrumbItem("Cards", href: "/Cards"), - }; - - protected override async Task OnInitializedAsync() - { - await base.OnInitializedAsync(); - isSavingOptions = false; - response = await Client.GetFromJsonAsync($"api/UserSettings/{Baid}"); - - breadcrumbs.Add(new BreadcrumbItem($"Card: {Baid}", href: null, disabled: true)); - breadcrumbs.Add(new BreadcrumbItem("Profile", href: $"/Cards/{Baid}/Profile", disabled: false)); - } - - private async Task SaveOptions() - { - isSavingOptions = true; - await Client.PostAsJsonAsync($"api/UserSettings/{Baid}", response); - isSavingOptions = false; - } - } \ No newline at end of file diff --git a/TaikoWebUI/Pages/Profile.razor.cs b/TaikoWebUI/Pages/Profile.razor.cs new file mode 100644 index 0000000..b646c36 --- /dev/null +++ b/TaikoWebUI/Pages/Profile.razor.cs @@ -0,0 +1,58 @@ +namespace TaikoWebUI.Pages; + +public partial class Profile +{ + [Parameter] + public int Baid { get; set; } + + private UserSetting? response; + + private bool isSavingOptions; + + private readonly string[] speedStrings = + { + "1.0", "1.1", "1.2", "1.3", "1.4", + "1.5", "1.6", "1.7", "1.8", "1.9", + "2.0", "2.5", "3.0", "3.5", "4.0" + }; + + private readonly string[] notePositionStrings = { "-5", "-4", "-3", "-2", "-1", "0", "+1", "+2", "+3", "+4", "+5" }; + + private readonly string[] toneStrings = + { + "Taiko", "Festival", "Dogs & Cats", "Deluxe", + "Drumset", "Tambourine", "Don Wada", "Clapping", + "Conga", "8-Bit", "Heave-ho", "Mecha", + "Bujain", "Rap", "Hosogai", "Akemi", + "Synth Drum", "Shuriken", "Bubble Pop", "Electric Guitar" + }; + + private readonly string[] titlePlateStrings = + { + "Wood", "Rainbow", "Gold", "Purple", + "AI 1", "AI 2", "AI 3", "AI 4" + }; + + private List breadcrumbs = new() + { + new BreadcrumbItem("Cards", href: "/Cards"), + }; + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + isSavingOptions = false; + response = await Client.GetFromJsonAsync($"api/UserSettings/{Baid}"); + + breadcrumbs.Add(new BreadcrumbItem($"Card: {Baid}", href: null, disabled: true)); + breadcrumbs.Add(new BreadcrumbItem("Profile", href: $"/Cards/{Baid}/Profile", disabled: false)); + } + + private async Task SaveOptions() + { + isSavingOptions = true; + await Client.PostAsJsonAsync($"api/UserSettings/{Baid}", response); + isSavingOptions = false; + } + +} \ No newline at end of file diff --git a/TaikoWebUI/Pages/TaikoMode.razor b/TaikoWebUI/Pages/TaikoMode.razor index 8858c5a..fcb4d98 100644 --- a/TaikoWebUI/Pages/TaikoMode.razor +++ b/TaikoWebUI/Pages/TaikoMode.razor @@ -1,10 +1,4 @@ -@using TaikoWebUI.Services -@using SharedProject.Models.Responses -@using SharedProject.Models -@using SharedProject.Models.Requests -@using SharedProject.Enums -@using Throw -@inject IGameDataService GameDataService +@inject IGameDataService GameDataService @inject HttpClient Client @page "/Cards/{baid:int}/TaikoMode" @@ -31,75 +25,78 @@ { @if (difficulty is not Difficulty.None) { - - @if (@response.SongBestData.Where(data => data.Difficulty == difficulty).Count() > 0) + @if (songBestDataMap.ContainsKey(difficulty)) { - - - - - - - - @GameDataService.GetMusicNameBySongId(context.Item.SongId) - @GameDataService.GetMusicArtistBySongId(context.Item.SongId) - - - - - - - - - - - - - - - - @GetGenreTitle(GameDataService.GetMusicGenreBySongId(context.Item.SongId)) - - - - - - - - @(context.Item.BestCrown) - - - - - - @if (context.Item.BestScoreRank is not ScoreRank.None) - { - - @(context.Item.BestScoreRank) + + + + + + + + @GameDataService.GetMusicNameBySongId(context.Item.SongId) + @GameDataService.GetMusicArtistBySongId(context.Item.SongId) + + + + + + + + + + + + + + + + @GetGenreTitle(GameDataService.GetMusicGenreBySongId(context.Item.SongId)) + + + + + + + + @(context.Item.BestCrown) - } - - - - - - - - - - - - - - } else { + + + + + @if (context.Item.BestScoreRank is not ScoreRank.None) + { + + @(context.Item.BestScoreRank) + + } + + + + + + + + + + + + + + } + else + { @@ -108,134 +105,10 @@ } - } } } - - - -@code { - - [Parameter] - public int Baid { get; set; } - - private SongBestResponse? response; - - private const string ICON_STYLE = "width:25px; height:25px;"; - - private readonly List breadcrumbs = new() - { - new BreadcrumbItem("Cards", href: "/Cards"), - }; - - protected override async Task OnInitializedAsync() - { - await base.OnInitializedAsync(); - response = await Client.GetFromJsonAsync($"api/PlayData/{Baid}"); - response.ThrowIfNull(); - response.SongBestData.Sort((data1, data2) => - { - return GameDataService.GetMusicIndexBySongId(data1.SongId) - .CompareTo(GameDataService.GetMusicIndexBySongId(data2.SongId)); - }); - - breadcrumbs.Add(new BreadcrumbItem($"Card: {Baid}", href: null, disabled: true)); - breadcrumbs.Add(new BreadcrumbItem("Taiko Mode", href: $"/Cards/{Baid}/TaikoMode", disabled: false)); - } - - private async Task OnFavoriteToggled(SongBestData data) - { - var request = new SetFavoriteRequest - { - Baid = (uint)Baid, - IsFavorite = !data.IsFavorite, - SongId = data.SongId - }; - var result = await Client.PostAsJsonAsync("api/FavoriteSongs", request); - if (result.IsSuccessStatusCode) - { - data.IsFavorite = !data.IsFavorite; - } - } - - private static string GetCrownText(CrownType crown) - { - return crown switch - { - CrownType.None => "Fail", - CrownType.Clear => "Clear", - CrownType.Gold => "Full Combo", - CrownType.Dondaful => "Donderful Combo", - _ => "" - }; - } - - private static string GetRankText(ScoreRank rank) - { - return rank switch - { - ScoreRank.White => "Stylish", - ScoreRank.Bronze => "Stylish", - ScoreRank.Silver => "Stylish", - ScoreRank.Gold => "Graceful", - ScoreRank.Sakura => "Graceful", - ScoreRank.Purple => "Graceful", - ScoreRank.Dondaful => "Top Class", - _ => "" - }; - } - - private static string GetDifficultyTitle(Difficulty difficulty) - { - return difficulty switch - { - Difficulty.Easy => "Easy", - Difficulty.Normal => "Normal", - Difficulty.Hard => "Hard", - Difficulty.Oni => "Oni", - Difficulty.UraOni => "Ura Oni", - _ => "" - }; - } - - private static string GetDifficultyIcon(Difficulty difficulty) - { - return $"{difficulty}"; - } - - private static string GetGenreTitle(SongGenre genre) - { - return genre switch - { - SongGenre.Pop => "Pop", - SongGenre.Anime => "Anime", - SongGenre.Kids => "Kids", - SongGenre.Vocaloid => "Vocaloid", - SongGenre.GameMusic => "Game Music", - SongGenre.NamcoOriginal => "NAMCO Original", - SongGenre.Variety => "Variety", - SongGenre.Classical => "Classical", - _ => "" - }; - } - - private static string GetGenreStyle(SongGenre genre) - { - return genre switch - { - SongGenre.Pop => "background: #42c0d2; color: #fff", - SongGenre.Anime => "background: #ff90d3; color: #fff", - SongGenre.Kids => "background: #fec000; color: #fff", - SongGenre.Vocaloid => "background: #ddd", - SongGenre.GameMusic => "background: #cc8aea; color: #fff", - SongGenre.NamcoOriginal => "background: #ff7027; color: #fff", - SongGenre.Variety => "background: #1dc83b; color: #fff", - SongGenre.Classical => "background: #bfa356", - _ => "" - }; - } -} \ No newline at end of file + \ No newline at end of file diff --git a/TaikoWebUI/Pages/TaikoMode.razor.cs b/TaikoWebUI/Pages/TaikoMode.razor.cs new file mode 100644 index 0000000..bfc3cfe --- /dev/null +++ b/TaikoWebUI/Pages/TaikoMode.razor.cs @@ -0,0 +1,132 @@ +using SharedProject.Models.Responses; + +namespace TaikoWebUI.Pages; + +public partial class TaikoMode +{ + [Parameter] + public int Baid { get; set; } + + private const string IconStyle = "width:25px; height:25px;"; + + private SongBestResponse? response; + + private Dictionary> songBestDataMap = new(); + + private readonly List breadcrumbs = new() + { + new BreadcrumbItem("Cards", href: "/Cards"), + }; + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + response = await Client.GetFromJsonAsync($"api/PlayData/{Baid}"); + response.ThrowIfNull(); + songBestDataMap = response.SongBestData.GroupBy(data => data.Difficulty) + .ToDictionary(data => data.Key, + data => data.ToList()); + foreach (var songBestDataList in songBestDataMap.Values) + { + songBestDataList.Sort((data1, data2) => GameDataService.GetMusicIndexBySongId(data1.SongId) + .CompareTo(GameDataService.GetMusicIndexBySongId(data2.SongId))); + } + + + breadcrumbs.Add(new BreadcrumbItem($"Card: {Baid}", href: null, disabled: true)); + breadcrumbs.Add(new BreadcrumbItem("Taiko Mode", href: $"/Cards/{Baid}/TaikoMode", disabled: false)); + } + + private async Task OnFavoriteToggled(SongBestData data) + { + var request = new SetFavoriteRequest + { + Baid = (uint)Baid, + IsFavorite = !data.IsFavorite, + SongId = data.SongId + }; + var result = await Client.PostAsJsonAsync("api/FavoriteSongs", request); + if (result.IsSuccessStatusCode) + { + data.IsFavorite = !data.IsFavorite; + } + } + + private static string GetCrownText(CrownType crown) + { + return crown switch + { + CrownType.None => "Fail", + CrownType.Clear => "Clear", + CrownType.Gold => "Full Combo", + CrownType.Dondaful => "Donderful Combo", + _ => "" + }; + } + + private static string GetRankText(ScoreRank rank) + { + return rank switch + { + ScoreRank.White => "Stylish", + ScoreRank.Bronze => "Stylish", + ScoreRank.Silver => "Stylish", + ScoreRank.Gold => "Graceful", + ScoreRank.Sakura => "Graceful", + ScoreRank.Purple => "Graceful", + ScoreRank.Dondaful => "Top Class", + _ => "" + }; + } + + private static string GetDifficultyTitle(Difficulty difficulty) + { + return difficulty switch + { + Difficulty.Easy => "Easy", + Difficulty.Normal => "Normal", + Difficulty.Hard => "Hard", + Difficulty.Oni => "Oni", + Difficulty.UraOni => "Ura Oni", + _ => "" + }; + } + + private static string GetDifficultyIcon(Difficulty difficulty) + { + return $"{difficulty}"; + } + + private static string GetGenreTitle(SongGenre genre) + { + return genre switch + { + SongGenre.Pop => "Pop", + SongGenre.Anime => "Anime", + SongGenre.Kids => "Kids", + SongGenre.Vocaloid => "Vocaloid", + SongGenre.GameMusic => "Game Music", + SongGenre.NamcoOriginal => "NAMCO Original", + SongGenre.Variety => "Variety", + SongGenre.Classical => "Classical", + _ => "" + }; + } + + private static string GetGenreStyle(SongGenre genre) + { + return genre switch + { + SongGenre.Pop => "background: #42c0d2; color: #fff", + SongGenre.Anime => "background: #ff90d3; color: #fff", + SongGenre.Kids => "background: #fec000; color: #fff", + SongGenre.Vocaloid => "background: #ddd", + SongGenre.GameMusic => "background: #cc8aea; color: #fff", + SongGenre.NamcoOriginal => "background: #ff7027; color: #fff", + SongGenre.Variety => "background: #1dc83b; color: #fff", + SongGenre.Classical => "background: #bfa356", + _ => "" + }; + } +} + diff --git a/TaikoWebUI/Services/GameDataService.cs b/TaikoWebUI/Services/GameDataService.cs index 7a7f94a..a04832a 100644 --- a/TaikoWebUI/Services/GameDataService.cs +++ b/TaikoWebUI/Services/GameDataService.cs @@ -1,6 +1,7 @@ using System.Collections.Immutable; using System.Net.Http.Json; using SharedProject.Enums; +using SharedProject.Models; using TaikoWebUI.Shared.Models; using Throw; @@ -12,6 +13,8 @@ public class GameDataService : IGameDataService private readonly Dictionary musicMap = new(); + private ImmutableDictionary danMap = null!; + public GameDataService(HttpClient client) { this.client = client; @@ -22,10 +25,14 @@ public class GameDataService : IGameDataService var musicInfo = await client.GetFromJsonAsync($"{dataBaseUrl}/data/musicinfo.json"); var wordList = await client.GetFromJsonAsync($"{dataBaseUrl}/data/wordlist.json"); var musicOrder = await client.GetFromJsonAsync($"{dataBaseUrl}/data/music_order.json"); + var danData = await client.GetFromJsonAsync>($"{dataBaseUrl}/data/dan_data.json"); musicInfo.ThrowIfNull(); wordList.ThrowIfNull(); musicOrder.ThrowIfNull(); + danData.ThrowIfNull(); + + danMap = danData.ToImmutableDictionary(data => data.DanId); // To prevent duplicate entries in wordlist var dict = wordList.WordListEntries.GroupBy(entry => entry.Key) @@ -79,5 +86,9 @@ public class GameDataService : IGameDataService { return musicMap.TryGetValue(songId, out var musicDetail) ? musicDetail.Index : int.MaxValue; } + public DanData GetDanDataById(uint danId) + { + return danMap.GetValueOrDefault(danId, new DanData()); + } } \ No newline at end of file diff --git a/TaikoWebUI/Services/IGameDataService.cs b/TaikoWebUI/Services/IGameDataService.cs index fa8d49f..5f80fce 100644 --- a/TaikoWebUI/Services/IGameDataService.cs +++ b/TaikoWebUI/Services/IGameDataService.cs @@ -1,4 +1,5 @@ using SharedProject.Enums; +using SharedProject.Models; using TaikoWebUI.Shared.Models; namespace TaikoWebUI.Services; @@ -14,4 +15,6 @@ public interface IGameDataService public SongGenre GetMusicGenreBySongId(uint songId); public int GetMusicIndexBySongId(uint songId); + + public DanData GetDanDataById(uint danId); } \ No newline at end of file diff --git a/TaikoWebUI/_Imports.razor b/TaikoWebUI/_Imports.razor index 6a7c60c..8814563 100644 --- a/TaikoWebUI/_Imports.razor +++ b/TaikoWebUI/_Imports.razor @@ -8,4 +8,10 @@ @using Microsoft.JSInterop @using MudBlazor @using TaikoWebUI -@using TaikoWebUI.Shared \ No newline at end of file +@using TaikoWebUI.Shared +@using TaikoWebUI.Services +@using SharedProject.Models.Responses +@using SharedProject.Models +@using SharedProject.Models.Requests +@using SharedProject.Enums +@using Throw \ No newline at end of file diff --git a/TaikoWebUI/wwwroot/appsettings.Development.json b/TaikoWebUI/wwwroot/appsettings.Development.json index cbe7f7d..ce35693 100644 --- a/TaikoWebUI/wwwroot/appsettings.Development.json +++ b/TaikoWebUI/wwwroot/appsettings.Development.json @@ -1,3 +1,3 @@ { - "DataBaseUrl": "https://localhost:44398" + "DataBaseUrl": "http://localhost:5000" } \ No newline at end of file