mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 07:22:54 +08:00
Merge pull request #27881 from smoogipoo/fix-mod-refilter
Don't re-filter unless mods may change the filter
This commit is contained in:
commit
d2a67d2d54
@ -1,9 +1,14 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Filter;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring.Legacy;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
@ -30,5 +35,20 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool FilterMayChangeFromMods(ValueChangedEvent<IReadOnlyList<Mod>> mods)
|
||||
{
|
||||
if (keys.HasFilter)
|
||||
{
|
||||
// Interpreting as the Mod type is required for equality comparison.
|
||||
HashSet<Mod> oldSet = mods.OldValue.OfType<ManiaKeyMod>().AsEnumerable<Mod>().ToHashSet();
|
||||
HashSet<Mod> newSet = mods.NewValue.OfType<ManiaKeyMod>().AsEnumerable<Mod>().ToHashSet();
|
||||
|
||||
if (!oldSet.SetEquals(newSet))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
// 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.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Filter;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
@ -311,6 +314,8 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
|
||||
public bool Matches(BeatmapInfo beatmapInfo, FilterCriteria criteria) => match;
|
||||
public bool TryParseCustomKeywordCriteria(string key, Operator op, string value) => false;
|
||||
|
||||
public bool FilterMayChangeFromMods(ValueChangedEvent<IReadOnlyList<Mod>> mods) => false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,13 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Filter;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
@ -514,6 +517,8 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool FilterMayChangeFromMods(ValueChangedEvent<IReadOnlyList<Mod>> mods) => false;
|
||||
}
|
||||
|
||||
private static readonly object[] correct_date_query_examples =
|
||||
|
@ -29,6 +29,7 @@ using osu.Game.Overlays.Dialog;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
@ -1147,6 +1148,62 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddAssert("filter text cleared", () => songSelect!.FilterControl.ChildrenOfType<FilterControl.FilterControlTextBox>().First().Text, () => Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNonFilterableModChange()
|
||||
{
|
||||
addRulesetImportStep(0);
|
||||
|
||||
createSongSelect();
|
||||
|
||||
// Mod that is guaranteed to never re-filter.
|
||||
AddStep("add non-filterable mod", () => SelectedMods.Value = new Mod[] { new OsuModCinema() });
|
||||
AddAssert("filter count is 1", () => songSelect!.FilterCount, () => Is.EqualTo(1));
|
||||
|
||||
// Removing the mod should still not re-filter.
|
||||
AddStep("remove non-filterable mod", () => SelectedMods.Value = Array.Empty<Mod>());
|
||||
AddAssert("filter count is 1", () => songSelect!.FilterCount, () => Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFilterableModChange()
|
||||
{
|
||||
addRulesetImportStep(3);
|
||||
|
||||
createSongSelect();
|
||||
|
||||
// Change to mania ruleset.
|
||||
AddStep("filter to mania ruleset", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.OnlineID == 3));
|
||||
AddAssert("filter count is 2", () => songSelect!.FilterCount, () => Is.EqualTo(2));
|
||||
|
||||
// Apply a mod, but this should NOT re-filter because there's no search text.
|
||||
AddStep("add filterable mod", () => SelectedMods.Value = new Mod[] { new ManiaModKey3() });
|
||||
AddAssert("filter count is 2", () => songSelect!.FilterCount, () => Is.EqualTo(2));
|
||||
|
||||
// Set search text. Should re-filter.
|
||||
AddStep("set search text to match mods", () => songSelect!.FilterControl.CurrentTextSearch.Value = "keys=3");
|
||||
AddAssert("filter count is 3", () => songSelect!.FilterCount, () => Is.EqualTo(3));
|
||||
|
||||
// Change filterable mod. Should re-filter.
|
||||
AddStep("change new filterable mod", () => SelectedMods.Value = new Mod[] { new ManiaModKey5() });
|
||||
AddAssert("filter count is 4", () => songSelect!.FilterCount, () => Is.EqualTo(4));
|
||||
|
||||
// Add non-filterable mod. Should NOT re-filter.
|
||||
AddStep("apply non-filterable mod", () => SelectedMods.Value = new Mod[] { new ManiaModNoFail(), new ManiaModKey5() });
|
||||
AddAssert("filter count is 4", () => songSelect!.FilterCount, () => Is.EqualTo(4));
|
||||
|
||||
// Remove filterable mod. Should re-filter.
|
||||
AddStep("remove filterable mod", () => SelectedMods.Value = new Mod[] { new ManiaModNoFail() });
|
||||
AddAssert("filter count is 5", () => songSelect!.FilterCount, () => Is.EqualTo(5));
|
||||
|
||||
// Remove non-filterable mod. Should NOT re-filter.
|
||||
AddStep("remove filterable mod", () => SelectedMods.Value = Array.Empty<Mod>());
|
||||
AddAssert("filter count is 5", () => songSelect!.FilterCount, () => Is.EqualTo(5));
|
||||
|
||||
// Add filterable mod. Should re-filter.
|
||||
AddStep("add filterable mod", () => SelectedMods.Value = new Mod[] { new ManiaModKey3() });
|
||||
AddAssert("filter count is 6", () => songSelect!.FilterCount, () => Is.EqualTo(6));
|
||||
}
|
||||
|
||||
private void waitForInitialSelection()
|
||||
{
|
||||
AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);
|
||||
|
@ -1,7 +1,10 @@
|
||||
// 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.Collections.Generic;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
|
||||
@ -52,5 +55,12 @@ namespace osu.Game.Rulesets.Filter
|
||||
/// while ignored criteria are included in <see cref="FilterCriteria.SearchText"/>.
|
||||
/// </returns>
|
||||
bool TryParseCustomKeywordCriteria(string key, Operator op, string value);
|
||||
|
||||
/// <summary>
|
||||
/// Whether to reapply the filter as a result of the given change in applied mods.
|
||||
/// </summary>
|
||||
/// <param name="mods">The change in mods.</param>
|
||||
/// <returns>Whether the filter should be re-applied.</returns>
|
||||
bool FilterMayChangeFromMods(ValueChangedEvent<IReadOnlyList<Mod>> mods);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -49,15 +50,14 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
private OsuTabControl<SortMode> sortTabs;
|
||||
|
||||
private Bindable<SortMode> sortMode;
|
||||
|
||||
private Bindable<GroupMode> groupMode;
|
||||
|
||||
private FilterControlTextBox searchTextBox;
|
||||
|
||||
private CollectionDropdown collectionDropdown;
|
||||
|
||||
[CanBeNull]
|
||||
private FilterCriteria currentCriteria;
|
||||
|
||||
public FilterCriteria CreateCriteria()
|
||||
{
|
||||
string query = searchTextBox.Text;
|
||||
@ -228,7 +228,8 @@ namespace osu.Game.Screens.Select
|
||||
if (m.NewValue.SequenceEqual(m.OldValue))
|
||||
return;
|
||||
|
||||
updateCriteria();
|
||||
if (currentCriteria?.RulesetCriteria?.FilterMayChangeFromMods(m) == true)
|
||||
updateCriteria();
|
||||
});
|
||||
|
||||
groupMode.BindValueChanged(_ => updateCriteria());
|
||||
@ -263,7 +264,7 @@ namespace osu.Game.Screens.Select
|
||||
private readonly Bindable<double> minimumStars = new BindableDouble();
|
||||
private readonly Bindable<double> maximumStars = new BindableDouble();
|
||||
|
||||
private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria());
|
||||
private void updateCriteria() => FilterChanged?.Invoke(currentCriteria = CreateCriteria());
|
||||
|
||||
protected override bool OnClick(ClickEvent e) => true;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user