1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-15 14:47:18 +08:00

Add support for grouping by artist

This commit is contained in:
Dean Herbert 2025-02-05 18:59:29 +09:00
parent ea725e2caf
commit 11de429621
No known key found for this signature in database
5 changed files with 68 additions and 22 deletions

View File

@ -85,7 +85,8 @@ namespace osu.Game.Tests.Resources
/// </summary> /// </summary>
/// <param name="difficultyCount">Number of difficulties. If null, a random number between 1 and 20 will be used.</param> /// <param name="difficultyCount">Number of difficulties. If null, a random number between 1 and 20 will be used.</param>
/// <param name="rulesets">Rulesets to cycle through when creating difficulties. If <c>null</c>, osu! ruleset will be used.</param> /// <param name="rulesets">Rulesets to cycle through when creating difficulties. If <c>null</c>, osu! ruleset will be used.</param>
public static BeatmapSetInfo CreateTestBeatmapSetInfo(int? difficultyCount = null, RulesetInfo[] rulesets = null) /// <param name="randomiseMetadata">Whether to randomise metadata to create a better distribution.</param>
public static BeatmapSetInfo CreateTestBeatmapSetInfo(int? difficultyCount = null, RulesetInfo[] rulesets = null, bool randomiseMetadata = false)
{ {
int j = 0; int j = 0;
@ -95,13 +96,27 @@ namespace osu.Game.Tests.Resources
int setId = GetNextTestID(); int setId = GetNextTestID();
var metadata = new BeatmapMetadata char getRandomCharacter()
{ {
// Create random metadata, then we can check if sorting works based on these const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*";
Artist = "Some Artist " + RNG.Next(0, 9), return chars[RNG.Next(chars.Length)];
Title = $"Some Song (set id {setId:000}) {Guid.NewGuid()}", }
Author = { Username = "Some Guy " + RNG.Next(0, 9) },
}; var metadata = randomiseMetadata
? new BeatmapMetadata
{
// Create random metadata, then we can check if sorting works based on these
Artist = $"{getRandomCharacter()}ome Artist " + RNG.Next(0, 9),
Title = $"{getRandomCharacter()}ome Song (set id {setId:000}) {Guid.NewGuid()}",
Author = { Username = $"{getRandomCharacter()}ome Guy " + RNG.Next(0, 9) },
}
: new BeatmapMetadata
{
// Create random metadata, then we can check if sorting works based on these
Artist = "Some Artist " + RNG.Next(0, 9),
Title = $"Some Song (set id {setId:000}) {Guid.NewGuid()}",
Author = { Username = "Some Guy " + RNG.Next(0, 9) },
};
Logger.Log($"🛠️ Generating beatmap set \"{metadata}\" for test consumption."); Logger.Log($"🛠️ Generating beatmap set \"{metadata}\" for test consumption.");

View File

@ -193,7 +193,7 @@ namespace osu.Game.Tests.Visual.SongSelect
protected void AddBeatmaps(int count, int? fixedDifficultiesPerSet = null) => AddStep($"add {count} beatmaps", () => protected void AddBeatmaps(int count, int? fixedDifficultiesPerSet = null) => AddStep($"add {count} beatmaps", () =>
{ {
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
BeatmapSets.Add(TestResources.CreateTestBeatmapSetInfo(fixedDifficultiesPerSet ?? RNG.Next(1, 4))); BeatmapSets.Add(TestResources.CreateTestBeatmapSetInfo(fixedDifficultiesPerSet ?? RNG.Next(1, 4), randomiseMetadata: true));
}); });
protected void RemoveAllBeatmaps() => AddStep("clear all beatmaps", () => BeatmapSets.Clear()); protected void RemoveAllBeatmaps() => AddStep("clear all beatmaps", () => BeatmapSets.Clear());

View File

@ -51,6 +51,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{ {
AddBeatmaps(10); AddBeatmaps(10);
SortBy(new FilterCriteria { Group = GroupMode.Difficulty, Sort = SortMode.Difficulty }); SortBy(new FilterCriteria { Group = GroupMode.Difficulty, Sort = SortMode.Difficulty });
SortBy(new FilterCriteria { Group = GroupMode.Artist, Sort = SortMode.Artist });
SortBy(new FilterCriteria { Sort = SortMode.Artist }); SortBy(new FilterCriteria { Sort = SortMode.Artist });
} }

View File

@ -119,20 +119,12 @@ namespace osu.Game.Screens.SelectV2
return false; return false;
case BeatmapInfo beatmapInfo: case BeatmapInfo beatmapInfo:
// Find any containing group. There should never be too many groups so iterating is efficient enough.
GroupDefinition? containingGroup = grouping.GroupItems.SingleOrDefault(kvp => kvp.Value.Any(i => ReferenceEquals(i.Model, beatmapInfo))).Key;
// If we have groups, we need to account for them. if (containingGroup != null)
if (Criteria.SplitOutDifficulties) setExpandedGroup(containingGroup);
{ setExpandedSet(beatmapInfo);
// Find the containing group. There should never be too many groups so iterating is efficient enough.
GroupDefinition? group = grouping.GroupItems.SingleOrDefault(kvp => kvp.Value.Any(i => ReferenceEquals(i.Model, beatmapInfo))).Key;
if (group != null)
setExpandedGroup(group);
}
else
{
setExpandedSet(beatmapInfo);
}
return true; return true;
} }
@ -170,6 +162,7 @@ namespace osu.Game.Screens.SelectV2
{ {
if (grouping.GroupItems.TryGetValue(group, out var items)) if (grouping.GroupItems.TryGetValue(group, out var items))
{ {
// First pass ignoring set groupings.
foreach (var i in items) foreach (var i in items)
{ {
if (i.Model is GroupDefinition) if (i.Model is GroupDefinition)
@ -177,6 +170,16 @@ namespace osu.Game.Screens.SelectV2
else else
i.IsVisible = expanded; i.IsVisible = expanded;
} }
// Second pass to hide set children when not meant to be displayed.
if (expanded)
{
foreach (var i in items)
{
if (i.Model is BeatmapSetInfo set)
setExpansionStateOfSetItems(set, i.IsExpanded);
}
}
} }
} }

