diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs
index db66c01814..df42ba9d16 100644
--- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs
@@ -77,6 +77,7 @@ namespace osu.Game.Tests.Visual
testEmptyTraversal();
testHiding();
testSelectingFilteredRuleset();
+ testFilterByStarRange();
testCarouselRootIsRandom();
}
@@ -245,6 +246,54 @@ namespace osu.Game.Tests.Visual
AddAssert("Selection is non-null", () => currentSelection != null);
}
+ ///
+ /// Test filtering by restricting the desired star range
+ ///
+ private void testFilterByStarRange()
+ {
+ var manyStarDiffs = createTestBeatmapSet(set_count + 1);
+ manyStarDiffs.Beatmaps.Clear();
+
+ for (int i = 0; i < 12; i++)
+ {
+ manyStarDiffs.Beatmaps.Add(new BeatmapInfo
+ {
+ OnlineBeatmapID = manyStarDiffs.ID * 10 + i,
+ Path = $"randomDiff{i}.osu",
+ Version = $"Totally Normal {i}",
+ StarDifficulty = i,
+ BaseDifficulty = new BeatmapDifficulty
+ {
+ OverallDifficulty = 5,
+ }
+ });
+ }
+
+ AddStep("add set with many stars", () => carousel.UpdateBeatmapSet(manyStarDiffs));
+
+ AddStep("select added set", () => carousel.SelectBeatmap(manyStarDiffs.Beatmaps[0], false));
+
+ AddStep("Filter to 1-3 stars", () => carousel.Filter(new FilterCriteria { DisplayStarsMinimum = 1, DisplayStarsMaximum = 3 }, false));
+ checkVisibleItemCount(diff: false, count: 1);
+ checkVisibleItemCount(diff: true, count: 3);
+
+ AddStep("Filter to 3-3 stars", () => carousel.Filter(new FilterCriteria { DisplayStarsMinimum = 3, DisplayStarsMaximum = 3 }, false));
+ checkVisibleItemCount(diff: false, count: 1);
+ checkVisibleItemCount(diff: true, count: 1);
+
+ AddStep("Filter to 4-2 stars", () => carousel.Filter(new FilterCriteria { DisplayStarsMinimum = 4, DisplayStarsMaximum = 2 }, false));
+ checkVisibleItemCount(diff: false, count: 0);
+ checkVisibleItemCount(diff: true, count: 0);
+
+ AddStep("remove added set", () =>
+ {
+ carousel.RemoveBeatmapSet(manyStarDiffs);
+ manyStarDiffs = null;
+ });
+
+ AddStep("Un-filter", () => carousel.Filter(new FilterCriteria(), false));
+ }
+
///
/// Test random non-repeating algorithm
///
diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs
index 272332f1ce..c9ed2f3573 100644
--- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs
+++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs
@@ -26,6 +26,12 @@ namespace osu.Game.Screens.Select.Carousel
bool match = criteria.Ruleset == null || Beatmap.RulesetID == criteria.Ruleset.ID || Beatmap.RulesetID == 0 && criteria.Ruleset.ID > 0 && criteria.AllowConvertedBeatmaps;
+ if(criteria.DisplayStarsMinimum.HasValue)
+ match &= Beatmap.StarDifficulty >= criteria.DisplayStarsMinimum;
+
+ if (criteria.DisplayStarsMaximum.HasValue)
+ match &= Beatmap.StarDifficulty <= criteria.DisplayStarsMaximum;
+
if (!string.IsNullOrEmpty(criteria.SearchText))
match &=
Beatmap.Metadata.SearchableTerms.Any(term => term.IndexOf(criteria.SearchText, StringComparison.InvariantCultureIgnoreCase) >= 0) ||
diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs
index fce7af1400..78b452b6f5 100644
--- a/osu.Game/Screens/Select/FilterControl.cs
+++ b/osu.Game/Screens/Select/FilterControl.cs
@@ -32,14 +32,13 @@ namespace osu.Game.Screens.Select
public SortMode Sort
{
- get { return sort; }
+ get => sort;
set
{
- if (sort != value)
- {
- sort = value;
- FilterChanged?.Invoke(CreateCriteria());
- }
+ if (sort == value) return;
+
+ sort = value;
+ FilterChanged?.Invoke(CreateCriteria());
}
}
@@ -47,14 +46,13 @@ namespace osu.Game.Screens.Select
public GroupMode Group
{
- get { return group; }
+ get => group;
set
{
- if (group != value)
- {
- group = value;
- FilterChanged?.Invoke(CreateCriteria());
- }
+ if (group == value) return;
+
+ group = value;
+ FilterChanged?.Invoke(CreateCriteria());
}
}
@@ -64,7 +62,9 @@ namespace osu.Game.Screens.Select
Sort = sort,
SearchText = searchTextBox.Text,
AllowConvertedBeatmaps = showConverted,
- Ruleset = ruleset.Value
+ Ruleset = ruleset.Value,
+ DisplayStarsMinimum = minimumStars,
+ DisplayStarsMaximum = maximumStars,
};
public Action Exit;
@@ -168,7 +168,9 @@ namespace osu.Game.Screens.Select
private readonly IBindable ruleset = new Bindable();
- private Bindable showConverted;
+ private readonly Bindable showConverted = new Bindable();
+ private readonly Bindable minimumStars = new Bindable();
+ private readonly Bindable maximumStars = new Bindable();
public readonly Box Background;
@@ -177,8 +179,14 @@ namespace osu.Game.Screens.Select
{
sortTabs.AccentColour = colours.GreenLight;
- showConverted = config.GetBindable(OsuSetting.ShowConvertedBeatmaps);
- showConverted.ValueChanged += val => updateCriteria();
+ config.BindWith(OsuSetting.ShowConvertedBeatmaps, showConverted);
+ showConverted.ValueChanged += _ => updateCriteria();
+
+ config.BindWith(OsuSetting.DisplayStarsMinimum, minimumStars);
+ minimumStars.ValueChanged += _ => updateCriteria();
+
+ config.BindWith(OsuSetting.DisplayStarsMaximum, maximumStars);
+ maximumStars.ValueChanged += _ => updateCriteria();
ruleset.BindTo(parentRuleset);
ruleset.BindValueChanged(_ => updateCriteria(), true);
diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs
index bea806f00f..f97eb1bea1 100644
--- a/osu.Game/Screens/Select/FilterCriteria.cs
+++ b/osu.Game/Screens/Select/FilterCriteria.cs
@@ -13,5 +13,7 @@ namespace osu.Game.Screens.Select
public string SearchText;
public RulesetInfo Ruleset;
public bool AllowConvertedBeatmaps;
+ public double? DisplayStarsMinimum;
+ public double? DisplayStarsMaximum;
}
}