Implement paging

This commit is contained in:
smoogipoo 2020-07-22 20:24:55 +09:00
parent b7790de66f
commit 46ea775cfb
3 changed files with 109 additions and 20 deletions

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -72,40 +73,93 @@ namespace osu.Game.Screens.Multi.Ranking
lowerScoresCursor = userScore.ScoresAround.Lower.Cursor; lowerScoresCursor = userScore.ScoresAround.Lower.Cursor;
} }
success(allScores); performSuccessCallback(scoresCallback, allScores);
}; };
userScoreReq.Failure += _ => userScoreReq.Failure += _ =>
{ {
// Fallback to a normal index. // Fallback to a normal index.
var indexReq = new IndexPlaylistScoresRequest(roomId, playlistItem.ID); var indexReq = new IndexPlaylistScoresRequest(roomId, playlistItem.ID);
indexReq.Success += r => success(r.Scores);
indexReq.Success += r =>
{
performSuccessCallback(scoresCallback, r.Scores);
lowerScoresCursor = r.Cursor;
};
indexReq.Failure += __ => loadingLayer.Hide(); indexReq.Failure += __ => loadingLayer.Hide();
api.Queue(indexReq); api.Queue(indexReq);
}; };
return userScoreReq; return userScoreReq;
}
void success(List<MultiplayerScore> scores) protected override APIRequest FetchNextPage(int direction, Action<IEnumerable<ScoreInfo>> scoresCallback)
{
Debug.Assert(direction == 1 || direction == -1);
Cursor cursor;
MultiplayerScoresSort sort;
switch (direction)
{ {
var scoreInfos = new List<ScoreInfo>(scores.Select(s => s.CreateScoreInfo(playlistItem))); case -1:
cursor = higherScoresCursor;
sort = MultiplayerScoresSort.Ascending;
break;
// Select a score if we don't already have one selected. default:
// Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll). cursor = lowerScoresCursor;
if (SelectedScore.Value == null) sort = MultiplayerScoresSort.Descending;
break;
}
if (cursor == null)
return null;
var indexReq = new IndexPlaylistScoresRequest(roomId, playlistItem.ID, cursor, sort);
indexReq.Success += r =>
{
switch (direction)
{ {
Schedule(() => case -1:
{ higherScoresCursor = r.Cursor;
// Prefer selecting the local user's score, or otherwise default to the first visible score. break;
SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.Id == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault();
}); default:
lowerScoresCursor = r.Cursor;
break;
} }
// Invoke callback to add the scores. Exclude the user's current score which was added previously. performSuccessCallback(scoresCallback, r.Scores);
scoresCallback?.Invoke(scoreInfos.Where(s => s.ID != Score?.OnlineScoreID)); };
loadingLayer.Hide(); indexReq.Failure += _ => loadingLayer.Hide();
return indexReq;
}
private void performSuccessCallback(Action<IEnumerable<ScoreInfo>> callback, List<MultiplayerScore> scores)
{
var scoreInfos = new List<ScoreInfo>(scores.Select(s => s.CreateScoreInfo(playlistItem)));
// Select a score if we don't already have one selected.
// Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll).
if (SelectedScore.Value == null)
{
Schedule(() =>
{
// Prefer selecting the local user's score, or otherwise default to the first visible score.
SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.Id == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault();
});
} }
// Invoke callback to add the scores. Exclude the user's current score which was added previously.
callback?.Invoke(scoreInfos.Where(s => s.ID != Score?.OnlineScoreID));
loadingLayer.Hide();
} }
} }
} }

View File

@ -164,11 +164,7 @@ namespace osu.Game.Screens.Ranking
{ {
base.LoadComplete(); base.LoadComplete();
var req = FetchScores(scores => Schedule(() => var req = FetchScores(fetchScoresCallback);
{
foreach (var s in scores)
addScore(s);
}));
if (req != null) if (req != null)
api.Queue(req); api.Queue(req);
@ -176,6 +172,29 @@ namespace osu.Game.Screens.Ranking
statisticsPanel.State.BindValueChanged(onStatisticsStateChanged, true); statisticsPanel.State.BindValueChanged(onStatisticsStateChanged, true);
} }
private APIRequest nextPageRequest;
protected override void Update()
{
base.Update();
if (hasAnyScores && nextPageRequest == null)
{
if (scorePanelList.IsScrolledToStart)
nextPageRequest = FetchNextPage(-1, fetchScoresCallback);
else if (scorePanelList.IsScrolledToEnd)
nextPageRequest = FetchNextPage(1, fetchScoresCallback);
if (nextPageRequest != null)
{
nextPageRequest.Success += () => nextPageRequest = null;
nextPageRequest.Failure += _ => nextPageRequest = null;
api.Queue(nextPageRequest);
}
}
}
/// <summary> /// <summary>
/// Performs a fetch/refresh of scores to be displayed. /// Performs a fetch/refresh of scores to be displayed.
/// </summary> /// </summary>
@ -183,6 +202,18 @@ namespace osu.Game.Screens.Ranking
/// <returns>An <see cref="APIRequest"/> responsible for the fetch operation. This will be queued and performed automatically.</returns> /// <returns>An <see cref="APIRequest"/> responsible for the fetch operation. This will be queued and performed automatically.</returns>
protected virtual APIRequest FetchScores(Action<IEnumerable<ScoreInfo>> scoresCallback) => null; protected virtual APIRequest FetchScores(Action<IEnumerable<ScoreInfo>> scoresCallback) => null;
protected virtual APIRequest FetchNextPage(int direction, Action<IEnumerable<ScoreInfo>> scoresCallback) => null;
private bool hasAnyScores;
private void fetchScoresCallback(IEnumerable<ScoreInfo> scores) => Schedule(() =>
{
foreach (var s in scores)
addScore(s);
hasAnyScores = true;
});
public override void OnEntering(IScreen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);

View File

@ -26,6 +26,10 @@ namespace osu.Game.Screens.Ranking
/// </summary> /// </summary>
private const float expanded_panel_spacing = 15; private const float expanded_panel_spacing = 15;
public bool IsScrolledToStart => flow.Count > 0 && scroll.ScrollableExtent > 0 && scroll.Current <= 100;
public bool IsScrolledToEnd => flow.Count > 0 && scroll.ScrollableExtent > 0 && scroll.IsScrolledToEnd(100);
/// <summary> /// <summary>
/// An action to be invoked if a <see cref="ScorePanel"/> is clicked while in an expanded state. /// An action to be invoked if a <see cref="ScorePanel"/> is clicked while in an expanded state.
/// </summary> /// </summary>