diff --git a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs b/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs
index 9c109bc782..1920647e38 100644
--- a/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs
+++ b/osu.Game.Tests/Visual/SongSelectV2/BeatmapCarouselTestScene.cs
@@ -149,6 +149,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
TextAnchor = Anchor.CentreLeft,
},
};
+
+ Carousel.Filter(new FilterCriteria());
});
// Prefer title sorting so that order of carousel panels match order of BeatmapSets bindable.
@@ -171,7 +173,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
AddStep(description, () =>
{
- var criteria = Carousel.Criteria;
+ var criteria = Carousel.Criteria ?? new FilterCriteria();
apply?.Invoke(criteria);
Carousel.Filter(criteria);
});
@@ -362,7 +364,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
""");
createHeader("carousel");
stats.AddParagraph($"""
- sorting: {Carousel.IsFiltering}
+ filtering: {Carousel.IsFiltering} (total {Carousel.FilterCount} times)
tracked: {Carousel.ItemsTracked}
displayable: {Carousel.DisplayableItems}
displayed: {Carousel.VisibleItems}
diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs
index b81484d3da..dcd745395b 100644
--- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs
@@ -78,6 +78,15 @@ namespace osu.Game.Tests.Visual.SongSelectV2
AddUntilStep("wait for results screen", () => Stack.CurrentScreen is ResultsScreen);
}
+ [Test]
+ public void TestSingleFilterWhenEntering()
+ {
+ ImportBeatmapForRuleset(0);
+ LoadSongSelect();
+
+ AddAssert("single filter", () => Carousel.FilterCount, () => Is.EqualTo(1));
+ }
+
[Test]
public void TestCookieDoesNothingIfNothingSelected()
{
diff --git a/osu.Game/Graphics/Carousel/Carousel.cs b/osu.Game/Graphics/Carousel/Carousel.cs
index 18395dfa12..85419a8009 100644
--- a/osu.Game/Graphics/Carousel/Carousel.cs
+++ b/osu.Game/Graphics/Carousel/Carousel.cs
@@ -71,6 +71,11 @@ namespace osu.Game.Graphics.Carousel
///
public bool IsFiltering => !filterTask.IsCompleted;
+ ///
+ /// The number of times filter operations have been triggered.
+ ///
+ internal int FilterCount { get; private set; }
+
///
/// The number of displayable items currently being tracked (before filtering).
///
@@ -187,6 +192,8 @@ namespace osu.Game.Graphics.Carousel
/// Whether all existing drawable panels should be reset post filter.
protected virtual Task> FilterAsync(bool clearExistingPanels = false)
{
+ FilterCount++;
+
if (clearExistingPanels)
filterReusesPanels.Invalidate();
diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs
index 6ee780b603..e9a8148d5a 100644
--- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs
+++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs
@@ -7,6 +7,7 @@ using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
@@ -90,9 +91,9 @@ namespace osu.Game.Screens.SelectV2
Filters = new ICarouselFilter[]
{
- matching = new BeatmapCarouselFilterMatching(() => Criteria),
- new BeatmapCarouselFilterSorting(() => Criteria),
- grouping = new BeatmapCarouselFilterGrouping(() => Criteria),
+ matching = new BeatmapCarouselFilterMatching(() => Criteria!),
+ new BeatmapCarouselFilterSorting(() => Criteria!),
+ grouping = new BeatmapCarouselFilterGrouping(() => Criteria!),
};
AddInternal(loading = new LoadingLayer());
@@ -483,7 +484,7 @@ namespace osu.Game.Screens.SelectV2
#region Filtering
- public FilterCriteria Criteria { get; private set; } = new FilterCriteria();
+ public FilterCriteria? Criteria { get; private set; }
private ScheduledDelegate? loadingDebounce;
@@ -509,6 +510,14 @@ namespace osu.Game.Screens.SelectV2
}));
}
+ protected override Task> FilterAsync(bool clearExistingPanels = false)
+ {
+ if (Criteria == null)
+ return Task.FromResult(Enumerable.Empty());
+
+ return base.FilterAsync(clearExistingPanels);
+ }
+
#endregion
#region Drawable pooling
diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs
index 44f3984c64..097abc7da8 100644
--- a/osu.Game/Screens/SelectV2/SongSelect.cs
+++ b/osu.Game/Screens/SelectV2/SongSelect.cs
@@ -562,12 +562,18 @@ namespace osu.Game.Screens.SelectV2
private void criteriaChanged(FilterCriteria criteria)
{
+ // The first filter needs to be applied immediately as this triggers the initial carousel load.
+ double filterDelay = filterDebounce == null ? 0 : filter_delay;
+
filterDebounce?.Cancel();
- filterDebounce = Scheduler.AddDelayed(() => { carousel.Filter(criteria); }, filter_delay);
+ filterDebounce = Scheduler.AddDelayed(() => { carousel.Filter(criteria); }, filterDelay);
}
private void newItemsPresented(IEnumerable carouselItems)
{
+ if (carousel.Criteria == null)
+ return;
+
int count = carousel.MatchedBeatmapsCount;
if (count == 0)