mirror of
https://github.com/ppy/osu.git
synced 2026-05-22 10:30:00 +08:00
Merge pull request #32346 from bdach/user-tags-on-results
Add ability to vote for beatmap user tags after completing a play
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Scoring;
|
||||
@@ -12,7 +13,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public partial class TestSceneOverallRanking : OsuTestScene
|
||||
{
|
||||
private OverallRanking overallRanking = null!;
|
||||
private readonly Bindable<ScoreBasedUserStatisticsUpdate?> statisticsUpdate = new Bindable<ScoreBasedUserStatisticsUpdate?>();
|
||||
|
||||
[Test]
|
||||
public void TestUpdatePending()
|
||||
@@ -104,14 +105,19 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
displayUpdate(statistics, statistics);
|
||||
}
|
||||
|
||||
private void createDisplay() => AddStep("create display", () => Child = overallRanking = new OverallRanking
|
||||
private void createDisplay() => AddStep("create display", () =>
|
||||
{
|
||||
Width = 400,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
statisticsUpdate.Value = null;
|
||||
Child = new OverallRanking(new ScoreInfo())
|
||||
{
|
||||
Width = 400,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
DisplayedUpdate = { BindTarget = statisticsUpdate }
|
||||
};
|
||||
});
|
||||
|
||||
private void displayUpdate(UserStatistics before, UserStatistics after) =>
|
||||
AddStep("display update", () => overallRanking.StatisticsUpdate.Value = new ScoreBasedUserStatisticsUpdate(new ScoreInfo(), before, after));
|
||||
AddStep("display update", () => statisticsUpdate.Value = new ScoreBasedUserStatisticsUpdate(new ScoreInfo(), before, after));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
: base(score)
|
||||
{
|
||||
AllowRetry = true;
|
||||
ShowUserStatistics = true;
|
||||
IsLocalPlay = true;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
|
||||
@@ -11,6 +11,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
@@ -18,6 +19,9 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@@ -36,6 +40,8 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public partial class TestSceneStatisticsPanel : OsuTestScene
|
||||
{
|
||||
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
|
||||
|
||||
[Test]
|
||||
public void TestScoreWithPositionStatistics()
|
||||
{
|
||||
@@ -137,62 +143,114 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
CachedDependencies = [(typeof(UserStatisticsWatcher), userStatisticsWatcher)],
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new UserStatisticsPanel(score)
|
||||
Child = new StatisticsPanel
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
State = { Value = Visibility.Visible },
|
||||
Score = { Value = score, }
|
||||
Score = { Value = score, },
|
||||
AchievedScore = score,
|
||||
}
|
||||
});
|
||||
AddUntilStep("overall ranking present", () => this.ChildrenOfType<OverallRanking>().Any());
|
||||
AddUntilStep("loading spinner not visible", () => this.ChildrenOfType<LoadingLayer>().All(l => l.State.Value == Visibility.Hidden));
|
||||
AddUntilStep("loading spinner not visible",
|
||||
() => this.ChildrenOfType<OverallRanking>().Single()
|
||||
.ChildrenOfType<LoadingLayer>().All(l => l.State.Value == Visibility.Hidden));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTagging()
|
||||
{
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
|
||||
AddStep("set up network requests", () =>
|
||||
{
|
||||
dummyAPI.HandleRequest = request =>
|
||||
{
|
||||
switch (request)
|
||||
{
|
||||
case ListTagsRequest listTagsRequest:
|
||||
{
|
||||
Scheduler.AddDelayed(() => listTagsRequest.TriggerSuccess(new APITagCollection
|
||||
{
|
||||
Tags =
|
||||
[
|
||||
new APITag { Id = 1, Name = "tech", Description = "Tests uncommon skills.", },
|
||||
new APITag { Id = 2, Name = "alt", Description = "Colloquial term for maps which use rhythms that encourage the player to alternate notes. Typically distinct from burst or stream maps.", },
|
||||
new APITag { Id = 3, Name = "aim", Description = "Category for difficulty relating to cursor movement.", },
|
||||
new APITag { Id = 4, Name = "tap", Description = "Category for difficulty relating to tapping input.", },
|
||||
]
|
||||
}), 500);
|
||||
return true;
|
||||
}
|
||||
|
||||
case GetBeatmapSetRequest getBeatmapSetRequest:
|
||||
{
|
||||
var beatmapSet = CreateAPIBeatmapSet(score.BeatmapInfo);
|
||||
beatmapSet.Beatmaps.Single().TopTags =
|
||||
[
|
||||
new APIBeatmapTag { TagId = 3, VoteCount = 9 },
|
||||
];
|
||||
Scheduler.AddDelayed(() => getBeatmapSetRequest.TriggerSuccess(beatmapSet), 500);
|
||||
return true;
|
||||
}
|
||||
|
||||
case AddBeatmapTagRequest:
|
||||
case RemoveBeatmapTagRequest:
|
||||
{
|
||||
Scheduler.AddDelayed(request.TriggerSuccess, 500);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
});
|
||||
AddStep("load panel", () =>
|
||||
{
|
||||
Child = new PopoverContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new StatisticsPanel
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
State = { Value = Visibility.Visible },
|
||||
Score = { Value = score },
|
||||
AchievedScore = score,
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTaggingWhenRankTooLow()
|
||||
{
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Rank = ScoreRank.D;
|
||||
|
||||
AddStep("load panel", () =>
|
||||
{
|
||||
Child = new PopoverContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new StatisticsPanel
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
State = { Value = Visibility.Visible },
|
||||
Score = { Value = score },
|
||||
AchievedScore = score,
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void loadPanel(ScoreInfo score) => AddStep("load panel", () =>
|
||||
{
|
||||
Child = new UserStatisticsPanel(score)
|
||||
Child = new StatisticsPanel
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
State = { Value = Visibility.Visible },
|
||||
Score = { Value = score },
|
||||
DisplayedUserStatisticsUpdate =
|
||||
{
|
||||
Value = new ScoreBasedUserStatisticsUpdate(score, new UserStatistics
|
||||
{
|
||||
Level = new UserStatistics.LevelInfo
|
||||
{
|
||||
Current = 5,
|
||||
Progress = 20,
|
||||
},
|
||||
GlobalRank = 38000,
|
||||
CountryRank = 12006,
|
||||
PP = 2134,
|
||||
RankedScore = 21123849,
|
||||
Accuracy = 0.985,
|
||||
PlayCount = 13375,
|
||||
PlayTime = 354490,
|
||||
TotalScore = 128749597,
|
||||
TotalHits = 0,
|
||||
MaxCombo = 1233,
|
||||
}, new UserStatistics
|
||||
{
|
||||
Level = new UserStatistics.LevelInfo
|
||||
{
|
||||
Current = 5,
|
||||
Progress = 30,
|
||||
},
|
||||
GlobalRank = 36000,
|
||||
CountryRank = 12000,
|
||||
PP = (decimal)2134.5,
|
||||
RankedScore = 23897015,
|
||||
Accuracy = 0.984,
|
||||
PlayCount = 13376,
|
||||
PlayTime = 35789,
|
||||
TotalScore = 132218497,
|
||||
TotalHits = 0,
|
||||
MaxCombo = 1233,
|
||||
})
|
||||
}
|
||||
AchievedScore = score,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
Child = new PopoverContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new UserTagControl
|
||||
Child = new UserTagControl(Beatmap.Value.BeatmapInfo)
|
||||
{
|
||||
Width = 500,
|
||||
Anchor = Anchor.Centre,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Globalization;
|
||||
using System.Net.Http;
|
||||
using osu.Framework.IO.Network;
|
||||
|
||||
@@ -22,10 +21,9 @@ namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
var req = base.CreateWebRequest();
|
||||
req.Method = HttpMethod.Post;
|
||||
req.AddParameter(@"tag_id", TagID.ToString(CultureInfo.InvariantCulture), RequestParameterType.Query);
|
||||
return req;
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmaps/{BeatmapID}/tags";
|
||||
protected override string Target => $@"beatmaps/{BeatmapID}/tags/{TagID}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -13,7 +14,9 @@ using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Screens.Edit.GameplayTest
|
||||
@@ -228,5 +231,7 @@ namespace osu.Game.Screens.Edit.GameplayTest
|
||||
editor.RestoreState(editorState);
|
||||
return base.OnExiting(e);
|
||||
}
|
||||
|
||||
protected override ResultsScreen CreateResults(ScoreInfo score) => throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,11 +198,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
return multiplayerLeaderboard.TeamScores.Count == 2
|
||||
? new MultiplayerTeamResultsScreen(score, Room.RoomID.Value, PlaylistItem, multiplayerLeaderboard.TeamScores)
|
||||
{
|
||||
ShowUserStatistics = true,
|
||||
IsLocalPlay = true,
|
||||
}
|
||||
: new MultiplayerResultsScreen(score, Room.RoomID.Value, PlaylistItem)
|
||||
{
|
||||
ShowUserStatistics = true
|
||||
IsLocalPlay = true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
return new PlaylistItemScoreResultsScreen(score, Room.RoomID.Value, PlaylistItem)
|
||||
{
|
||||
AllowRetry = true,
|
||||
ShowUserStatistics = true,
|
||||
IsLocalPlay = true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1276,11 +1276,7 @@ namespace osu.Game.Screens.Play
|
||||
/// </summary>
|
||||
/// <param name="score">The <see cref="ScoreInfo"/> to be displayed in the results screen.</param>
|
||||
/// <returns>The <see cref="ResultsScreen"/>.</returns>
|
||||
protected virtual ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score)
|
||||
{
|
||||
AllowRetry = true,
|
||||
ShowUserStatistics = true,
|
||||
};
|
||||
protected abstract ResultsScreen CreateResults(ScoreInfo score);
|
||||
|
||||
private void fadeOut()
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@ using osu.Game.Online.Rooms;
|
||||
using osu.Game.Online.Spectator;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
@@ -323,5 +324,11 @@ namespace osu.Game.Screens.Play
|
||||
api.Queue(request);
|
||||
return scoreSubmissionSource.Task;
|
||||
}
|
||||
|
||||
protected override ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score)
|
||||
{
|
||||
AllowRetry = true,
|
||||
IsLocalPlay = true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,11 +79,10 @@ namespace osu.Game.Screens.Ranking
|
||||
public bool AllowWatchingReplay { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the user's personal statistics should be shown on the extended statistics panel
|
||||
/// after clicking the score panel associated with the <see cref="Score"/> being presented.
|
||||
/// Requires <see cref="Score"/> to be present.
|
||||
/// Whether the provided score is for a local user's play.
|
||||
/// This will trigger elements like the user's ranking to display.
|
||||
/// </summary>
|
||||
public bool ShowUserStatistics { get; init; }
|
||||
public bool IsLocalPlay { get; init; }
|
||||
|
||||
private Sample? popInSample;
|
||||
|
||||
@@ -121,11 +120,12 @@ namespace osu.Game.Screens.Ranking
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new GlobalScrollAdjustsVolume(),
|
||||
StatisticsPanel = createStatisticsPanel().With(panel =>
|
||||
StatisticsPanel = new StatisticsPanel
|
||||
{
|
||||
panel.RelativeSizeAxes = Axes.Both;
|
||||
panel.Score.BindTarget = SelectedScore;
|
||||
}),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Score = { BindTarget = SelectedScore },
|
||||
AchievedScore = IsLocalPlay && Score != null ? Score : null,
|
||||
},
|
||||
ScorePanelList = new ScorePanelList
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@@ -353,16 +353,6 @@ namespace osu.Game.Screens.Ranking
|
||||
/// <param name="direction">The fetch direction. -1 to fetch scores greater than the current start of the list, and 1 to fetch scores lower than the current end of the list.</param>
|
||||
protected virtual Task<ScoreInfo[]> FetchNextPage(int direction) => Task.FromResult<ScoreInfo[]>([]);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="Statistics.StatisticsPanel"/> to be used to display extended information about scores.
|
||||
/// </summary>
|
||||
private StatisticsPanel createStatisticsPanel()
|
||||
{
|
||||
return ShowUserStatistics && Score != null
|
||||
? new UserStatisticsPanel(Score)
|
||||
: new StatisticsPanel();
|
||||
}
|
||||
|
||||
private Task addScores(ScoreInfo[] scores)
|
||||
{
|
||||
var tcs = new TaskCompletionSource();
|
||||
|
||||
@@ -14,10 +14,13 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Placeholders;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking.Statistics.User;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Statistics
|
||||
@@ -28,11 +31,21 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
|
||||
public readonly Bindable<ScoreInfo?> Score = new Bindable<ScoreInfo?>();
|
||||
|
||||
/// <summary>
|
||||
/// The score which was achieved by the local user.
|
||||
/// If this is set to a non-null score, an <see cref="OverallRanking"/> component will be displayed showing changes to the local user's ranking and statistics
|
||||
/// when a statistics update related to this score is received from spectator server.
|
||||
/// </summary>
|
||||
public ScoreInfo? AchievedScore { get; init; }
|
||||
|
||||
protected override bool StartHidden => true;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmapManager { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; } = null!;
|
||||
|
||||
private readonly Container content;
|
||||
private readonly LoadingSpinner spinner;
|
||||
|
||||
@@ -97,7 +110,7 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
bool hitEventsAvailable = newScore.HitEvents.Count != 0;
|
||||
Container<Drawable> container;
|
||||
|
||||
var statisticItems = CreateStatisticItems(newScore, task.GetResultSafely());
|
||||
var statisticItems = CreateStatisticItems(newScore, task.GetResultSafely()).ToArray();
|
||||
|
||||
if (!hitEventsAvailable && statisticItems.All(c => c.RequiresHitEvents))
|
||||
{
|
||||
@@ -199,8 +212,53 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
/// </summary>
|
||||
/// <param name="newScore">The score to create the rows for.</param>
|
||||
/// <param name="playableBeatmap">The beatmap on which the score was set.</param>
|
||||
protected virtual ICollection<StatisticItem> CreateStatisticItems(ScoreInfo newScore, IBeatmap playableBeatmap)
|
||||
=> newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, playableBeatmap);
|
||||
protected virtual IEnumerable<StatisticItem> CreateStatisticItems(ScoreInfo newScore, IBeatmap playableBeatmap)
|
||||
{
|
||||
foreach (var statistic in newScore.Ruleset.CreateInstance().CreateStatisticsForScore(newScore, playableBeatmap))
|
||||
yield return statistic;
|
||||
|
||||
if (AchievedScore != null
|
||||
&& newScore.UserID > 1
|
||||
&& newScore.UserID == AchievedScore.UserID
|
||||
&& newScore.OnlineID > 0
|
||||
&& newScore.OnlineID == AchievedScore.OnlineID)
|
||||
{
|
||||
yield return new StatisticItem("Overall Ranking", () => new OverallRanking(newScore)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
}
|
||||
|
||||
if (AchievedScore != null
|
||||
&& newScore.BeatmapInfo!.OnlineID > 0
|
||||
&& api.IsLoggedIn)
|
||||
{
|
||||
if (
|
||||
// We may want to iterate on this condition
|
||||
AchievedScore.Rank >= ScoreRank.C
|
||||
)
|
||||
{
|
||||
yield return new StatisticItem("Tag the beatmap!", () => new UserTagControl(newScore.BeatmapInfo)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new StatisticItem("Tag the beatmap!", () => new OsuTextFlowContainer(cp => cp.Font = OsuFont.GetFont(size: StatisticItem.FONT_SIZE, weight: FontWeight.SemiBold))
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
TextAnchor = Anchor.Centre,
|
||||
Text = "Set a better score to contribute to beatmap tags!",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
|
||||
@@ -5,8 +5,10 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Statistics.User
|
||||
{
|
||||
@@ -14,13 +16,21 @@ namespace osu.Game.Screens.Ranking.Statistics.User
|
||||
{
|
||||
private const float transition_duration = 300;
|
||||
|
||||
public Bindable<ScoreBasedUserStatisticsUpdate?> StatisticsUpdate { get; } = new Bindable<ScoreBasedUserStatisticsUpdate?>();
|
||||
public Bindable<ScoreBasedUserStatisticsUpdate?> DisplayedUpdate { get; } = new Bindable<ScoreBasedUserStatisticsUpdate?>();
|
||||
private readonly IBindable<ScoreBasedUserStatisticsUpdate?> latestGlobalStatisticsUpdate = new Bindable<ScoreBasedUserStatisticsUpdate?>();
|
||||
|
||||
private readonly ScoreInfo scoreInfo;
|
||||
|
||||
private LoadingLayer loadingLayer = null!;
|
||||
private GridContainer content = null!;
|
||||
|
||||
public OverallRanking(ScoreInfo scoreInfo)
|
||||
{
|
||||
this.scoreInfo = scoreInfo;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(UserStatisticsWatcher? userStatisticsWatcher)
|
||||
{
|
||||
AutoSizeAxes = Axes.Y;
|
||||
AutoSizeEasing = Easing.OutQuint;
|
||||
@@ -55,34 +65,44 @@ namespace osu.Game.Screens.Ranking.Statistics.User
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
new GlobalRankChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } },
|
||||
new GlobalRankChangeRow { StatisticsUpdate = { BindTarget = DisplayedUpdate } },
|
||||
new SimpleStatisticTable.Spacer(),
|
||||
new PerformancePointsChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } },
|
||||
new PerformancePointsChangeRow { StatisticsUpdate = { BindTarget = DisplayedUpdate } },
|
||||
},
|
||||
[],
|
||||
new Drawable[]
|
||||
{
|
||||
new MaximumComboChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } },
|
||||
new MaximumComboChangeRow { StatisticsUpdate = { BindTarget = DisplayedUpdate } },
|
||||
new SimpleStatisticTable.Spacer(),
|
||||
new AccuracyChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } },
|
||||
new AccuracyChangeRow { StatisticsUpdate = { BindTarget = DisplayedUpdate } },
|
||||
},
|
||||
[],
|
||||
new Drawable[]
|
||||
{
|
||||
new RankedScoreChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } },
|
||||
new RankedScoreChangeRow { StatisticsUpdate = { BindTarget = DisplayedUpdate } },
|
||||
new SimpleStatisticTable.Spacer(),
|
||||
new TotalScoreChangeRow { StatisticsUpdate = { BindTarget = StatisticsUpdate } },
|
||||
new TotalScoreChangeRow { StatisticsUpdate = { BindTarget = DisplayedUpdate } },
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (userStatisticsWatcher != null)
|
||||
{
|
||||
latestGlobalStatisticsUpdate.BindTo(userStatisticsWatcher.LatestUpdate);
|
||||
latestGlobalStatisticsUpdate.BindValueChanged(update =>
|
||||
{
|
||||
if (update.NewValue?.Score.MatchesOnlineID(scoreInfo) == true)
|
||||
DisplayedUpdate.Value = update.NewValue;
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
StatisticsUpdate.BindValueChanged(onUpdateReceived, true);
|
||||
DisplayedUpdate.BindValueChanged(onUpdateReceived, true);
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking.Statistics.User;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Statistics
|
||||
{
|
||||
public partial class UserStatisticsPanel : StatisticsPanel
|
||||
{
|
||||
private readonly ScoreInfo achievedScore;
|
||||
|
||||
internal readonly Bindable<ScoreBasedUserStatisticsUpdate?> DisplayedUserStatisticsUpdate = new Bindable<ScoreBasedUserStatisticsUpdate?>();
|
||||
|
||||
private IBindable<ScoreBasedUserStatisticsUpdate?> latestGlobalStatisticsUpdate = null!;
|
||||
|
||||
public UserStatisticsPanel(ScoreInfo achievedScore)
|
||||
{
|
||||
this.achievedScore = achievedScore;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(UserStatisticsWatcher? userStatisticsWatcher)
|
||||
{
|
||||
if (userStatisticsWatcher != null)
|
||||
{
|
||||
latestGlobalStatisticsUpdate = userStatisticsWatcher.LatestUpdate.GetBoundCopy();
|
||||
latestGlobalStatisticsUpdate.BindValueChanged(update =>
|
||||
{
|
||||
if (update.NewValue?.Score.MatchesOnlineID(achievedScore) == true)
|
||||
DisplayedUserStatisticsUpdate.Value = update.NewValue;
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override ICollection<StatisticItem> CreateStatisticItems(ScoreInfo newScore, IBeatmap playableBeatmap)
|
||||
{
|
||||
var items = base.CreateStatisticItems(newScore, playableBeatmap);
|
||||
|
||||
if (newScore.UserID > 1
|
||||
&& newScore.UserID == achievedScore.UserID
|
||||
&& newScore.OnlineID > 0
|
||||
&& newScore.OnlineID == achievedScore.OnlineID)
|
||||
{
|
||||
items = items.Append(new StatisticItem("Overall Ranking", () => new OverallRanking
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
StatisticsUpdate = { BindTarget = DisplayedUserStatisticsUpdate }
|
||||
})).ToArray();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,11 @@ using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterfaceV2;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
@@ -37,6 +39,8 @@ namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
public partial class UserTagControl : CompositeDrawable
|
||||
{
|
||||
private readonly BeatmapInfo beatmapInfo;
|
||||
|
||||
public override bool HandlePositionalInput => true;
|
||||
|
||||
private readonly Cached layout = new Cached();
|
||||
@@ -53,8 +57,10 @@ namespace osu.Game.Screens.Ranking
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private Bindable<WorkingBeatmap> beatmap { get; set; } = null!;
|
||||
public UserTagControl(BeatmapInfo beatmapInfo)
|
||||
{
|
||||
this.beatmapInfo = beatmapInfo;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(SessionStatics sessionStatics)
|
||||
@@ -104,8 +110,8 @@ namespace osu.Game.Screens.Ranking
|
||||
api.Queue(listTagsRequest);
|
||||
}
|
||||
|
||||
var getBeatmapSetRequest = new GetBeatmapSetRequest(beatmap.Value.BeatmapInfo.BeatmapSet!.OnlineID);
|
||||
getBeatmapSetRequest.Success += set => apiBeatmap.Value = set.Beatmaps.SingleOrDefault(b => b.MatchesOnlineID(beatmap.Value.BeatmapInfo));
|
||||
var getBeatmapSetRequest = new GetBeatmapSetRequest(beatmapInfo.BeatmapSet!.OnlineID);
|
||||
getBeatmapSetRequest.Success += set => apiBeatmap.Value = set.Beatmaps.SingleOrDefault(b => b.MatchesOnlineID(beatmapInfo));
|
||||
api.Queue(getBeatmapSetRequest);
|
||||
}
|
||||
|
||||
@@ -114,7 +120,7 @@ namespace osu.Game.Screens.Ranking
|
||||
loadingLayer.Show();
|
||||
extraTags.Remove(tag);
|
||||
|
||||
var req = new AddBeatmapTagRequest(beatmap.Value.BeatmapInfo.OnlineID, tag.Id);
|
||||
var req = new AddBeatmapTagRequest(beatmapInfo.OnlineID, tag.Id);
|
||||
req.Success += () =>
|
||||
{
|
||||
tag.Voted.Value = true;
|
||||
@@ -495,21 +501,45 @@ namespace osu.Game.Screens.Ranking
|
||||
searchBox.Current.BindValueChanged(_ => searchContainer.SearchTerm = searchBox.Current.Value, true);
|
||||
}
|
||||
|
||||
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||
{
|
||||
if (base.OnPressed(e))
|
||||
return true;
|
||||
|
||||
if (e.Repeat)
|
||||
return false;
|
||||
|
||||
if (State.Value == Visibility.Hidden)
|
||||
return false;
|
||||
|
||||
if (e.Action == GlobalAction.Select)
|
||||
{
|
||||
attemptSelect();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(KeyDownEvent e)
|
||||
{
|
||||
var visibleItems = searchContainer.OfType<DrawableAddableTag>().Where(d => d.IsPresent).ToArray();
|
||||
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
if (visibleItems.Length == 1)
|
||||
select(visibleItems.Single().Tag);
|
||||
|
||||
attemptSelect();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnKeyDown(e);
|
||||
}
|
||||
|
||||
private void attemptSelect()
|
||||
{
|
||||
var visibleItems = searchContainer.OfType<DrawableAddableTag>().Where(d => d.IsPresent).ToArray();
|
||||
|
||||
if (visibleItems.Length == 1)
|
||||
select(visibleItems.Single().Tag);
|
||||
}
|
||||
|
||||
private void select(UserTag tag)
|
||||
{
|
||||
OnSelected?.Invoke(tag);
|
||||
@@ -530,14 +560,14 @@ namespace osu.Game.Screens.Ranking
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(OsuColour colours, OverlayColourProvider? colourProvider)
|
||||
{
|
||||
Content.AddRange(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.GreySeaFoamDark,
|
||||
Colour = colourProvider?.Background3 ?? colours.GreySeaFoamDark,
|
||||
Depth = float.MaxValue,
|
||||
},
|
||||
new FillFlowContainer
|
||||
|
||||
Reference in New Issue
Block a user