1
0
mirror of synced 2024-11-27 16:10:53 +01:00

Add play result sample page and update related parts

This commit is contained in:
asesidaa 2022-09-09 20:31:45 +08:00
parent a0af130d1d
commit 91d76bfeb5
18 changed files with 245 additions and 16 deletions

View File

@ -0,0 +1,8 @@
namespace SharedProject.Models.Requests;
public class SetFavoriteRequest
{
public uint Baid { get; set; }
public uint SongId { get; set; }
public bool IsFavorite { get; set; }
}

View File

@ -6,10 +6,6 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Folder Include="Models\Requests" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Throw" Version="1.3.0" /> <PackageReference Include="Throw" Version="1.3.0" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,2 @@
<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>

View File

@ -1,4 +1,5 @@
using TaikoLocalServer.Services.Interfaces; using SharedProject.Models.Requests;
using TaikoLocalServer.Services.Interfaces;
namespace TaikoLocalServer.Controllers.Api; namespace TaikoLocalServer.Controllers.Api;
@ -14,16 +15,16 @@ public class FavoriteSongsController : BaseController<FavoriteSongsController>
} }
[HttpPost] [HttpPost]
public async Task<IActionResult> UpdateFavoriteSong(uint baid, uint songId, bool isFavorite) public async Task<IActionResult> UpdateFavoriteSong(SetFavoriteRequest request)
{ {
var user = await userDatumService.GetFirstUserDatumOrNull(baid); var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
if (user is null) if (user is null)
{ {
return NotFound(); return NotFound();
} }
await userDatumService.UpdateFavoriteSong(baid, songId, isFavorite); await userDatumService.UpdateFavoriteSong(request.Baid, request.SongId, request.IsFavorite);
return NoContent(); return NoContent();
} }
} }

View File

@ -40,7 +40,7 @@ public class MyDonEntryController : BaseController<MyDonEntryController>
ColorFace = 0, ColorFace = 0,
ColorBody = 1, ColorBody = 1,
ColorLimb = 3, ColorLimb = 3,
FavoriteSongsArray = "{}" FavoriteSongsArray = "[]"
}; };
await userDatumService.InsertUserDatum(newUser); await userDatumService.InsertUserDatum(newUser);

View File

@ -102,9 +102,14 @@ public class UserDatumService : IUserDatumService
{ {
favoriteSet.Remove(songId); favoriteSet.Remove(songId);
} }
await JsonSerializer.SerializeAsync(stringStream, favoriteSet);
using var newFavoriteSongStream = new MemoryStream();
await JsonSerializer.SerializeAsync(newFavoriteSongStream, favoriteSet);
newFavoriteSongStream.Position = 0;
using var reader = new StreamReader(newFavoriteSongStream);
userDatum.FavoriteSongsArray = await reader.ReadToEndAsync();
logger.LogInformation("Favorite songs are: {Favorite}", userDatum.FavoriteSongsArray);
context.Update(userDatum); context.Update(userDatum);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }

2
TaikoWebUI/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
wwwroot/data/musicinfo
wwwroot/data/wordlist

View File

@ -1,4 +1,4 @@
@page "/Card/{baid}" @page "/Card/{baid:int}"
@using SharedProject.Enums @using SharedProject.Enums
@using SharedProject.Models @using SharedProject.Models
@inject HttpClient Client @inject HttpClient Client
@ -121,7 +121,7 @@
@code { @code {
[Parameter] [Parameter]
public string? Baid { get; set; } public int Baid { get; set; }
private UserSetting? response; private UserSetting? response;

View File

@ -0,0 +1,82 @@
@using TaikoWebUI.Services
@using SharedProject.Models.Responses
@using SharedProject.Models
@using SharedProject.Models.Requests
@inject IGameDataService GameDataService
@inject HttpClient Client
@page "/PlayResults/{baid:int}"
<h3>PlayResults for baid : @Baid</h3>
@if (response is null)
{
<MudText>No data</MudText>
}
else
{
<MudDataGrid Items="@response.SongBestData">
<Columns>
@* Notice here we have to use cell template for custom conversion *@
@* Field is retrieved using reflection, so it is a string with name equals field name*@
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Song Name">
<CellTemplate>
<MudText>@GameDataService.GetMusicNameBySongId(context.Item.SongId)</MudText>
</CellTemplate>
</Column>
<Column T="SongBestData" Field="@nameof(SongBestData.SongId)" Title="Artist">
<CellTemplate>
<MudText>@GameDataService.GetMusicArtistBySongId(context.Item.SongId)</MudText>
</CellTemplate>
</Column>
<Column T="SongBestData" Field="@nameof(SongBestData.Difficulty)" Title="Difficulty"/>
<Column T="SongBestData" Field="@nameof(SongBestData.BestScore)" Title="Best score"/>
<Column T="SongBestData" Field="@nameof(SongBestData.BestCrown)" Title="Best crown"/>
<Column T="SongBestData" Field="@nameof(SongBestData.BestRate)" Title="Best rate"/>
<Column T="SongBestData" Field="@nameof(SongBestData.BestScoreRank)" Title="Best score rank"/>
<Column T="SongBestData" Field="@nameof(SongBestData.IsFavorite)" Title="Is favorite">
<CellTemplate>
<MudToggleIconButton Toggled="@context.Item.IsFavorite"
ToggledChanged="@(async () => await OnFavoriteToggled(context.Item))"
Icon="@Icons.Material.Filled.FavoriteBorder" Color="@Color.Secondary"
Title="Add to favorite"
ToggledIcon="@Icons.Material.Filled.Favorite" ToggledColor="@Color.Secondary"
ToggledTitle="Remove from favorite"/>
</CellTemplate>
</Column>
</Columns>
<PagerContent>
<MudDataGridPager T="SongBestData"/>
</PagerContent>
</MudDataGrid>
}
@code {
[Parameter]
public int Baid { get; set; }
private SongBestResponse? response;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
response = await Client.GetFromJsonAsync<SongBestResponse>($"api/PlayData/{Baid}");
}
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;
}
}
}

