Add primitive dan data page
This commit is contained in:
parent
809a2d72f6
commit
a147b82ecc
7
SharedProject/Enums/DanBorderType.cs
Normal file
7
SharedProject/Enums/DanBorderType.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace SharedProject.Enums;
|
||||
|
||||
public enum DanBorderType
|
||||
{
|
||||
All = 1,
|
||||
PerSong = 2
|
||||
}
|
13
SharedProject/Enums/DanConditionType.cs
Normal file
13
SharedProject/Enums/DanConditionType.cs
Normal file
@ -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
|
||||
}
|
16
SharedProject/Models/DanBestData.cs
Normal file
16
SharedProject/Models/DanBestData.cs
Normal file
@ -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<DanBestStageData> DanBestStageDataList { get; set; } = new();
|
||||
}
|
20
SharedProject/Models/DanBestStageData.cs
Normal file
20
SharedProject/Models/DanBestStageData.cs
Normal file
@ -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; }
|
||||
}
|
@ -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; }
|
6
SharedProject/Models/Responses/DanBestDataResponse.cs
Normal file
6
SharedProject/Models/Responses/DanBestDataResponse.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace SharedProject.Models.Responses;
|
||||
|
||||
public class DanBestDataResponse
|
||||
{
|
||||
public List<DanBestData> DanBestDataList { get; set; } = new();
|
||||
}
|
@ -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<List<OdaiData>>(jsonString);
|
||||
var result = JsonSerializer.Deserialize<List<DanData>>(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
|
||||
{
|
||||
|
36
TaikoLocalServer/Controllers/Api/DanBestDataController.cs
Normal file
36
TaikoLocalServer/Controllers/Api/DanBestDataController.cs
Normal file
@ -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<DanBestDataController>
|
||||
{
|
||||
private readonly IDanScoreDatumService danScoreDatumService;
|
||||
|
||||
public DanBestDataController(IDanScoreDatumService danScoreDatumService) {
|
||||
this.danScoreDatumService = danScoreDatumService;
|
||||
}
|
||||
|
||||
[HttpGet("{baid}")]
|
||||
public async Task<IActionResult> GetDanBestData(uint baid)
|
||||
{
|
||||
var danScores = await danScoreDatumService.GetDanScoreDatumByBaid(baid);
|
||||
var danDataList = new List<DanBestData>();
|
||||
|
||||
foreach (var danScore in danScores)
|
||||
{
|
||||
var danData = danScore.CopyPropertiesToNew<DanBestData>();
|
||||
danData.DanBestStageDataList = danScore.DanStageScoreData.Select(datum => datum.CopyPropertiesToNew<DanBestStageData>()).ToList();
|
||||
danDataList.Add(danData);
|
||||
}
|
||||
|
||||
return Ok(new DanBestDataResponse
|
||||
{
|
||||
DanBestDataList = danDataList
|
||||
});
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedProject\SharedProject.csproj" />
|
||||
<ProjectReference Include="..\TaikoWebUI\TaikoWebUI.csproj"/>
|
||||
<ProjectReference Include="..\TaikoWebUI\TaikoWebUI.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
17
TaikoWebUI/GlobalUsings.cs
Normal file
17
TaikoWebUI/GlobalUsings.cs
Normal file
@ -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;
|
@ -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
|
||||
|
||||
|
@ -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 @@
|
||||
|
||||
<h1>Dani Dojo</h1>
|
||||
<MudText Typo="Typo.caption">Card: @Baid</MudText>
|
||||
<MudContainer>
|
||||
<MudTabs>
|
||||
@for (uint i = 1; i <= 19; i++)
|
||||
{
|
||||
var danId = i;
|
||||
var danData = GameDataService.GetDanDataById(danId);
|
||||
<MudTabPanel Text="@danData.Title">
|
||||
@foreach (var data in danData.OdaiBorderList)
|
||||
{
|
||||
<MudText>@DanRequirementToString(data)</MudText>
|
||||
}
|
||||
@if (bestDataMap.ContainsKey(danId))
|
||||
{
|
||||
var danBestData = bestDataMap[danId];
|
||||
<MudText>Clear state: @danBestData.ClearState </MudText>
|
||||
<MudText>Best Soul gauge: @danBestData.SoulGaugeTotal </MudText>
|
||||
<MudText>Best Total Combo: @danBestData.ComboCountTotal </MudText>
|
||||
<MudGrid>
|
||||
@foreach (var bestStage in danBestData.DanBestStageDataList)
|
||||
{
|
||||
var songNumber = bestStage.SongNumber;
|
||||
var danDataOdaiSong = danData.OdaiSongList[(int)songNumber];
|
||||
<MudItem>
|
||||
<MudText>Song Number: @songNumber</MudText>
|
||||
<MudText>
|
||||
Song Name:
|
||||
@GameDataService.GetMusicNameBySongId(danDataOdaiSong.SongNo)
|
||||
</MudText>
|
||||
<MudText>Song Difficulty: @((Difficulty)danDataOdaiSong.Level)</MudText>
|
||||
<MudText>
|
||||
Song play detail <br/>
|
||||
Good : @bestStage.GoodCount <br/>
|
||||
Ok : @bestStage.OkCount <br/>
|
||||
Bad : @bestStage.BadCount <br/>
|
||||
Combo : @bestStage.ComboCount<br/>
|
||||
Drumroll : @bestStage.DrumrollCount <br/>
|
||||
Total hit : @bestStage.TotalHitCount
|
||||
</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
|
||||
<MudGrid Class="my-8">
|
||||
|
||||
</MudGrid>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText>
|
||||
This dan course hasn't been played
|
||||
</MudText>
|
||||
}
|
||||
</MudTabPanel>
|
||||
}
|
||||
</MudTabs>
|
||||
</MudContainer>
|
||||
|
||||
|
||||
@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<uint, DanBestData> bestDataMap = new();
|
||||
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new()
|
||||
{
|
||||
@ -36,15 +79,24 @@
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
response = await Client.GetFromJsonAsync<SongBestResponse>($"api/PlayData/{Baid}");
|
||||
response = await Client.GetFromJsonAsync<DanBestDataResponse>($"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()
|
||||
};
|
||||
}
|
||||
}
|
@ -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 "/"
|
||||
|
||||
<h1>Dashboard</h1>
|
||||
|
||||
<MudText Class="mt-8">
|
||||
Welcome to TaikoWebUI!
|
||||
</MudText>
|
||||
|
||||
|
||||
@code {
|
||||
private DashboardResponse? response;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
response = await Client.GetFromJsonAsync<DashboardResponse>("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<CardDeleteConfirmDialog>("Delete Card", parameters);
|
||||
var result = await dialog.Result;
|
||||
|
||||
if (result.Cancelled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
response = await Client.GetFromJsonAsync<DashboardResponse>("api/Dashboard");
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
@using SharedProject.Models
|
||||
@inject HttpClient Client
|
||||
@inject HttpClient Client
|
||||
@inject ISnackbar Snackbar
|
||||
|
||||
<MudDialog>
|
||||
|
@ -1,6 +1,4 @@
|
||||
@page "/Cards/{baid:int}/Profile"
|
||||
@using SharedProject.Enums
|
||||
@using SharedProject.Models
|
||||
@inject HttpClient Client
|
||||
|
||||
<MudBreadcrumbs Items="breadcrumbs" Class="px-0"></MudBreadcrumbs>
|
||||
@ -114,60 +112,3 @@
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
}
|
||||
|
||||
@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<BreadcrumbItem> breadcrumbs = new()
|
||||
{
|
||||
new BreadcrumbItem("Cards", href: "/Cards"),
|
||||
};
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
isSavingOptions = false;
|
||||
response = await Client.GetFromJsonAsync<UserSetting>($"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;
|
||||
}
|
||||
|
||||
}
|
58
TaikoWebUI/Pages/Profile.razor.cs
Normal file
58
TaikoWebUI/Pages/Profile.razor.cs
Normal file
@ -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<BreadcrumbItem> breadcrumbs = new()
|
||||
{
|
||||
new BreadcrumbItem("Cards", href: "/Cards"),
|
||||
};
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
isSavingOptions = false;
|
||||
response = await Client.GetFromJsonAsync<UserSetting>($"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;
|
||||
}
|
||||
|
||||
}
|
@ -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"
|
||||
@ -33,73 +27,76 @@
|
||||
{
|
||||
<MudTabPanel Text="@GetDifficultyTitle(difficulty)"
|
||||
Icon="@GetDifficultyIcon(difficulty)">
|
||||
@if (@response.SongBestData.Where(data => data.Difficulty == difficulty).Count() > 0)
|
||||
@if (songBestDataMap.ContainsKey(difficulty))
|
||||
{
|
||||
<MudDataGrid Items="@response.SongBestData.Where(data => data.Difficulty == difficulty)"
|
||||
ColumnResizeMode="ResizeMode.Container" RowsPerPage="25" Elevation="0">
|
||||
<Columns>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Song" StickyLeft="true" Class="clm-row-large">
|
||||
<CellTemplate>
|
||||
<MudGrid Justify="Justify.Center">
|
||||
<MudItem xs="10">
|
||||
<MudStack Spacing="0">
|
||||
<MudText Typo="Typo.body2" Style="font-weight:bold">@GameDataService.GetMusicNameBySongId(context.Item.SongId)</MudText>
|
||||
<MudText Typo="Typo.caption">@GameDataService.GetMusicArtistBySongId(context.Item.SongId)</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="2">
|
||||
<MudStack Justify="Justify.Center" AlignItems="AlignItems.End" Style="height:100%">
|
||||
<MudTooltip Text="@(context.Item.IsFavorite ? "Remove from favorites" : "Add to favorites")" Arrow="true" Placement="Placement.Top">
|
||||
<MudToggleIconButton Toggled="@context.Item.IsFavorite"
|
||||
ToggledChanged="@(async () => await OnFavoriteToggled(context.Item))"
|
||||
Icon="@Icons.Material.Filled.FavoriteBorder" Color="@Color.Secondary"
|
||||
ToggledIcon="@Icons.Material.Filled.Favorite" ToggledColor="@Color.Secondary"
|
||||
Size="Size.Small"
|
||||
ToggledSize="Size.Small"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Genre" Sortable="false">
|
||||
<CellTemplate>
|
||||
<MudChip Style="@GetGenreStyle(GameDataService.GetMusicGenreBySongId(context.Item.SongId))"
|
||||
Size="Size.Small">
|
||||
@GetGenreTitle(GameDataService.GetMusicGenreBySongId(context.Item.SongId))
|
||||
</MudChip>
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.BestScore)" Title="Best Score"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.BestCrown)" Title="Best Crown">
|
||||
<CellTemplate>
|
||||
<MudTooltip Text="@(GetCrownText(context.Item.BestCrown))" Arrow="true" Placement="Placement.Top">
|
||||
<img src="@($"/images/crown_{context.Item.BestCrown}.png")" alt="@(context.Item.BestCrown)" style="@ICON_STYLE"/>
|
||||
</MudTooltip>
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.BestScoreRank)" Title="Best Rank" Sortable="false">
|
||||
<CellTemplate>
|
||||
@if (context.Item.BestScoreRank is not ScoreRank.None)
|
||||
{
|
||||
<MudTooltip Text="@(GetRankText(context.Item.BestScoreRank))" Arrow="true" Placement="Placement.Top">
|
||||
<img src="@($"/images/rank_{context.Item.BestScoreRank}.png")" alt="@(context.Item.BestScoreRank)" style="@ICON_STYLE"/>
|
||||
<MudDataGrid Items="@songBestDataMap[difficulty]"
|
||||
ColumnResizeMode="ResizeMode.Container" RowsPerPage="25" Elevation="0">
|
||||
<Columns>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Song" StickyLeft="true" Class="clm-row-large">
|
||||
<CellTemplate>
|
||||
<MudGrid Justify="Justify.Center">
|
||||
<MudItem xs="10">
|
||||
<MudStack Spacing="0">
|
||||
<MudText Typo="Typo.body2" Style="font-weight:bold">@GameDataService.GetMusicNameBySongId(context.Item.SongId)</MudText>
|
||||
<MudText Typo="Typo.caption">@GameDataService.GetMusicArtistBySongId(context.Item.SongId)</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="2">
|
||||
<MudStack Justify="Justify.Center" AlignItems="AlignItems.End" Style="height:100%">
|
||||
<MudTooltip Text="@(context.Item.IsFavorite ? "Remove from favorites" : "Add to favorites")" Arrow="true" Placement="Placement.Top">
|
||||
<MudToggleIconButton Toggled="@context.Item.IsFavorite"
|
||||
ToggledChanged="@(async () => await OnFavoriteToggled(context.Item))"
|
||||
Icon="@Icons.Material.Filled.FavoriteBorder" Color="@Color.Secondary"
|
||||
ToggledIcon="@Icons.Material.Filled.Favorite" ToggledColor="@Color.Secondary"
|
||||
Size="Size.Small"
|
||||
ToggledSize="Size.Small"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Genre"
|
||||
Sortable="false" Filterable="true">
|
||||
<CellTemplate>
|
||||
<MudChip Style="@GetGenreStyle(GameDataService.GetMusicGenreBySongId(context.Item.SongId))"
|
||||
Size="Size.Small">
|
||||
@GetGenreTitle(GameDataService.GetMusicGenreBySongId(context.Item.SongId))
|
||||
</MudChip>
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.BestScore)" Title="Best Score"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.BestCrown)" Title="Best Crown">
|
||||
<CellTemplate>
|
||||
<MudTooltip Text="@(GetCrownText(context.Item.BestCrown))" Arrow="true" Placement="Placement.Top">
|
||||
<img src="@($"/images/crown_{context.Item.BestCrown}.png")" alt="@(context.Item.BestCrown)" style="@IconStyle"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.GoodCount)" Title="Good" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.OkCount)" Title="Ok" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.MissCount)" Title="Bad" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.DrumrollCount)" Title="Drum Roll" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.ComboCount)" Title="Max Combo" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.LastPlayTime)" Title="Last Played"/>
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="SongBestData"/>
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
} else {
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.BestScoreRank)" Title="Best Rank" Sortable="false">
|
||||
<CellTemplate>
|
||||
@if (context.Item.BestScoreRank is not ScoreRank.None)
|
||||
{
|
||||
<MudTooltip Text="@(GetRankText(context.Item.BestScoreRank))" Arrow="true" Placement="Placement.Top">
|
||||
<img src="@($"/images/rank_{context.Item.BestScoreRank}.png")" alt="@(context.Item.BestScoreRank)" style="@IconStyle"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
</CellTemplate>
|
||||
</Column>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.GoodCount)" Title="Good" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.OkCount)" Title="Ok" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.MissCount)" Title="Bad" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.DrumrollCount)" Title="Drum Roll" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.ComboCount)" Title="Max Combo" Sortable="false"/>
|
||||
<Column T="SongBestData" Field="@nameof(SongBestData.LastPlayTime)" Title="Last Played"/>
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="SongBestData"/>
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudGrid>
|
||||
<MudItem xs="12">
|
||||
<MudText Align="Align.Center" Class="my-8">
|
||||
@ -108,7 +105,6 @@
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
}
|
||||
|
||||
</MudTabPanel>
|
||||
}
|
||||
}
|
||||
@ -116,126 +112,3 @@
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public int Baid { get; set; }
|
||||
|
||||
private SongBestResponse? response;
|
||||
|
||||
private const string ICON_STYLE = "width:25px; height:25px;";
|
||||
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new()
|
||||
{
|
||||
new BreadcrumbItem("Cards", href: "/Cards"),
|
||||
};
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
response = await Client.GetFromJsonAsync<SongBestResponse>($"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 $"<image href='/images/difficulty_{difficulty}.png' alt='{difficulty}' width='24' height='24'/>";
|
||||
}
|
||||
|
||||
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",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
}
|
132
TaikoWebUI/Pages/TaikoMode.razor.cs
Normal file
132
TaikoWebUI/Pages/TaikoMode.razor.cs
Normal file
@ -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<Difficulty, List<SongBestData>> songBestDataMap = new();
|
||||
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new()
|
||||
{
|
||||
new BreadcrumbItem("Cards", href: "/Cards"),
|
||||
};
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
response = await Client.GetFromJsonAsync<SongBestResponse>($"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 $"<image href='/images/difficulty_{difficulty}.png' alt='{difficulty}' width='24' height='24'/>";
|
||||
}
|
||||
|
||||
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",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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<uint, MusicDetail> musicMap = new();
|
||||
|
||||
private ImmutableDictionary<uint, DanData> danMap = null!;
|
||||
|
||||
public GameDataService(HttpClient client)
|
||||
{
|
||||
this.client = client;
|
||||
@ -22,10 +25,14 @@ public class GameDataService : IGameDataService
|
||||
var musicInfo = await client.GetFromJsonAsync<MusicInfo>($"{dataBaseUrl}/data/musicinfo.json");
|
||||
var wordList = await client.GetFromJsonAsync<WordList>($"{dataBaseUrl}/data/wordlist.json");
|
||||
var musicOrder = await client.GetFromJsonAsync<MusicOrder>($"{dataBaseUrl}/data/music_order.json");
|
||||
var danData = await client.GetFromJsonAsync<List<DanData>>($"{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());
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -9,3 +9,9 @@
|
||||
@using MudBlazor
|
||||
@using TaikoWebUI
|
||||
@using TaikoWebUI.Shared
|
||||
@using TaikoWebUI.Services
|
||||
@using SharedProject.Models.Responses
|
||||
@using SharedProject.Models
|
||||
@using SharedProject.Models.Requests
|
||||
@using SharedProject.Enums
|
||||
@using Throw
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"DataBaseUrl": "https://localhost:44398"
|
||||
"DataBaseUrl": "http://localhost:5000"
|
||||
}
|
Loading…
Reference in New Issue
Block a user