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)