1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-14 05:47:20 +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>
/// <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>
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;
@ -95,13 +96,27 @@ namespace osu.Game.Tests.Resources
int setId = GetNextTestID();
var metadata = new BeatmapMetadata
char getRandomCharacter()
{
// 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) },
};
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*";
return chars[RNG.Next(chars.Length)];
}
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.");

View File

@ -193,7 +193,7 @@ namespace osu.Game.Tests.Visual.SongSelect
protected void AddBeatmaps(int count, int? fixedDifficultiesPerSet = null) => AddStep($"add {count} beatmaps", () =>
{
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());

View File

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

View File

@ -119,20 +119,12 @@ namespace osu.Game.Screens.SelectV2
return false;
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 (Criteria.SplitOutDifficulties)
{
// 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);
}
if (containingGroup != null)
setExpandedGroup(containingGroup);
setExpandedSet(beatmapInfo);
return true;
}
@ -170,6 +162,7 @@ namespace osu.Game.Screens.SelectV2
{
if (grouping.GroupItems.TryGetValue(group, out var items))
{
// First pass ignoring set groupings.
foreach (var i in items)
{
if (i.Model is GroupDefinition)
@ -177,6 +170,16 @@ namespace osu.Game.Screens.SelectV2
else
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);
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:
groupSetsTogether = false;
int starGroup = int.MinValue;
@ -91,7 +118,7 @@ namespace osu.Game.Screens.SelectV2
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)
{