Add play result sample page and update related parts
This commit is contained in:
parent
a0af130d1d
commit
91d76bfeb5
8
SharedProject/Models/Requests/SetFavoriteRequest.cs
Normal file
8
SharedProject/Models/Requests/SetFavoriteRequest.cs
Normal 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; }
|
||||||
|
}
|
@ -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>
|
||||||
|
2
TaikoLocalServer.sln.DotSettings
Normal file
2
TaikoLocalServer.sln.DotSettings
Normal 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>
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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);
|
||||||
|
@ -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
2
TaikoWebUI/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
wwwroot/data/musicinfo
|
||||||
|
wwwroot/data/wordlist
|
@ -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;
|
||||||
|
|
||||||
|
82
TaikoWebUI/Pages/PlayResults.razor
Normal file
82
TaikoWebUI/Pages/PlayResults.razor
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
52
TaikoWebUI/Services/GameDataService.cs
Normal file
52
TaikoWebUI/Services/GameDataService.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
10
TaikoWebUI/Services/IGameDataService.cs
Normal file
10
TaikoWebUI/Services/IGameDataService.cs
Normal 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);
|
||||||
|
}
|
9
TaikoWebUI/Shared/Models/MusicInfo.cs
Normal file
9
TaikoWebUI/Shared/Models/MusicInfo.cs
Normal 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();
|
||||||
|
}
|
15
TaikoWebUI/Shared/Models/MusicInfoEntry.cs
Normal file
15
TaikoWebUI/Shared/Models/MusicInfoEntry.cs
Normal 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; }
|
||||||
|
}
|
9
TaikoWebUI/Shared/Models/WordList.cs
Normal file
9
TaikoWebUI/Shared/Models/WordList.cs
Normal 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();
|
||||||
|
}
|
21
TaikoWebUI/Shared/Models/WordListEntry.cs
Normal file
21
TaikoWebUI/Shared/Models/WordListEntry.cs
Normal 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;
|
||||||
|
}
|
@ -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>
|
@ -1,3 +1,4 @@
|
|||||||
{
|
{
|
||||||
"BaseUrl": "http://localhost:5000"
|
"BaseUrl": "http://localhost:5000",
|
||||||
|
"DataBaseUrl": "https://localhost:44398"
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user