Merged from new-songs-ui branch
This commit is contained in:
commit
4e13b4bfe1
@ -2,5 +2,7 @@
|
||||
|
||||
public class SongLeaderboardResponse
|
||||
{
|
||||
public List<SongLeaderboard> Leaderboard { get; set; } = new();
|
||||
public List<SongLeaderboard> LeaderboardData { get; set; }
|
||||
public int CurrentPage { get; set; }
|
||||
public int TotalPages { get; set; }
|
||||
}
|
@ -4,7 +4,7 @@ namespace SharedProject.Models;
|
||||
|
||||
public class SongLeaderboard
|
||||
{
|
||||
public uint Rank { get; set; }
|
||||
public int Rank { get; set; }
|
||||
|
||||
public uint Baid { get; set; }
|
||||
|
||||
|
@ -16,8 +16,7 @@ public class SongLeaderboardController(ISongLeaderboardService songLeaderboardSe
|
||||
|
||||
[HttpGet("{songId}")]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
|
||||
public async Task<ActionResult<SongLeaderboardResponse>> GetSongLeaderboard(uint songId, [FromQuery] uint baid, [FromQuery] uint difficulty)
|
||||
public async Task<ActionResult<SongLeaderboardResponse>> GetSongLeaderboard(uint songId, [FromQuery] uint baid, [FromQuery] uint difficulty, [FromQuery] int page = 1, [FromQuery] int limit = 10)
|
||||
{
|
||||
// if baid id is provided, check authentication
|
||||
if (!baid.Equals(0))
|
||||
@ -37,16 +36,28 @@ public class SongLeaderboardController(ISongLeaderboardService songLeaderboardSe
|
||||
}
|
||||
}
|
||||
|
||||
if (page < 1)
|
||||
{
|
||||
return BadRequest(new { Message = "Page number cannot be less than 1." });
|
||||
}
|
||||
|
||||
if (limit > 200)
|
||||
{
|
||||
return BadRequest(new { Message = "Limit cannot be greater than 200." });
|
||||
}
|
||||
|
||||
if (difficulty < 1 || difficulty > 5)
|
||||
{
|
||||
return BadRequest(new { Message = "Invalid difficulty. Please provide a number between 1-5." });
|
||||
}
|
||||
|
||||
var leaderboard = await songLeaderboardService.GetSongLeaderboard(songId, (Difficulty)difficulty, (int)baid);
|
||||
|
||||
var (leaderboard, totalPages) = await songLeaderboardService.GetSongLeaderboard(songId, (Difficulty)difficulty, (int)baid, page, limit);
|
||||
|
||||
return Ok(new SongLeaderboardResponse
|
||||
{
|
||||
Leaderboard = leaderboard
|
||||
LeaderboardData = leaderboard,
|
||||
CurrentPage = page,
|
||||
TotalPages = totalPages
|
||||
});
|
||||
}
|
||||
}
|
@ -3,5 +3,5 @@
|
||||
using SharedProject.Models;
|
||||
public interface ISongLeaderboardService
|
||||
{
|
||||
public Task<List<SongLeaderboard>> GetSongLeaderboard(uint songId, Difficulty difficulty, int baid, int limit = 10);
|
||||
Task<(List<SongLeaderboard>, int)> GetSongLeaderboard(uint songId, Difficulty difficulty, int baid = 0, int page = 1, int limit = 10);
|
||||
}
|
@ -12,19 +12,29 @@ public class SongLeaderboardService : ISongLeaderboardService
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public async Task<List<SongLeaderboard>> GetSongLeaderboard(uint songId, Difficulty difficulty, int baid,
|
||||
int limit = 10)
|
||||
public async Task<(List<SongLeaderboard>, int)> GetSongLeaderboard(uint songId, Difficulty difficulty, int baid = 0,
|
||||
int page = 1, int limit = 10)
|
||||
{
|
||||
if (baid == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(baid));
|
||||
}
|
||||
// Get the total count of scores for the song
|
||||
var totalScores = await context.SongBestData
|
||||
.Where(x => x.SongId == songId && x.Difficulty == difficulty)
|
||||
.CountAsync();
|
||||
|
||||
// Calculate the total pages
|
||||
var totalPages = totalScores / limit;
|
||||
|
||||
// If there is a remainder, add one to the total pages
|
||||
if (totalScores % limit > 0)
|
||||
{
|
||||
totalPages++;
|
||||
}
|
||||
|
||||
// get all scores for the song from every user
|
||||
var scores = await context.SongBestData
|
||||
.Where(x => x.SongId == songId && x.Difficulty == difficulty)
|
||||
.OrderByDescending(x => x.BestScore)
|
||||
.ThenByDescending(x => x.BestRate)
|
||||
.Skip((page - 1) * limit) // Subtract 1 because page numbers now start at 1
|
||||
.Take(limit)
|
||||
.ToListAsync();
|
||||
|
||||
@ -41,10 +51,15 @@ public class SongLeaderboardService : ISongLeaderboardService
|
||||
var playDatum = await context.SongPlayData
|
||||
.Where(x => x.SongId == songId && x.Difficulty == difficulty && x.Baid == score.Baid)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
// calculate Rank based on page/limit
|
||||
var rank = await context.SongBestData
|
||||
.Where(x => x.SongId == songId && x.Difficulty == difficulty && x.BestScore > score.BestScore)
|
||||
.CountAsync();
|
||||
|
||||
leaderboard.Add(new SongLeaderboard
|
||||
{
|
||||
Rank = (uint)leaderboard.Count + 1,
|
||||
Rank = rank + 1,
|
||||
Baid = score.Baid,
|
||||
UserName = user?.MyDonName,
|
||||
BestScore = score.BestScore,
|
||||
@ -54,6 +69,11 @@ public class SongLeaderboardService : ISongLeaderboardService
|
||||
});
|
||||
}
|
||||
|
||||
if (baid == 0)
|
||||
{
|
||||
return (leaderboard, totalPages);
|
||||
}
|
||||
|
||||
// get current user score if it exists
|
||||
var currentUserScore = await context.SongBestData
|
||||
.Where(x => x.SongId == songId && x.Difficulty == difficulty && x.Baid == baid)
|
||||
@ -70,10 +90,14 @@ public class SongLeaderboardService : ISongLeaderboardService
|
||||
var user = await context.UserData
|
||||
.Where(x => x.Baid == baid)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
var rank = await context.SongBestData
|
||||
.Where(x => x.SongId == songId && x.Difficulty == difficulty && x.BestScore > currentUserScore.BestScore)
|
||||
.CountAsync();
|
||||
|
||||
leaderboard.Add(new SongLeaderboard
|
||||
{
|
||||
Rank = (uint)userRank + 1,
|
||||
Rank = rank + 1,
|
||||
Baid = currentUserScore.Baid,
|
||||
UserName = user?.MyDonName,
|
||||
BestScore = currentUserScore.BestScore,
|
||||
@ -84,6 +108,6 @@ public class SongLeaderboardService : ISongLeaderboardService
|
||||
}
|
||||
}
|
||||
|
||||
return leaderboard;
|
||||
return (leaderboard, totalPages);
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@
|
||||
</MudGrid>
|
||||
</MudCardHeader>
|
||||
<MudCardContent Class="pa-0">
|
||||
@if (response == null || response.Leaderboard.Count == 0)
|
||||
@if (response == null || response.LeaderboardData.Count == 0)
|
||||
{
|
||||
<MudGrid>
|
||||
<MudItem xs="12">
|
||||
@ -44,7 +44,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTable Loading="isLoading" Items="@response.Leaderboard" Class="leaderboard-table" Elevation="0" Outlined="false" Dense="true" Striped="true" Breakpoint=Breakpoint.None>
|
||||
<MudTable RowClassFunc="@GetActiveRowClass" Loading="isLoading" Items="@response.LeaderboardData" Class="leaderboard-table" Elevation="0" Outlined="false" Dense="true" Striped="true">
|
||||
<HeaderContent>
|
||||
<MudTh>@Localizer["Rank"]</MudTh>
|
||||
<MudTh>@Localizer["Player"]</MudTh>
|
||||
@ -57,14 +57,14 @@
|
||||
<MudTd>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Baseline">
|
||||
<MudText Typo="Typo.body1">@context.UserName</MudText>
|
||||
<MudText Typo="Typo.caption">(@Localizer["ID"]: @context.Baid)</MudText>
|
||||
<MudText Typo="Typo.caption" Style="color: #9E9E9E">(@Localizer["ID"]: @context.Baid)</MudText>
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
<MudTd>@context.BestScore</MudTd>
|
||||
<MudTd>
|
||||
@if (context.BestScoreRank is not ScoreRank.None)
|
||||
{
|
||||
<img src="@($"/images/rank_{context.BestScoreRank}.png")" alt="@(ScoreUtils.GetRankText(context.BestScoreRank))" title="@(ScoreUtils.GetRankText(context.BestScoreRank))" style="@Constants.ICON_STYLE"/>
|
||||
<img src="@($"/images/rank_{context.BestScoreRank}.png")" alt="@(ScoreUtils.GetRankText(context.BestScoreRank))" title="@(ScoreUtils.GetRankText(context.BestScoreRank))" style="@Constants.ICON_STYLE"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -75,6 +75,14 @@
|
||||
<img src="@($"/images/crown_{context.BestCrown}.png")" alt="@(ScoreUtils.GetCrownText(context.BestCrown))" title="@(ScoreUtils.GetCrownText(context.BestCrown))" style="@Constants.ICON_STYLE"/>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
<PagerContent>
|
||||
@if (TotalPages > 1)
|
||||
{
|
||||
<div class="d-flex flex-column align-center">
|
||||
<MudPagination Class="pa-4" Rectangular="true" DisableElevation="true" Count="@TotalPages" Selected="currentPage" SelectedChanged="(page) => OnPageChange(page)" BoundaryCount="1" MiddleCount="3" />
|
||||
</div>
|
||||
}
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
}
|
||||
</MudCardContent>
|
||||
|
@ -15,8 +15,21 @@ public partial class SongLeaderboardCard
|
||||
public Difficulty Difficulty { get; set; } = Difficulty.None;
|
||||
|
||||
private string SelectedDifficulty { get; set; } = "None";
|
||||
private int TotalPages { get; set; } = 0;
|
||||
|
||||
private bool isLoading = true;
|
||||
private int currentPage = 1;
|
||||
private int pageSize = 10;
|
||||
|
||||
private async Task GetLeaderboardData()
|
||||
{
|
||||
isLoading = true;
|
||||
response = await Client.GetFromJsonAsync<SongLeaderboardResponse>($"api/SongLeaderboard/{(uint)SongId}?baid={(uint)Baid}&difficulty={(uint)Difficulty}&page={currentPage}&limit={pageSize}");
|
||||
response.ThrowIfNull();
|
||||
|
||||
TotalPages = response.TotalPages;
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@ -37,22 +50,32 @@ public partial class SongLeaderboardCard
|
||||
Difficulty = Difficulty.Easy;
|
||||
}
|
||||
|
||||
response = await Client.GetFromJsonAsync<SongLeaderboardResponse>($"api/SongLeaderboard/{(uint)SongId}?baid={(uint)Baid}&difficulty={(uint)Difficulty}");
|
||||
response.ThrowIfNull();
|
||||
await GetLeaderboardData();
|
||||
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
private async Task OnDifficultyChange(string difficulty)
|
||||
private async Task OnDifficultyChange(string difficulty = "None")
|
||||
{
|
||||
isLoading = true;
|
||||
SelectedDifficulty = difficulty;
|
||||
Difficulty = Enum.Parse<Difficulty>(SelectedDifficulty);
|
||||
|
||||
await LocalStorage.SetItemAsync("songPageDifficulty", SelectedDifficulty);
|
||||
await GetLeaderboardData();
|
||||
|
||||
response = await Client.GetFromJsonAsync<SongLeaderboardResponse>($"api/SongLeaderboard/{(uint)SongId}?baid={(uint)Baid}&difficulty={(uint)Difficulty}");
|
||||
response.ThrowIfNull();
|
||||
currentPage = 1;
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
private async Task OnPageChange(int page)
|
||||
{
|
||||
currentPage = page;
|
||||
await GetLeaderboardData();
|
||||
}
|
||||
|
||||
private string GetActiveRowClass(SongLeaderboard leaderboard, int index)
|
||||
{
|
||||
return leaderboard.Baid == Baid ? "is-current-user" : "";
|
||||
}
|
||||
}
|
@ -55,6 +55,16 @@
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
tr.is-current-user {
|
||||
background-color: #d6e5f8 !important;
|
||||
}
|
||||
|
||||
tr.is-current-user td,
|
||||
tr.is-current-user span,
|
||||
tr.is-current-user p {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.lang-menu-item .mud-list-item-icon {
|
||||
min-width: 26px;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user