1
0
mirror of synced 2025-02-17 19:19:18 +01:00

Merged from new-songs-ui branch

This commit is contained in:
S-Sebb 2024-06-05 14:57:10 +01:00
commit 4e13b4bfe1
8 changed files with 104 additions and 26 deletions

View File

@ -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; }
}

View File

@ -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; }

View File

@ -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
});
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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" : "";
}
}

View File

@ -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;
}