View File

@ -2,15 +2,22 @@ using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using TaikoWebUI; using TaikoWebUI;
using MudBlazor.Services; using MudBlazor.Services;
using TaikoWebUI.Services;
var builder = WebAssemblyHostBuilder.CreateDefault(args); var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app"); builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after"); builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient builder.Services.AddSingleton(sp => new HttpClient
{ {
BaseAddress = new Uri(builder.Configuration.GetValue<string>("BaseUrl")) BaseAddress = new Uri(builder.Configuration.GetValue<string>("BaseUrl"))
}); });
builder.Services.AddMudServices(); builder.Services.AddMudServices();
builder.Services.AddSingleton<IGameDataService, GameDataService>();
await builder.Build().RunAsync(); var host = builder.Build();
var gameDataService = host.Services.GetRequiredService<IGameDataService>();
await gameDataService.InitializeAsync(builder.Configuration.GetValue<string>("DataBaseUrl"));
await host.RunAsync();

View File

@ -0,0 +1,52 @@
using System.Collections.Immutable;
using System.Net.Http.Json;
using TaikoWebUI.Shared.Models;
using Throw;
namespace TaikoWebUI.Services;
public class GameDataService : IGameDataService
{
private readonly HttpClient client;
private readonly Dictionary<uint, string> musicNameMap = new();
private readonly Dictionary<uint, string> musicArtistMap = new();
public GameDataService(HttpClient client)
{
this.client = client;
}
public async Task InitializeAsync(string dataBaseUrl)
{
var musicInfo = await client.GetFromJsonAsync<MusicInfo>($"{dataBaseUrl}/data/musicinfo");
var wordList = await client.GetFromJsonAsync<WordList>($"{dataBaseUrl}/data/wordlist");
musicInfo.ThrowIfNull();
wordList.ThrowIfNull();
var dict = wordList.WordListEntries.ToImmutableDictionary(entry => entry.Key);
foreach (var music in musicInfo.Items)
{
var songNameKey = $"song_{music.Id}";
var songArtistKey = $"song_sub_{music.Id}";
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);
}
}
public string GetMusicNameBySongId(uint songId)
{
return musicNameMap.GetValueOrDefault(songId, string.Empty);
}
public string GetMusicArtistBySongId(uint songId)
{
return musicArtistMap.GetValueOrDefault(songId, string.Empty);
}
}

View File

@ -0,0 +1,10 @@
namespace TaikoWebUI.Services;
public interface IGameDataService
{
public Task InitializeAsync(string dataBaseUrl);
public string GetMusicNameBySongId(uint songId);
public string GetMusicArtistBySongId(uint songId);
}

View File

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

View File

@ -0,0 +1,15 @@
using System.Text.Json.Serialization;
namespace TaikoWebUI.Shared.Models;
public class MusicInfoEntry
{
[JsonPropertyName("id")]
public string Id { get; set; } = string.Empty;
[JsonPropertyName("uniqueId")]
public uint SongId { get; set; }
[JsonPropertyName("genreNo")]
public uint Genre { get; set; }
}

View File

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

View File

@ -0,0 +1,21 @@
using System.Text.Json.Serialization;
namespace TaikoWebUI.Shared.Models;
public class WordListEntry
{
[JsonPropertyName("key")]
public string Key { get; set; } = string.Empty;
[JsonPropertyName("japaneseText")]
public string JapaneseText { get; set; } = string.Empty;
[JsonPropertyName("englishUsText")]
public string EnglishUsText { get; set; } = string.Empty;
[JsonPropertyName("chineseTText")]
public string ChineseTText { get; set; } = string.Empty;
[JsonPropertyName("koreanText")]
public string KoreanText { get; set; } = string.Empty;
}

View File

@ -16,5 +16,14 @@
<ProjectReference Include="..\SharedProject\SharedProject.csproj" /> <ProjectReference Include="..\SharedProject\SharedProject.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Update="wwwroot\data\musicinfo">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\data\wordlist">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project> </Project>

View File

@ -1,3 +1,4 @@
{ {
"BaseUrl": "http://localhost:5000" "BaseUrl": "http://localhost:5000",
"DataBaseUrl": "https://localhost:44398"
} }