1
0
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:
Dean Herbert
2025-03-15 14:36:27 +09:00
committed by GitHub
Unverified
15 changed files with 271 additions and 168 deletions
@@ -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,
};
}
+1 -5
View File
@@ -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,
};
}
}
+8 -18
View File
@@ -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;
}
}
}
+42 -12
View File
@@ -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