View File

@ -52,6 +52,33 @@ namespace osu.Game.Screens.SelectV2
newItems.AddRange(items); newItems.AddRange(items);
break; break;
case GroupMode.Artist:
groupSetsTogether = true;
char groupChar = (char)0;
foreach (var item in items)
{
cancellationToken.ThrowIfCancellationRequested();
var b = (BeatmapInfo)item.Model;
char beatmapFirstChar = char.ToUpperInvariant(b.Metadata.Artist[0]);
if (beatmapFirstChar > groupChar)
{
groupChar = beatmapFirstChar;
var groupDefinition = new GroupDefinition($"{groupChar}");
var groupItem = new CarouselItem(groupDefinition) { DrawHeight = GroupPanel.HEIGHT };
newItems.Add(groupItem);
groupItems[groupDefinition] = new HashSet<CarouselItem> { groupItem };
}
newItems.Add(item);
}
break;
case GroupMode.Difficulty: case GroupMode.Difficulty:
groupSetsTogether = false; groupSetsTogether = false;
int starGroup = int.MinValue; int starGroup = int.MinValue;
@ -91,7 +118,7 @@ namespace osu.Game.Screens.SelectV2
if (item.Model is BeatmapInfo beatmap) if (item.Model is BeatmapInfo beatmap)
{ {
bool newBeatmapSet = lastItem == null || (lastItem.Model is BeatmapInfo lastBeatmap && lastBeatmap.BeatmapSet!.ID != beatmap.BeatmapSet!.ID); bool newBeatmapSet = lastItem?.Model is not BeatmapInfo lastBeatmap || lastBeatmap.BeatmapSet!.ID != beatmap.BeatmapSet!.ID;
if (newBeatmapSet) if (newBeatmapSet)
{ {