1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-06 06:57:39 +08:00

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.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
@ -72,40 +73,93 @@ namespace osu.Game.Screens.Multi.Ranking
lowerScoresCursor = userScore.ScoresAround.Lower.Cursor;
}
success(allScores);
performSuccessCallback(scoresCallback, allScores);
};
userScoreReq.Failure += _ =>
{
// Fallback to a normal index.
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();
api.Queue(indexReq);
};
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.
// 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)
default:
cursor = lowerScoresCursor;
sort = MultiplayerScoresSort.Descending;
break;
}
if (cursor == null)
return null;
var indexReq = new IndexPlaylistScoresRequest(roomId, playlistItem.ID, cursor, sort);
indexReq.Success += r =>
{
switch (direction)
{
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();
});
case -1:
higherScoresCursor = r.Cursor;
break;
default:
lowerScoresCursor = r.Cursor;
break;
}
// Invoke callback to add the scores. Exclude the user's current score which was added previously.
scoresCallback?.Invoke(scoreInfos.Where(s => s.ID != Score?.OnlineScoreID));
performSuccessCallback(scoresCallback, r.Scores);
};
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();
var req = FetchScores(scores => Schedule(() =>
{
foreach (var s in scores)
addScore(s);
}));
var req = FetchScores(fetchScoresCallback);
if (req != null)
api.Queue(req);
@ -176,6 +172,29 @@ namespace osu.Game.Screens.Ranking
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>
/// Performs a fetch/refresh of scores to be displayed.
/// </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>
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)
{
base.OnEntering(last);

View File

@ -26,6 +26,10 @@ namespace osu.Game.Screens.Ranking
/// </summary>
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>
/// An action to be invoked if a <see cref="ScorePanel"/> is clicked while in an expanded state.
/// </summary>