Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add group support to beatmap carousel v2 #31764

Merged
merged 11 commits into from
Feb 4, 2025
52 changes: 50 additions & 2 deletions osu.Game.Tests/Visual/SongSelect/BeatmapCarouselV2TestScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Resources;
using osuTK.Graphics;
using osuTK.Input;
using BeatmapCarousel = osu.Game.Screens.SelectV2.BeatmapCarousel;

namespace osu.Game.Tests.Visual.SongSelect
Expand Down Expand Up @@ -53,7 +54,7 @@ protected BeatmapCarouselV2TestScene()
}

[SetUpSteps]
public void SetUpSteps()
public virtual void SetUpSteps()
{
RemoveAllBeatmaps();

Expand Down Expand Up @@ -129,12 +130,59 @@ protected void CreateCarousel()
});
}

protected void SortBy(FilterCriteria criteria) => AddStep($"sort by {criteria.Sort}", () => Carousel.Filter(criteria));
protected void SortBy(FilterCriteria criteria) => AddStep($"sort {criteria.Sort} group {criteria.Group}", () => Carousel.Filter(criteria));

protected void WaitForDrawablePanels() => AddUntilStep("drawable panels loaded", () => Carousel.ChildrenOfType<ICarouselPanel>().Count(), () => Is.GreaterThan(0));
protected void WaitForSorting() => AddUntilStep("sorting finished", () => Carousel.IsFiltering, () => Is.False);
protected void WaitForScrolling() => AddUntilStep("scroll finished", () => Scroll.Current, () => Is.EqualTo(Scroll.Target));

protected void SelectNextPanel() => AddStep("select next panel", () => InputManager.Key(Key.Down));
protected void SelectPrevPanel() => AddStep("select prev panel", () => InputManager.Key(Key.Up));
protected void SelectNextGroup() => AddStep("select next group", () => InputManager.Key(Key.Right));
protected void SelectPrevGroup() => AddStep("select prev group", () => InputManager.Key(Key.Left));

protected void Select() => AddStep("select", () => InputManager.Key(Key.Enter));

protected void CheckNoSelection() => AddAssert("has no selection", () => Carousel.CurrentSelection, () => Is.Null);
protected void CheckHasSelection() => AddAssert("has selection", () => Carousel.CurrentSelection, () => Is.Not.Null);

protected void WaitForGroupSelection(int group, int panel)
{
AddUntilStep($"selected is group{group} panel{panel}", () =>
{
var groupingFilter = Carousel.Filters.OfType<BeatmapCarouselFilterGrouping>().Single();

GroupDefinition g = groupingFilter.GroupItems.Keys.ElementAt(group);
CarouselItem item = groupingFilter.GroupItems[g].ElementAt(panel);

return ReferenceEquals(Carousel.CurrentSelection, item.Model);
});
}

protected void WaitForSelection(int set, int? diff = null)
{
AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () =>
{
if (diff != null)
return ReferenceEquals(Carousel.CurrentSelection, BeatmapSets[set].Beatmaps[diff.Value]);

return BeatmapSets[set].Beatmaps.Contains(Carousel.CurrentSelection);
});
}

protected void ClickVisiblePanel<T>(int index)
where T : Drawable
{
AddStep($"click panel at index {index}", () =>
{
Carousel.ChildrenOfType<T>()
.Where(p => ((ICarouselPanel)p).Item?.IsVisible == true)
.Reverse()
.ElementAt(index)
.TriggerClick();
});
}

/// <summary>
/// Add requested beatmap sets count to list.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ public void TestBasics()
RemoveAllBeatmaps();
}

[Test]
public void TestOffScreenLoading()
{
AddStep("disable masking", () => Scroll.Masking = false);
AddStep("enable masking", () => Scroll.Masking = true);
}

[Test]
public void TestAddRemoveOneByOne()
{
Expand All @@ -43,7 +50,7 @@ public void TestAddRemoveOneByOne()
public void TestSorting()
{
AddBeatmaps(10);
SortBy(new FilterCriteria { Sort = SortMode.Difficulty });
SortBy(new FilterCriteria { Group = GroupMode.Difficulty, Sort = SortMode.Difficulty });
SortBy(new FilterCriteria { Sort = SortMode.Artist });
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// 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.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
using osu.Game.Screens.SelectV2;

namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public partial class TestSceneBeatmapCarouselV2GroupSelection : BeatmapCarouselV2TestScene
{
public override void SetUpSteps()
{
RemoveAllBeatmaps();

CreateCarousel();

SortBy(new FilterCriteria { Group = GroupMode.Difficulty, Sort = SortMode.Difficulty });
}

[Test]
public void TestOpenCloseGroupWithNoSelection()
{
AddBeatmaps(10, 5);
WaitForDrawablePanels();

AddAssert("no beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.Zero);
CheckNoSelection();

ClickVisiblePanel<GroupPanel>(0);
AddUntilStep("some beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.GreaterThan(0));
CheckNoSelection();

ClickVisiblePanel<GroupPanel>(0);
AddUntilStep("no beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.Zero);
CheckNoSelection();
}

[Test]
public void TestCarouselRemembersSelection()
{
AddBeatmaps(10);
WaitForDrawablePanels();

SelectNextGroup();

object? selection = null;

AddStep("store drawable selection", () => selection = getSelectedPanel()?.Item?.Model);

CheckHasSelection();
AddAssert("drawable selection non-null", () => selection, () => Is.Not.Null);
AddAssert("drawable selection matches carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection));

RemoveAllBeatmaps();
AddUntilStep("no drawable selection", getSelectedPanel, () => Is.Null);

AddBeatmaps(10);
WaitForDrawablePanels();

CheckHasSelection();
AddAssert("no drawable selection", getSelectedPanel, () => Is.Null);

AddStep("add previous selection", () => BeatmapSets.Add(((BeatmapInfo)selection!).BeatmapSet!));

AddAssert("selection matches original carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection));
AddUntilStep("drawable selection restored", () => getSelectedPanel()?.Item?.Model, () => Is.EqualTo(selection));
AddAssert("carousel item is visible", () => getSelectedPanel()?.Item?.IsVisible, () => Is.True);

ClickVisiblePanel<GroupPanel>(0);
AddUntilStep("carousel item not visible", getSelectedPanel, () => Is.Null);

ClickVisiblePanel<GroupPanel>(0);
AddUntilStep("carousel item is visible", () => getSelectedPanel()?.Item?.IsVisible, () => Is.True);

BeatmapPanel? getSelectedPanel() => Carousel.ChildrenOfType<BeatmapPanel>().SingleOrDefault(p => p.Selected.Value);
}

[Test]
public void TestKeyboardSelection()
{
AddBeatmaps(10, 3);
WaitForDrawablePanels();

SelectNextPanel();
SelectNextPanel();
SelectNextPanel();
SelectNextPanel();
CheckNoSelection();

// open first group
Select();
CheckNoSelection();
AddUntilStep("some beatmaps visible", () => Carousel.ChildrenOfType<BeatmapPanel>().Count(p => p.Alpha > 0), () => Is.GreaterThan(0));

SelectNextPanel();
Select();
WaitForGroupSelection(0, 0);

SelectNextGroup();
WaitForGroupSelection(0, 1);

SelectNextGroup();
WaitForGroupSelection(0, 2);

SelectPrevGroup();
WaitForGroupSelection(0, 1);

SelectPrevGroup();
WaitForGroupSelection(0, 0);

SelectPrevGroup();
WaitForGroupSelection(2, 9);
}
}
}
Loading
Loading