1
0
mirror of synced 2024-11-23 22:41:01 +01:00

Add song genre

Add tabs for play result
Reformat game data manager
This commit is contained in:
asesidaa 2022-09-10 23:45:18 +08:00
parent f5bb98d5da
commit 62d0e6b4d7
10 changed files with 179 additions and 73 deletions

View File

@ -0,0 +1,13 @@
namespace SharedProject.Enums;
public enum SongGenre
{
Pop = 0,
Anime = 1,
Kids = 2,
Vocaloid = 3,
GameMusic = 4,
NamcoOriginal = 5,
Variety = 7,
Classical = 8
}

View File

@ -1,2 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=musicinfo/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=musicinfo/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Namco/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Vocaloid/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -3,6 +3,7 @@
@using SharedProject.Models
@using SharedProject.Models.Requests
@using SharedProject.Enums
@using Throw
@inject IGameDataService GameDataService
@inject HttpClient Client
@ -14,65 +15,72 @@
<MudText Typo="Typo.caption">Card: @Baid</MudText>
<MudGrid Class="my-8">
@if (response is null)
{
<MudItem xs="12">
<MudText Align="Align.Center">
No data.
</MudText>
</MudItem>
}
else
{
<MudItem xs="12">
<MudDataGrid Items="@response.SongBestData">
<Columns>
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Song">
<CellTemplate>
<MudText Typo="Typo.body2" Style="font-weight:bold">@GameDataService.GetMusicNameBySongId(context.Item.SongId)</MudText>
<MudText Typo="Typo.caption">@GameDataService.GetMusicArtistBySongId(context.Item.SongId)</MudText>
</CellTemplate>
</Column>
<Column T="SongBestData" Field="@nameof(SongBestData.Difficulty)" Title="Difficulty">
<CellTemplate>
<MudTooltip Text="@(context.Item.Difficulty.ToString())" Arrow="true" Placement="Placement.Top">
<img src="@($"/images/{context.Item.Difficulty}.png")" alt="@(context.Item.Difficulty)" style="@ICON_STYLE" />
</MudTooltip>
</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" />
<Column T="SongBestData" Field="@nameof(SongBestData.BestRate)" Title="Best Rate"/>
<Column T="SongBestData" Field="@nameof(SongBestData.GoodCount)" Title="Good"/>
<Column T="SongBestData" Field="@nameof(SongBestData.OkCount)" Title="Ok"/>
<Column T="SongBestData" Field="@nameof(SongBestData.MissCount)" Title="Miss"/>
<Column T="SongBestData" Field="@nameof(SongBestData.ComboCount)" Title="Max Combo"/>
<Column T="SongBestData" Field="@nameof(SongBestData.DrumrollCount)" Title="Drum Rolls"/>
<Column T="SongBestData" Field="@nameof(SongBestData.HitCount)" Title="Hit"/>
<Column T="SongBestData" Field="@nameof(SongBestData.IsFavorite)" Title="Favorite">
<CellTemplate>
<MudToggleIconButton Toggled="@context.Item.IsFavorite"
ToggledChanged="@(async () => await OnFavoriteToggled(context.Item))"
Icon="@Icons.Material.Filled.FavoriteBorder" Color="@Color.Secondary"
Title="Add to favorites"
ToggledIcon="@Icons.Material.Filled.Favorite" ToggledColor="@Color.Secondary"
ToggledTitle="Remove from favorites"/>
</CellTemplate>
</Column>
</Columns>
<PagerContent>
<MudDataGridPager T="SongBestData"/>
</PagerContent>
</MudDataGrid>
</MudItem>
}
@if (response is null)
{
<MudItem xs="12">
<MudText Align="Align.Center">
No data.
</MudText>
</MudItem>
}
else
{
<MudItem xs="12">
<MudTabs Elevation="2" Rounded="true" ApplyEffectsToContainer="true" PanelClass="pa-6">
@foreach (var genre in Enum.GetValues<SongGenre>())
{
<MudTabPanel Text="@genre.ToString()">
<MudDataGrid Items="@response.SongBestData.Where(data => GameDataService.GetMusicGenreBySongId(data.SongId) == genre)">
<Columns>
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Song">
<CellTemplate>
<MudText Typo="Typo.body2" Style="font-weight:bold">@GameDataService.GetMusicNameBySongId(context.Item.SongId)</MudText>
<MudText Typo="Typo.caption">@GameDataService.GetMusicArtistBySongId(context.Item.SongId)</MudText>
</CellTemplate>
</Column>
<Column T="SongBestData" Field="@nameof(SongBestData.Difficulty)" Title="Difficulty">
<CellTemplate>
<MudTooltip Text="@(context.Item.Difficulty.ToString())" Arrow="true" Placement="Placement.Top">
<img src="@($"/images/{context.Item.Difficulty}.png")" alt="@(context.Item.Difficulty)" style="@ICON_STYLE"/>
</MudTooltip>
</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"/>
<Column T="SongBestData" Field="@nameof(SongBestData.BestRate)" Title="Best Rate"/>
<Column T="SongBestData" Field="@nameof(SongBestData.GoodCount)" Title="Good"/>
<Column T="SongBestData" Field="@nameof(SongBestData.OkCount)" Title="Ok"/>
<Column T="SongBestData" Field="@nameof(SongBestData.MissCount)" Title="Miss"/>
<Column T="SongBestData" Field="@nameof(SongBestData.ComboCount)" Title="Max Combo"/>
<Column T="SongBestData" Field="@nameof(SongBestData.DrumrollCount)" Title="Drum Rolls"/>
<Column T="SongBestData" Field="@nameof(SongBestData.HitCount)" Title="Hit"/>
<Column T="SongBestData" Field="@nameof(SongBestData.IsFavorite)" Title="Favorite">
<CellTemplate>
<MudToggleIconButton Toggled="@context.Item.IsFavorite"
ToggledChanged="@(async () => await OnFavoriteToggled(context.Item))"
Icon="@Icons.Material.Filled.FavoriteBorder" Color="@Color.Secondary"
Title="Add to favorites"
ToggledIcon="@Icons.Material.Filled.Favorite" ToggledColor="@Color.Secondary"
ToggledTitle="Remove from favorites"/>
</CellTemplate>
</Column>
</Columns>
<PagerContent>
<MudDataGridPager T="SongBestData"/>
</PagerContent>
</MudDataGrid>
</MudTabPanel>
}
</MudTabs>
</MudItem>
}
</MudGrid>
@ -82,7 +90,7 @@ else
public int Baid { get; set; }
private SongBestResponse? response;
private const string ICON_STYLE = "width:25px; height:25px;";
private readonly List<BreadcrumbItem> breadcrumbs = new()
@ -94,7 +102,13 @@ else
{
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("Play Data", href: $"/Cards/{Baid}/PlayResults", disabled: false));
}
@ -123,7 +137,7 @@ else
CrownType.Gold => "Full Combo",
CrownType.Dondaful => "Donderful Combo",
_ => ""
};
};
}
}

