Simplify `CollectionFilterDropdown` filter flow weirdness

This commit is contained in:
Dean Herbert 2022-07-27 19:02:43 +09:00
parent 804bb33aed
commit 67c7f324ee
3 changed files with 32 additions and 41 deletions

View File

@ -176,6 +176,8 @@ public void TestButtonAddsAndRemovesBeatmap()
[Test]
public void TestManageCollectionsFilterIsNotSelected()
{
bool received = false;
addExpandHeaderStep();
AddStep("add collection", () => Realm.Write(r => r.Add(new BeatmapCollection(name: "1", new List<string> { "abc" }))));
@ -187,6 +189,12 @@ public void TestManageCollectionsFilterIsNotSelected()
addExpandHeaderStep();
AddStep("watch for filter requests", () =>
{
received = false;
control.ChildrenOfType<CollectionDropdown>().First().RequestFilter = () => received = true;
});
AddStep("click manage collections filter", () =>
{
InputManager.MoveMouseTo(getCollectionDropdownItems().Last());
@ -194,6 +202,8 @@ public void TestManageCollectionsFilterIsNotSelected()
});
AddAssert("collection filter still selected", () => control.CreateCriteria().CollectionBeatmapMD5Hashes.Any());
AddAssert("filter request not fired", () => !received);
}
private BeatmapCollection getFirstCollection() => Realm.Run(r => r.All<BeatmapCollection>().First());

View File

@ -30,15 +30,8 @@ public class CollectionFilterDropdown : OsuDropdown<CollectionFilterMenuItem>
/// </summary>
protected virtual bool ShowManageCollectionsItem => true;
private readonly BindableWithCurrent<CollectionFilterMenuItem> current = new BindableWithCurrent<CollectionFilterMenuItem>();
public Action? RequestFilter { private get; set; }
public new Bindable<CollectionFilterMenuItem> Current
{
get => current.Current;
set => current.Current = value;
}
private readonly IBindableList<string> beatmaps = new BindableList<string>();
private readonly BindableList<CollectionFilterMenuItem> filters = new BindableList<CollectionFilterMenuItem>();
[Resolved]
@ -50,6 +43,7 @@ public class CollectionFilterDropdown : OsuDropdown<CollectionFilterMenuItem>
public CollectionFilterDropdown()
{
ItemSource = filters;
Current.Value = new AllBeatmapsCollectionFilterMenuItem();
}
@ -59,17 +53,9 @@ protected override void LoadComplete()
realm.RegisterForNotifications(r => r.All<BeatmapCollection>(), collectionsChanged);
// Dropdown has logic which triggers a change on the bindable with every change to the contained items.
// This is not desirable here, as it leads to multiple filter operations running even though nothing has changed.
// An extra bindable is enough to subvert this behaviour.
base.Current = Current;
Current.BindValueChanged(currentChanged, true);
Current.BindValueChanged(currentChanged);
}
/// <summary>
/// Occurs when a collection has been added or removed.
/// </summary>
private void collectionsChanged(IRealmCollection<BeatmapCollection> collections, ChangeSet? changes, Exception error)
{
var selectedItem = SelectedItem?.Value?.Collection;
@ -83,38 +69,41 @@ private void collectionsChanged(IRealmCollection<BeatmapCollection> collections,
Current.Value = filters.SingleOrDefault(f => f.Collection != null && f.Collection.ID == selectedItem?.ID) ?? filters[0];
// Trigger a re-filter if the current item was in the changeset.
// Trigger a re-filter if the current item was in the change set.
if (selectedItem != null && changes != null)
{
foreach (int index in changes.ModifiedIndices)
{
if (collections[index].ID == selectedItem.ID)
{
// The filtered beatmaps have changed, without the filter having changed itself. So a change in filter must be notified.
// Note that this does NOT propagate to bound bindables, so the FilterControl must bind directly to the value change event of this bindable.
Current.TriggerChange();
}
RequestFilter?.Invoke();
}
}
}
private void currentChanged(ValueChangedEvent<CollectionFilterMenuItem> filter)
{
// May be null during .Clear().
if (filter.NewValue == null)
return;
// Never select the manage collection filter - rollback to the previous filter.
// This is done after the above since it is important that bindable is unbound from OldValue, which is lost after forcing it back to the old value.
if (filter.NewValue is ManageCollectionsFilterMenuItem)
{
Current.Value = filter.OldValue;
manageCollectionsDialog?.Show();
return;
}
// This dropdown be weird.
// We only care about filtering if the actual collection has changed.
if (filter.OldValue?.Collection != null || filter.NewValue?.Collection != null)
RequestFilter?.Invoke();
}
protected override LocalisableString GenerateItemText(CollectionFilterMenuItem item) => item.CollectionName;
protected sealed override DropdownHeader CreateHeader() => CreateCollectionHeader().With(d =>
{
d.SelectedItem.BindTarget = Current;
});
protected sealed override DropdownHeader CreateHeader() => CreateCollectionHeader().With(d => d.SelectedItem.BindTarget = Current);
protected sealed override DropdownMenu CreateMenu() => CreateCollectionMenu();

View File

@ -39,6 +39,10 @@ public class FilterControl : Container
private Bindable<GroupMode> groupMode;
private SeekLimitedSearchTextBox searchTextBox;
private CollectionFilterDropdown collectionDropdown;
public FilterCriteria CreateCriteria()
{
string query = searchTextBox.Text;
@ -49,7 +53,7 @@ public FilterCriteria CreateCriteria()
Sort = sortMode.Value,
AllowConvertedBeatmaps = showConverted.Value,
Ruleset = ruleset.Value,
CollectionBeatmapMD5Hashes = collectionDropdown?.Current.Value?.Collection?.PerformRead(c => c.BeatmapMD5Hashes)
CollectionBeatmapMD5Hashes = collectionDropdown.Current.Value?.Collection?.PerformRead(c => c.BeatmapMD5Hashes)
};
if (!minimumStars.IsDefault)
@ -64,10 +68,6 @@ public FilterCriteria CreateCriteria()
return criteria;
}
private SeekLimitedSearchTextBox searchTextBox;
private CollectionFilterDropdown collectionDropdown;
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
base.ReceivePositionalInputAt(screenSpacePos) || sortTabs.ReceivePositionalInputAt(screenSpacePos);
@ -183,6 +183,7 @@ private void load(OsuColour colours, IBindable<RulesetInfo> parentRuleset, OsuCo
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RequestFilter = updateCriteria,
RelativeSizeAxes = Axes.X,
Y = 4,
Width = 0.5f,
@ -209,15 +210,6 @@ private void load(OsuColour colours, IBindable<RulesetInfo> parentRuleset, OsuCo
groupMode.BindValueChanged(_ => updateCriteria());
sortMode.BindValueChanged(_ => updateCriteria());
collectionDropdown.Current.ValueChanged += val =>
{
if (val.NewValue == null)
// may be null briefly while menu is repopulated.
return;
updateCriteria();
};
searchTextBox.Current.ValueChanged += _ => updateCriteria();
updateCriteria();