Update web interface
This commit is contained in:
parent
4871c0bf6f
commit
d3265dbc02
41
GC-local-server-rewrite/backports/JsonDataAttribute.cs
Normal file
41
GC-local-server-rewrite/backports/JsonDataAttribute.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace EmbedIO.WebApi
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Specifies that a parameter of a controller method will receive
|
||||||
|
/// an object obtained by deserializing the request body as JSON.</para>
|
||||||
|
/// <para>The received object will be <see langword="null"/>
|
||||||
|
/// only if the deserialized object is <c>null</c>.</para>
|
||||||
|
/// <para>If the request body is not valid JSON,
|
||||||
|
/// or if it cannot be deserialized to the type of the parameter,
|
||||||
|
/// a <c>400 Bad Request</c> response will be sent to the client.</para>
|
||||||
|
/// <para>This class cannot be inherited.</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="Attribute" />
|
||||||
|
/// <seealso cref="IRequestDataAttribute{TController}" />
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter)]
|
||||||
|
public class JsonDataAttribute : Attribute, IRequestDataAttribute<WebApiController>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<object?> GetRequestDataAsync(WebApiController controller, Type type, string parameterName)
|
||||||
|
{
|
||||||
|
string body;
|
||||||
|
|
||||||
|
using (var reader = controller.HttpContext.OpenRequestText())
|
||||||
|
{
|
||||||
|
body = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Swan.Formatters.Json.Deserialize(body, type);
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
throw HttpException.BadRequest($"Expected request body to be deserializable to {type.FullName}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -122,6 +122,16 @@ public static class Configs
|
|||||||
|
|
||||||
public const string RANK_STATUS_XPATH = $"{ROOT_XPATH}/ranking_status";
|
public const string RANK_STATUS_XPATH = $"{ROOT_XPATH}/ranking_status";
|
||||||
|
|
||||||
|
public const int CONFIG_PCOL1 = 0;
|
||||||
|
public const int CONFIG_PCOL2 = 0;
|
||||||
|
public const int CONFIG_PCOL3 = 0;
|
||||||
|
|
||||||
|
public const int FAVORITE_PCOL1 = 10;
|
||||||
|
|
||||||
|
public const int COUNT_PCOL1 = 20;
|
||||||
|
|
||||||
|
public const int SCORE_PCOL1 = 21;
|
||||||
|
|
||||||
public static readonly List<string> DOMAINS = new()
|
public static readonly List<string> DOMAINS = new()
|
||||||
{
|
{
|
||||||
"localhost",
|
"localhost",
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using ChoETL;
|
using EmbedIO;
|
||||||
using EmbedIO;
|
|
||||||
using EmbedIO.Routing;
|
using EmbedIO.Routing;
|
||||||
using EmbedIO.WebApi;
|
using EmbedIO.WebApi;
|
||||||
using GCLocalServerRewrite.common;
|
using GCLocalServerRewrite.common;
|
||||||
@ -39,6 +38,54 @@ public class ApiController : WebApiController
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route(HttpVerbs.Post, "/UserDetail/SetMusicFavorite")]
|
||||||
|
// ReSharper disable once UnusedMember.Global
|
||||||
|
public bool SetFavorite([JsonData] MusicFavoriteData data)
|
||||||
|
{
|
||||||
|
var existing = cardSqLiteConnection.Table<CardDetail>()
|
||||||
|
.Where(detail => detail.CardId == data.CardId
|
||||||
|
&& detail.Pcol1 == Configs.FAVORITE_PCOL1
|
||||||
|
&& detail.Pcol2 == data.MusicId);
|
||||||
|
|
||||||
|
if (!existing.Any())
|
||||||
|
{
|
||||||
|
$"Trying to update non existing song's favorite! Card id {data.CardId}, music id {data.MusicId}".Warn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cardDetail = existing.First();
|
||||||
|
cardDetail.Fcol1 = data.IsFavorite ? 1 : 0;
|
||||||
|
var result = cardSqLiteConnection.Update(cardDetail);
|
||||||
|
|
||||||
|
return result == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route(HttpVerbs.Post, "/UserDetail/SetPlayOption")]
|
||||||
|
// ReSharper disable once UnusedMember.Global
|
||||||
|
public bool SetPlayOption([JsonData] PlayOption data)
|
||||||
|
{
|
||||||
|
var existing = cardSqLiteConnection.Table<CardDetail>()
|
||||||
|
.Where(detail => detail.CardId == data.CardId
|
||||||
|
&& detail.Pcol1 == Configs.CONFIG_PCOL1
|
||||||
|
&& detail.Pcol2 == Configs.CONFIG_PCOL2
|
||||||
|
&& detail.Pcol3 == Configs.CONFIG_PCOL3);
|
||||||
|
|
||||||
|
if (!existing.Any())
|
||||||
|
{
|
||||||
|
$"Trying to update non existing card's config! Card id {data.CardId}".Warn();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cardDetail = existing.First();
|
||||||
|
cardDetail.ScoreUi1 = (long)data.FastSlowIndicator;
|
||||||
|
cardDetail.ScoreUi2 = (long)data.FeverTrance;
|
||||||
|
|
||||||
|
var result = cardSqLiteConnection.Update(cardDetail);
|
||||||
|
|
||||||
|
return result == 1;
|
||||||
|
}
|
||||||
|
|
||||||
[Route(HttpVerbs.Get, "/UserDetail/{cardId}")]
|
[Route(HttpVerbs.Get, "/UserDetail/{cardId}")]
|
||||||
// ReSharper disable once UnusedMember.Global
|
// ReSharper disable once UnusedMember.Global
|
||||||
public UserDetail? GetUserDetail(long cardId)
|
public UserDetail? GetUserDetail(long cardId)
|
||||||
@ -47,6 +94,7 @@ public class ApiController : WebApiController
|
|||||||
|
|
||||||
if (!cardResult.Any())
|
if (!cardResult.Any())
|
||||||
{
|
{
|
||||||
|
$"Getting detail for non exisisting card! Card id is {cardId}".Warn();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,6 +277,7 @@ public class ApiController : WebApiController
|
|||||||
{
|
{
|
||||||
Artist = musicData.Artist ?? string.Empty,
|
Artist = musicData.Artist ?? string.Empty,
|
||||||
Title = musicData.Title ?? string.Empty,
|
Title = musicData.Title ?? string.Empty,
|
||||||
|
MusicId = musicId,
|
||||||
SongPlaySubDataList = new SongPlayDetailData[4]
|
SongPlaySubDataList = new SongPlayDetailData[4]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
57
MudAdmin/Pages/FavoriteDialog.razor
Normal file
57
MudAdmin/Pages/FavoriteDialog.razor
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
@using SharedProject.models
|
||||||
|
@inject HttpClient Client
|
||||||
|
@inject ILogger<FavoriteDialog> Logger
|
||||||
|
|
||||||
|
<MudDialog>
|
||||||
|
<TitleContent>
|
||||||
|
@if (!Data.IsFavorite)
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.h6">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.BookmarkAdd" Color="Color.Secondary"/>
|
||||||
|
Add to favorite?
|
||||||
|
</MudText>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.h6">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.BookmarkRemove" Color="Color.Secondary"/>
|
||||||
|
Remove from favorite?
|
||||||
|
</MudText>
|
||||||
|
}
|
||||||
|
</TitleContent>
|
||||||
|
<DialogContent>
|
||||||
|
<MudTextField Value="@Data.Title" Label="Song Title" ReadOnly="true"/>
|
||||||
|
<MudTextField Value="@Data.Artist" Label="Artist Name" ReadOnly="true"/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton OnClick="Cancel">Cancel</MudButton>
|
||||||
|
<MudButton Color="Color.Primary" OnClick="Submit">Confirm</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
@code {
|
||||||
|
[CascadingParameter]
|
||||||
|
MudDialogInstance MudDialog { get; set; } = null!;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public SongPlayData Data { get; set; } = null!;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public long CardId { get; set; }
|
||||||
|
|
||||||
|
async void Submit()
|
||||||
|
{
|
||||||
|
var postData = new MusicFavoriteData
|
||||||
|
{
|
||||||
|
CardId = CardId,
|
||||||
|
IsFavorite = !Data.IsFavorite,
|
||||||
|
MusicId = Data.MusicId
|
||||||
|
};
|
||||||
|
Logger.LogInformation("Data is {cardId}, {musicId}", CardId, Data.MusicId);
|
||||||
|
var response = await Client.PostAsJsonAsync("api/UserDetail/SetMusicFavorite", postData);
|
||||||
|
var result = await response.Content.ReadFromJsonAsync<bool>();
|
||||||
|
Logger.LogInformation("Favorite result is {result}", result);
|
||||||
|
MudDialog.Close(DialogResult.Ok(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cancel() => MudDialog.Cancel();
|
||||||
|
}
|
@ -1,61 +0,0 @@
|
|||||||
@page "/fetchdata"
|
|
||||||
@inject HttpClient Http
|
|
||||||
|
|
||||||
<PageTitle>Weather forecast</PageTitle>
|
|
||||||
|
|
||||||
<MudText Typo="Typo.h3" GutterBottom="true">Weather forecast</MudText>
|
|
||||||
<MudText Class="mb-8">This component demonstrates fetching data from the server.</MudText>
|
|
||||||
@if (forecasts == null)
|
|
||||||
{
|
|
||||||
<MudProgressCircular Color="Color.Default" Indeterminate="true"/>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<MudTable Items="forecasts" Hover="true" SortLabel="Sort By" Elevation="0">
|
|
||||||
<HeaderContent>
|
|
||||||
<MudTh>
|
|
||||||
<MudTableSortLabel InitialDirection="SortDirection.Ascending" SortBy="new Func<WeatherForecast, object>(x=>x.Date)">Date</MudTableSortLabel>
|
|
||||||
</MudTh>
|
|
||||||
<MudTh>
|
|
||||||
<MudTableSortLabel SortBy="new Func<WeatherForecast, object>(x=>x.TemperatureC)">Temp. (C)</MudTableSortLabel>
|
|
||||||
</MudTh>
|
|
||||||
<MudTh>
|
|
||||||
<MudTableSortLabel SortBy="new Func<WeatherForecast, object>(x=>x.TemperatureF)">Temp. (F)</MudTableSortLabel>
|
|
||||||
</MudTh>
|
|
||||||
<MudTh>
|
|
||||||
<MudTableSortLabel SortBy="new Func<WeatherForecast, object>(x=>x.Summary!)">Summary</MudTableSortLabel>
|
|
||||||
</MudTh>
|
|
||||||
</HeaderContent>
|
|
||||||
<RowTemplate>
|
|
||||||
<MudTd DataLabel="Date">@context.Date</MudTd>
|
|
||||||
<MudTd DataLabel="Temp. (C)">@context.TemperatureC</MudTd>
|
|
||||||
<MudTd DataLabel="Temp. (F)">@context.TemperatureF</MudTd>
|
|
||||||
<MudTd DataLabel="Summary">@context.Summary</MudTd>
|
|
||||||
</RowTemplate>
|
|
||||||
<PagerContent>
|
|
||||||
<MudTablePager PageSizeOptions="new int[]{50, 100}"/>
|
|
||||||
</PagerContent>
|
|
||||||
</MudTable>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private WeatherForecast[]? forecasts;
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
public class WeatherForecast
|
|
||||||
{
|
|
||||||
public DateTime Date { get; set; }
|
|
||||||
|
|
||||||
public int TemperatureC { get; set; }
|
|
||||||
|
|
||||||
public string? Summary { get; set; }
|
|
||||||
|
|
||||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,14 +1,17 @@
|
|||||||
@page "/user/{CardId:long}"
|
@page "/user/{CardId:long}"
|
||||||
@using SharedProject.models
|
@using SharedProject.models
|
||||||
@using MudAdmin.Utils
|
|
||||||
@using SharedProject.enums
|
@using SharedProject.enums
|
||||||
@inject HttpClient Client
|
@inject HttpClient Client
|
||||||
|
@inject IDialogService DialogService
|
||||||
|
@inject ILogger<User> Logger
|
||||||
|
|
||||||
<PageTitle>User</PageTitle>
|
<PageTitle>User</PageTitle>
|
||||||
|
<MudContainer>
|
||||||
@if (userDetail == null)
|
@if (userDetail == null)
|
||||||
{
|
{
|
||||||
<MudProgressCircular Color="Color.Default" Indeterminate="true"/>
|
<MudSkeleton Width="1184px" Height="57px"/>
|
||||||
|
<MudSkeleton Width="1184px" Height="57px"/>
|
||||||
|
<MudSkeleton Width="1184px" Height="57px"/>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -57,12 +60,12 @@ else
|
|||||||
</MudButton>
|
</MudButton>
|
||||||
</MudExpansionPanel>
|
</MudExpansionPanel>
|
||||||
<MudExpansionPanel Text="SongPlayData">
|
<MudExpansionPanel Text="SongPlayData">
|
||||||
<MudDataGrid T="SongPlayData" Items="@songPlayDataList" Sortable="true">
|
<MudDataGrid T="SongPlayData" Items="@songPlayDataList" Sortable="true" Filterable="true">
|
||||||
<ToolBarContent>
|
<ToolBarContent>
|
||||||
<MudText Typo="Typo.h6">Played Songs</MudText>
|
<MudText Typo="Typo.h6">Played Songs</MudText>
|
||||||
</ToolBarContent>
|
</ToolBarContent>
|
||||||
<Columns>
|
<Columns>
|
||||||
<Column T="SongPlayData">
|
<Column T="SongPlayData" Sortable="false" Filterable="false">
|
||||||
<CellTemplate>
|
<CellTemplate>
|
||||||
<MudButton Variant="Variant.Outlined" Size="Size.Small"
|
<MudButton Variant="Variant.Outlined" Size="Size.Small"
|
||||||
OnClick="@(() => OnShowDetailsClick(context.Item))">
|
OnClick="@(() => OnShowDetailsClick(context.Item))">
|
||||||
@ -70,22 +73,17 @@ else
|
|||||||
</MudButton>
|
</MudButton>
|
||||||
</CellTemplate>
|
</CellTemplate>
|
||||||
</Column>
|
</Column>
|
||||||
<Column T="SongPlayData">
|
<Column T="SongPlayData" Field="IsFavorite" Sortable="false" Title="Favorite">
|
||||||
<CellTemplate>
|
<CellTemplate>
|
||||||
<MudToggleIconButton ToggleChanged="@(() => OnFavoriteToggled(context.Item))"
|
<MudToggleIconButton Toggled="@context.Item.IsFavorite"
|
||||||
|
ToggledChanged="@(()=>OnFavoriteToggled(context.Item))"
|
||||||
Icon="@Icons.Material.Filled.FavoriteBorder" Color="@Color.Secondary" Title="Add to favorite"
|
Icon="@Icons.Material.Filled.FavoriteBorder" Color="@Color.Secondary" Title="Add to favorite"
|
||||||
ToggledIcon="@Icons.Material.Filled.Favorite" ToggledColor="@Color.Secondary" ToggledTitle="Remove from favorite"/>
|
ToggledIcon="@Icons.Material.Filled.Favorite" ToggledColor="@Color.Secondary" ToggledTitle="Remove from favorite"/>
|
||||||
</CellTemplate>
|
</CellTemplate>
|
||||||
</Column>
|
</Column>
|
||||||
<Column T="SongPlayData" Field="Title" Title="Song Title"/>
|
<Column T="SongPlayData" Field="Title" Title="Song Title"/>
|
||||||
<Column T="SongPlayData" Field="Artist" Title="Artist"/>
|
<Column T="SongPlayData" Field="Artist" Title="Artist"/>
|
||||||
<Column T="SongPlayData" Title="Total Play Count">
|
<Column T="SongPlayData" Field="TotalPlayCount" Title="Total Play Count" />
|
||||||
<CellTemplate>
|
|
||||||
<MudText>
|
|
||||||
@CalculateTotalPlayCount(context.Item)
|
|
||||||
</MudText>
|
|
||||||
</CellTemplate>
|
|
||||||
</Column>
|
|
||||||
</Columns>
|
</Columns>
|
||||||
<ChildRowContent>
|
<ChildRowContent>
|
||||||
@if (context.ShowDetails)
|
@if (context.ShowDetails)
|
||||||
@ -99,7 +97,7 @@ else
|
|||||||
</CardHeaderContent>
|
</CardHeaderContent>
|
||||||
</MudCardHeader>
|
</MudCardHeader>
|
||||||
<MudCardContent Class="pa-0">
|
<MudCardContent Class="pa-0">
|
||||||
<MudTable Items="@context.SongPlaySubDataList" Context="SongPlayDetail" Elevation="0">
|
<MudTable Items="@context.SongPlaySubDataList" Context="SongPlayDetail" Elevation="0" Filter="data => data.ClearState != ClearState.NotPlayed">
|
||||||
<HeaderContent>
|
<HeaderContent>
|
||||||
<MudTh>Difficulty</MudTh>
|
<MudTh>Difficulty</MudTh>
|
||||||
<MudTh>Clear State</MudTh>
|
<MudTh>Clear State</MudTh>
|
||||||
@ -132,6 +130,7 @@ else
|
|||||||
</MudExpansionPanel>
|
</MudExpansionPanel>
|
||||||
</MudExpansionPanels>
|
</MudExpansionPanels>
|
||||||
}
|
}
|
||||||
|
</MudContainer>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
@ -177,7 +176,13 @@ else
|
|||||||
private async Task SaveOptions()
|
private async Task SaveOptions()
|
||||||
{
|
{
|
||||||
isSavingOptions = true;
|
isSavingOptions = true;
|
||||||
await Task.Delay(2000);
|
var postData = new PlayOption
|
||||||
|
{
|
||||||
|
CardId = CardId,
|
||||||
|
FastSlowIndicator = fastSlowIndicator,
|
||||||
|
FeverTrance = feverTranceShow
|
||||||
|
};
|
||||||
|
var result = await Client.PostAsJsonAsync("api/UserDetail/SetPlayOption", postData);
|
||||||
isSavingOptions = false;
|
isSavingOptions = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,14 +200,29 @@ else
|
|||||||
return grade;
|
return grade;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFavoriteToggled(SongPlayData data)
|
private async Task OnFavoriteToggled(SongPlayData data)
|
||||||
{
|
{
|
||||||
data.IsFavorite = !data.IsFavorite;
|
var options = new DialogOptions
|
||||||
}
|
{
|
||||||
|
CloseOnEscapeKey = false,
|
||||||
|
DisableBackdropClick = true,
|
||||||
|
FullWidth = true
|
||||||
|
};
|
||||||
|
var parameters = new DialogParameters();
|
||||||
|
parameters.Add("Data", data);
|
||||||
|
parameters.Add("CardId", CardId);
|
||||||
|
var dialog = DialogService.Show<FavoriteDialog>("Favorite", parameters, options);
|
||||||
|
var result = await dialog.Result;
|
||||||
|
|
||||||
private static int CalculateTotalPlayCount(SongPlayData data)
|
if (result.Cancelled)
|
||||||
{
|
{
|
||||||
return data.SongPlaySubDataList
|
return;
|
||||||
.Sum(detailData => detailData.PlayCount);
|
}
|
||||||
|
|
||||||
|
if ((bool)result.Data)
|
||||||
|
{
|
||||||
|
Logger.LogInformation("Changed!");
|
||||||
|
data.IsFavorite = !data.IsFavorite;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,30 +5,63 @@
|
|||||||
|
|
||||||
<PageTitle>Users</PageTitle>
|
<PageTitle>Users</PageTitle>
|
||||||
|
|
||||||
<MudGrid>
|
<MudContainer>
|
||||||
@foreach (var user in users)
|
@if (users is null)
|
||||||
{
|
{
|
||||||
<MudItem>
|
<MudGrid>
|
||||||
<MudCard>
|
@for (var i = 0; i < 5; i++)
|
||||||
<MudCardHeader>
|
{
|
||||||
<CardHeaderContent>
|
<MudItem>
|
||||||
<MudText Typo="Typo.h6">@user.PlayerName</MudText>
|
<MudCard>
|
||||||
</CardHeaderContent>
|
<MudCardHeader>
|
||||||
</MudCardHeader>
|
<CardHeaderContent>
|
||||||
<MudCardContent>
|
<MudSkeleton SkeletonType="SkeletonType.Rectangle" Height="32px"/>
|
||||||
<MudText Typo="Typo.h6">Card ID</MudText>
|
</CardHeaderContent>
|
||||||
<MudText>@user.CardId</MudText>
|
</MudCardHeader>
|
||||||
</MudCardContent>
|
<MudCardContent>
|
||||||
<MudCardActions>
|
<MudSkeleton Width="80px" Height="32px"/>
|
||||||
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="() => OnClick(user)">Test</MudButton>
|
<MudSkeleton Width="147px" Height="28px"/>
|
||||||
</MudCardActions>
|
</MudCardContent>
|
||||||
</MudCard>
|
<MudCardActions>
|
||||||
</MudItem>
|
<MudSkeleton SkeletonType="SkeletonType.Rectangle" Width="99px" Height="25px" Class="ml-2"/>
|
||||||
|
</MudCardActions>
|
||||||
|
</MudCard>
|
||||||
|
</MudItem>
|
||||||
|
}
|
||||||
|
</MudGrid>
|
||||||
}
|
}
|
||||||
</MudGrid>
|
else if (!(users.Count == 0))
|
||||||
|
{
|
||||||
|
<MudGrid>
|
||||||
|
@foreach (var user in users)
|
||||||
|
{
|
||||||
|
<MudItem>
|
||||||
|
<MudCard>
|
||||||
|
<MudCardHeader>
|
||||||
|
<CardHeaderContent>
|
||||||
|
<MudText Typo="Typo.h5">@user.PlayerName</MudText>
|
||||||
|
</CardHeaderContent>
|
||||||
|
</MudCardHeader>
|
||||||
|
<MudCardContent>
|
||||||
|
<MudText Typo="Typo.h6">Card ID</MudText>
|
||||||
|
<MudText>@user.CardId</MudText>
|
||||||
|
</MudCardContent>
|
||||||
|
<MudCardActions>
|
||||||
|
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="() => OnClick(user)">Check detail</MudButton>
|
||||||
|
</MudCardActions>
|
||||||
|
</MudCard>
|
||||||
|
</MudItem>
|
||||||
|
}
|
||||||
|
</MudGrid>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.h3">No Data</MudText>
|
||||||
|
}
|
||||||
|
</MudContainer>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<models.User> users = new();
|
private List<models.User>? users;
|
||||||
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
@ -41,4 +74,5 @@
|
|||||||
{
|
{
|
||||||
NavigationManager.NavigateTo($"user/{user.CardId}");
|
NavigationManager.NavigateTo($"user/{user.CardId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
using MudAdmin;
|
using MudAdmin;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<MudNavMenu>
|
<MudNavMenu>
|
||||||
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
|
<MudNavLink Href="" Match="NavLinkMatch.All" Icon="@Icons.Material.Filled.Home">Home</MudNavLink>
|
||||||
<MudNavLink Href="counter" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Add">Counter</MudNavLink>
|
<MudNavLink Href="counter" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Add">Counter</MudNavLink>
|
||||||
<MudNavLink Href="fetchdata" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.List">Fetch data</MudNavLink>
|
|
||||||
<MudNavLink Href="users" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.List">Users</MudNavLink>
|
<MudNavLink Href="users" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.List">Users</MudNavLink>
|
||||||
</MudNavMenu>
|
</MudNavMenu>
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
public enum ClearState
|
public enum ClearState
|
||||||
{
|
{
|
||||||
|
NotPlayed = 0,
|
||||||
Failed,
|
Failed,
|
||||||
Clear,
|
Clear,
|
||||||
NoMiss,
|
NoMiss,
|
||||||
|
15
SharedProject/models/MusicFavoriteData.cs
Normal file
15
SharedProject/models/MusicFavoriteData.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace SharedProject.models;
|
||||||
|
|
||||||
|
public class MusicFavoriteData
|
||||||
|
{
|
||||||
|
[JsonPropertyName(nameof(CardId))]
|
||||||
|
public long CardId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName(nameof(MusicId))]
|
||||||
|
public int MusicId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName(nameof(IsFavorite))]
|
||||||
|
public bool IsFavorite { get; set; }
|
||||||
|
}
|
@ -1,12 +1,16 @@
|
|||||||
using SharedProject.enums;
|
using System.Text.Json.Serialization;
|
||||||
|
using SharedProject.enums;
|
||||||
|
|
||||||
namespace SharedProject.models;
|
namespace SharedProject.models;
|
||||||
|
|
||||||
public class PlayOption
|
public class PlayOption
|
||||||
{
|
{
|
||||||
|
[JsonPropertyName(nameof(CardId))]
|
||||||
public long CardId { get; set; }
|
public long CardId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName(nameof(FastSlowIndicator))]
|
||||||
public PlayOptions.FastSlowIndicator FastSlowIndicator { get; set; }
|
public PlayOptions.FastSlowIndicator FastSlowIndicator { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName(nameof(FeverTrance))]
|
||||||
public PlayOptions.FeverTranceShow FeverTrance { get; set; }
|
public PlayOptions.FeverTranceShow FeverTrance { get; set; }
|
||||||
}
|
}
|
@ -1,4 +1,6 @@
|
|||||||
namespace SharedProject.models;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace SharedProject.models;
|
||||||
|
|
||||||
public class SongPlayData
|
public class SongPlayData
|
||||||
{
|
{
|
||||||
@ -6,9 +8,20 @@ public class SongPlayData
|
|||||||
|
|
||||||
public string Artist { get; set; } = string.Empty;
|
public string Artist { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public int MusicId { get; set; }
|
||||||
|
|
||||||
public SongPlayDetailData[] SongPlaySubDataList { get; set; } = new SongPlayDetailData[4];
|
public SongPlayDetailData[] SongPlaySubDataList { get; set; } = new SongPlayDetailData[4];
|
||||||
|
|
||||||
public bool IsFavorite { get; set; }
|
public bool IsFavorite { get; set; }
|
||||||
|
|
||||||
public bool ShowDetails { get; set; }
|
public bool ShowDetails { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public int TotalPlayCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return SongPlaySubDataList.Sum(data => data.PlayCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user