View File

@ -1,5 +1,6 @@
using System.Collections.Immutable;
using System.Net.Http.Json;
using SharedProject.Enums;
using TaikoWebUI.Shared.Models;
using Throw;
@ -9,9 +10,7 @@ public class GameDataService : IGameDataService
{
private readonly HttpClient client;
private readonly Dictionary<uint, string> musicNameMap = new();
private readonly Dictionary<uint, string> musicArtistMap = new();
private readonly Dictionary<uint, MusicDetail> musicMap = new();
public GameDataService(HttpClient client)
{
@ -22,10 +21,13 @@ 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");
musicInfo.ThrowIfNull();
wordList.ThrowIfNull();
musicOrder.ThrowIfNull();
// To prevent duplicate entries in wordlist
var dict = wordList.WordListEntries.GroupBy(entry => entry.Key)
.ToImmutableDictionary(group => group.Key, group => group.First());
foreach (var music in musicInfo.Items)
@ -35,19 +37,47 @@ public class GameDataService : IGameDataService
var musicName = dict.GetValueOrDefault(songNameKey, new WordListEntry());
var musicArtist = dict.GetValueOrDefault(songArtistKey, new WordListEntry());
musicNameMap.TryAdd(music.SongId, musicName.JapaneseText);
musicArtistMap.TryAdd(music.SongId, musicArtist.JapaneseText);
var musicSongId = music.SongId;
var musicDetail = new MusicDetail
{
SongId = musicSongId,
SongName = musicName.JapaneseText,
ArtistName = musicArtist.JapaneseText,
Genre = music.Genre
};
musicMap.TryAdd(musicSongId, musicDetail);
}
for (var index = 0; index < musicOrder.Order.Count; index++)
{
var musicOrderEntry = musicOrder.Order[index];
var songId = musicOrderEntry.SongId;
if (musicMap.ContainsKey(songId))
{
musicMap[songId].Index = index;
}
}
}
public string GetMusicNameBySongId(uint songId)
{
return musicNameMap.GetValueOrDefault(songId, string.Empty);
return musicMap.TryGetValue(songId, out var musicDetail) ? musicDetail.SongName : string.Empty;
}
public string GetMusicArtistBySongId(uint songId)
{
return musicArtistMap.GetValueOrDefault(songId, string.Empty);
return musicMap.TryGetValue(songId, out var musicDetail) ? musicDetail.ArtistName : string.Empty;
}
public SongGenre GetMusicGenreBySongId(uint songId)
{
return musicMap.TryGetValue(songId, out var musicDetail) ? musicDetail.Genre : SongGenre.Variety;
}
public int GetMusicIndexBySongId(uint songId)
{
return musicMap.TryGetValue(songId, out var musicDetail) ? musicDetail.Index : int.MaxValue;
}
}

View File

@ -1,4 +1,7 @@
namespace TaikoWebUI.Services;
using SharedProject.Enums;
using TaikoWebUI.Shared.Models;
namespace TaikoWebUI.Services;
public interface IGameDataService
{
@ -7,4 +10,8 @@ public interface IGameDataService
public string GetMusicNameBySongId(uint songId);
public string GetMusicArtistBySongId(uint songId);
public SongGenre GetMusicGenreBySongId(uint songId);
public int GetMusicIndexBySongId(uint songId);
}

View File

@ -0,0 +1,16 @@
using SharedProject.Enums;
namespace TaikoWebUI.Shared.Models;
public class MusicDetail
{
public uint SongId { get; set; }
public int Index { get; set; }
public string SongName { get; set; } = string.Empty;
public string ArtistName { get; set; } = string.Empty;
public SongGenre Genre { get; set; }
}

View File

@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using SharedProject.Enums;
namespace TaikoWebUI.Shared.Models;
@ -11,5 +12,5 @@ public class MusicInfoEntry
public uint SongId { get; set; }
[JsonPropertyName("genreNo")]
public uint Genre { get; set; }
public SongGenre Genre { get; set; }
}

View File

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace TaikoWebUI.Shared.Models;
public class MusicOrder
{
[JsonPropertyName("items")]
public List<MusicOrderEntry> Order { get; set; } = new();
}

View File

@ -0,0 +1,10 @@
using System.Text.Json.Serialization;
using SharedProject.Enums;
namespace TaikoWebUI.Shared.Models;
public class MusicOrderEntry
{
[JsonPropertyName("uniqueId")]
public uint SongId { get; set; }
}

View File

@ -28,5 +28,9 @@
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\data" />
</ItemGroup>
</Project>