mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 19:42:55 +08:00
Hook up remaining data flows
This commit is contained in:
parent
438067a18b
commit
804bb33aed
@ -2,7 +2,6 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -17,6 +16,7 @@ using osu.Game.Database;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using Realms;
|
||||||
|
|
||||||
namespace osu.Game.Collections
|
namespace osu.Game.Collections
|
||||||
{
|
{
|
||||||
@ -38,13 +38,15 @@ namespace osu.Game.Collections
|
|||||||
set => current.Current = value;
|
set => current.Current = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IBindableList<Live<BeatmapCollection>> collections = new BindableList<Live<BeatmapCollection>>();
|
|
||||||
private readonly IBindableList<string> beatmaps = new BindableList<string>();
|
private readonly IBindableList<string> beatmaps = new BindableList<string>();
|
||||||
private readonly BindableList<CollectionFilterMenuItem> filters = new BindableList<CollectionFilterMenuItem>();
|
private readonly BindableList<CollectionFilterMenuItem> filters = new BindableList<CollectionFilterMenuItem>();
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private ManageCollectionsDialog? manageCollectionsDialog { get; set; }
|
private ManageCollectionsDialog? manageCollectionsDialog { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private RealmAccess realm { get; set; } = null!;
|
||||||
|
|
||||||
public CollectionFilterDropdown()
|
public CollectionFilterDropdown()
|
||||||
{
|
{
|
||||||
ItemSource = filters;
|
ItemSource = filters;
|
||||||
@ -55,51 +57,49 @@ namespace osu.Game.Collections
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
// TODO: bind to realm data
|
realm.RegisterForNotifications(r => r.All<BeatmapCollection>(), collectionsChanged);
|
||||||
|
|
||||||
// Dropdown has logic which triggers a change on the bindable with every change to the contained items.
|
// 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.
|
// 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.
|
// An extra bindable is enough to subvert this behaviour.
|
||||||
base.Current = Current;
|
base.Current = Current;
|
||||||
|
|
||||||
collections.BindCollectionChanged((_, _) => collectionsChanged(), true);
|
Current.BindValueChanged(currentChanged, true);
|
||||||
Current.BindValueChanged(filterChanged, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when a collection has been added or removed.
|
/// Occurs when a collection has been added or removed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void collectionsChanged()
|
private void collectionsChanged(IRealmCollection<BeatmapCollection> collections, ChangeSet? changes, Exception error)
|
||||||
{
|
{
|
||||||
var selectedItem = SelectedItem?.Value?.Collection;
|
var selectedItem = SelectedItem?.Value?.Collection;
|
||||||
|
|
||||||
filters.Clear();
|
filters.Clear();
|
||||||
filters.Add(new AllBeatmapsCollectionFilterMenuItem());
|
filters.Add(new AllBeatmapsCollectionFilterMenuItem());
|
||||||
filters.AddRange(collections.Select(c => new CollectionFilterMenuItem(c)));
|
filters.AddRange(collections.Select(c => new CollectionFilterMenuItem(c.ToLive(realm))));
|
||||||
|
|
||||||
if (ShowManageCollectionsItem)
|
if (ShowManageCollectionsItem)
|
||||||
filters.Add(new ManageCollectionsFilterMenuItem());
|
filters.Add(new ManageCollectionsFilterMenuItem());
|
||||||
|
|
||||||
Current.Value = filters.SingleOrDefault(f => f.Collection != null && f.Collection.ID == selectedItem?.ID) ?? filters[0];
|
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.
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void currentChanged(ValueChangedEvent<CollectionFilterMenuItem> filter)
|
||||||
/// Occurs when the <see cref="CollectionFilterMenuItem"/> selection has changed.
|
|
||||||
/// </summary>
|
|
||||||
private void filterChanged(ValueChangedEvent<CollectionFilterMenuItem> filter)
|
|
||||||
{
|
{
|
||||||
// Binding the beatmaps will trigger a collection change event, which results in an infinite-loop. This is rebound later, when it's safe to do so.
|
|
||||||
beatmaps.CollectionChanged -= filterBeatmapsChanged;
|
|
||||||
|
|
||||||
// TODO: binding with realm
|
|
||||||
// if (filter.OldValue?.Collection != null)
|
|
||||||
// beatmaps.UnbindFrom(filter.OldValue.Collection.BeatmapMD5Hashes);
|
|
||||||
//
|
|
||||||
// if (filter.NewValue?.Collection != null)
|
|
||||||
// beatmaps.BindTo(filter.NewValue.Collection.BeatmapMD5Hashes);
|
|
||||||
|
|
||||||
beatmaps.CollectionChanged += filterBeatmapsChanged;
|
|
||||||
|
|
||||||
// Never select the manage collection filter - rollback to the previous filter.
|
// 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.
|
// 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)
|
if (filter.NewValue is ManageCollectionsFilterMenuItem)
|
||||||
@ -109,18 +109,7 @@ namespace osu.Game.Collections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected override LocalisableString GenerateItemText(CollectionFilterMenuItem item) => item.CollectionName;
|
||||||
/// Occurs when the beatmaps contained by a <see cref="BeatmapCollection"/> have changed.
|
|
||||||
/// </summary>
|
|
||||||
private void filterBeatmapsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
// TODO: fuck this shit right off
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override LocalisableString GenerateItemText(CollectionFilterMenuItem item) => item.CollectionName.Value;
|
|
||||||
|
|
||||||
protected sealed override DropdownHeader CreateHeader() => CreateCollectionHeader().With(d =>
|
protected sealed override DropdownHeader CreateHeader() => CreateCollectionHeader().With(d =>
|
||||||
{
|
{
|
||||||
@ -136,13 +125,6 @@ namespace osu.Game.Collections
|
|||||||
public class CollectionDropdownHeader : OsuDropdownHeader
|
public class CollectionDropdownHeader : OsuDropdownHeader
|
||||||
{
|
{
|
||||||
public readonly Bindable<CollectionFilterMenuItem> SelectedItem = new Bindable<CollectionFilterMenuItem>();
|
public readonly Bindable<CollectionFilterMenuItem> SelectedItem = new Bindable<CollectionFilterMenuItem>();
|
||||||
private readonly Bindable<string> collectionName = new Bindable<string>();
|
|
||||||
|
|
||||||
protected override LocalisableString Label
|
|
||||||
{
|
|
||||||
get => base.Label;
|
|
||||||
set { } // See updateText().
|
|
||||||
}
|
|
||||||
|
|
||||||
public CollectionDropdownHeader()
|
public CollectionDropdownHeader()
|
||||||
{
|
{
|
||||||
@ -150,26 +132,6 @@ namespace osu.Game.Collections
|
|||||||
Icon.Size = new Vector2(16);
|
Icon.Size = new Vector2(16);
|
||||||
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 8, Right = 4 };
|
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 8, Right = 4 };
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
SelectedItem.BindValueChanged(_ => updateBindable(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBindable()
|
|
||||||
{
|
|
||||||
collectionName.UnbindAll();
|
|
||||||
|
|
||||||
if (SelectedItem.Value != null)
|
|
||||||
collectionName.BindTo(SelectedItem.Value.CollectionName);
|
|
||||||
|
|
||||||
collectionName.BindValueChanged(_ => updateText(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dropdowns don't bind to value changes, so the real name is copied directly from the selected item here.
|
|
||||||
private void updateText() => base.Label = collectionName.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class CollectionDropdownMenu : OsuDropdownMenu
|
protected class CollectionDropdownMenu : OsuDropdownMenu
|
||||||
@ -190,23 +152,16 @@ namespace osu.Game.Collections
|
|||||||
{
|
{
|
||||||
protected new CollectionFilterMenuItem Item => ((DropdownMenuItem<CollectionFilterMenuItem>)base.Item).Value;
|
protected new CollectionFilterMenuItem Item => ((DropdownMenuItem<CollectionFilterMenuItem>)base.Item).Value;
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private IBindable<WorkingBeatmap> beatmap { get; set; } = null!;
|
|
||||||
|
|
||||||
private readonly Bindable<string> collectionName;
|
|
||||||
|
|
||||||
private IconButton addOrRemoveButton = null!;
|
private IconButton addOrRemoveButton = null!;
|
||||||
private Content content = null!;
|
|
||||||
private bool beatmapInCollection;
|
private bool beatmapInCollection;
|
||||||
|
|
||||||
private IDisposable? realmSubscription;
|
[Resolved]
|
||||||
|
private IBindable<WorkingBeatmap> beatmap { get; set; } = null!;
|
||||||
private Live<BeatmapCollection>? collection => Item.Collection;
|
|
||||||
|
|
||||||
public CollectionDropdownMenuItem(MenuItem item)
|
public CollectionDropdownMenuItem(MenuItem item)
|
||||||
: base(item)
|
: base(item)
|
||||||
{
|
{
|
||||||
collectionName = Item.CollectionName.GetBoundCopy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -222,22 +177,25 @@ namespace osu.Game.Collections
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private RealmAccess realm { get; set; } = null!;
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
if (Item.Collection != null)
|
if (Item.Collection != null)
|
||||||
{
|
{
|
||||||
realmSubscription = realm.SubscribeToPropertyChanged(r => r.Find<BeatmapCollection>(Item.Collection.ID), c => c.BeatmapMD5Hashes, _ => hashesChanged());
|
beatmap.BindValueChanged(_ =>
|
||||||
beatmap.BindValueChanged(_ => hashesChanged(), true);
|
{
|
||||||
}
|
Debug.Assert(Item.Collection != null);
|
||||||
|
|
||||||
// Although the DrawableMenuItem binds to value changes of the item's text, the item is an internal implementation detail of Dropdown that has no knowledge
|
beatmapInCollection = Item.Collection.PerformRead(c => c.BeatmapMD5Hashes.Contains(beatmap.Value.BeatmapInfo.MD5Hash));
|
||||||
// of the underlying CollectionFilter value and its accompanying name, so the real name has to be copied here. Without this, the collection name wouldn't update when changed.
|
|
||||||
collectionName.BindValueChanged(name => content.Text = name.NewValue, true);
|
addOrRemoveButton.Enabled.Value = !beatmap.IsDefault;
|
||||||
|
addOrRemoveButton.Icon = beatmapInCollection ? FontAwesome.Solid.MinusSquare : FontAwesome.Solid.PlusSquare;
|
||||||
|
addOrRemoveButton.TooltipText = beatmapInCollection ? "Remove selected beatmap" : "Add selected beatmap";
|
||||||
|
|
||||||
|
updateButtonVisibility();
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
updateButtonVisibility();
|
updateButtonVisibility();
|
||||||
}
|
}
|
||||||
@ -254,19 +212,6 @@ namespace osu.Game.Collections
|
|||||||
base.OnHoverLost(e);
|
base.OnHoverLost(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hashesChanged()
|
|
||||||
{
|
|
||||||
Debug.Assert(collection != null);
|
|
||||||
|
|
||||||
beatmapInCollection = collection.PerformRead(c => c.BeatmapMD5Hashes.Contains(beatmap.Value.BeatmapInfo.MD5Hash));
|
|
||||||
|
|
||||||
addOrRemoveButton.Enabled.Value = !beatmap.IsDefault;
|
|
||||||
addOrRemoveButton.Icon = beatmapInCollection ? FontAwesome.Solid.MinusSquare : FontAwesome.Solid.PlusSquare;
|
|
||||||
addOrRemoveButton.TooltipText = beatmapInCollection ? "Remove selected beatmap" : "Add selected beatmap";
|
|
||||||
|
|
||||||
updateButtonVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnSelectChange()
|
protected override void OnSelectChange()
|
||||||
{
|
{
|
||||||
base.OnSelectChange();
|
base.OnSelectChange();
|
||||||
@ -275,7 +220,7 @@ namespace osu.Game.Collections
|
|||||||
|
|
||||||
private void updateButtonVisibility()
|
private void updateButtonVisibility()
|
||||||
{
|
{
|
||||||
if (collection == null)
|
if (Item.Collection == null)
|
||||||
addOrRemoveButton.Alpha = 0;
|
addOrRemoveButton.Alpha = 0;
|
||||||
else
|
else
|
||||||
addOrRemoveButton.Alpha = IsHovered || IsPreSelected || beatmapInCollection ? 1 : 0;
|
addOrRemoveButton.Alpha = IsHovered || IsPreSelected || beatmapInCollection ? 1 : 0;
|
||||||
@ -283,22 +228,16 @@ namespace osu.Game.Collections
|
|||||||
|
|
||||||
private void addOrRemove()
|
private void addOrRemove()
|
||||||
{
|
{
|
||||||
Debug.Assert(collection != null);
|
Debug.Assert(Item.Collection != null);
|
||||||
|
|
||||||
collection.PerformWrite(c =>
|
Item.Collection.PerformWrite(c =>
|
||||||
{
|
{
|
||||||
if (!c.BeatmapMD5Hashes.Remove(beatmap.Value.BeatmapInfo.MD5Hash))
|
if (!c.BeatmapMD5Hashes.Remove(beatmap.Value.BeatmapInfo.MD5Hash))
|
||||||
c.BeatmapMD5Hashes.Add(beatmap.Value.BeatmapInfo.MD5Hash);
|
c.BeatmapMD5Hashes.Add(beatmap.Value.BeatmapInfo.MD5Hash);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateContent() => content = (Content)base.CreateContent();
|
protected override Drawable CreateContent() => (Content)base.CreateContent();
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
base.Dispose(isDisposing);
|
|
||||||
realmSubscription?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
|
||||||
namespace osu.Game.Collections
|
namespace osu.Game.Collections
|
||||||
@ -21,19 +20,22 @@ namespace osu.Game.Collections
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the collection.
|
/// The name of the collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Bindable<string> CollectionName;
|
public string CollectionName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="CollectionFilterMenuItem"/>.
|
/// Creates a new <see cref="CollectionFilterMenuItem"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="collection">The collection to filter beatmaps from.</param>
|
/// <param name="collection">The collection to filter beatmaps from.</param>
|
||||||
public CollectionFilterMenuItem(Live<BeatmapCollection>? collection)
|
public CollectionFilterMenuItem(Live<BeatmapCollection> collection)
|
||||||
|
: this(collection.PerformRead(c => c.Name))
|
||||||
{
|
{
|
||||||
Collection = collection;
|
Collection = collection;
|
||||||
CollectionName = new Bindable<string>(collection?.PerformRead(c => c.Name) ?? "All beatmaps");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: track name changes i guess?
|
protected CollectionFilterMenuItem(string name)
|
||||||
|
{
|
||||||
|
CollectionName = name;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Equals(CollectionFilterMenuItem? other)
|
public bool Equals(CollectionFilterMenuItem? other)
|
||||||
{
|
{
|
||||||
@ -47,16 +49,16 @@ namespace osu.Game.Collections
|
|||||||
|
|
||||||
// fallback to name-based comparison.
|
// fallback to name-based comparison.
|
||||||
// this is required for special dropdown items which don't have a collection (all beatmaps / manage collections items below).
|
// this is required for special dropdown items which don't have a collection (all beatmaps / manage collections items below).
|
||||||
return CollectionName.Value == other.CollectionName.Value;
|
return CollectionName == other.CollectionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode() => CollectionName.Value.GetHashCode();
|
public override int GetHashCode() => CollectionName.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AllBeatmapsCollectionFilterMenuItem : CollectionFilterMenuItem
|
public class AllBeatmapsCollectionFilterMenuItem : CollectionFilterMenuItem
|
||||||
{
|
{
|
||||||
public AllBeatmapsCollectionFilterMenuItem()
|
public AllBeatmapsCollectionFilterMenuItem()
|
||||||
: base(null)
|
: base("All beatmaps")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,9 +66,8 @@ namespace osu.Game.Collections
|
|||||||
public class ManageCollectionsFilterMenuItem : CollectionFilterMenuItem
|
public class ManageCollectionsFilterMenuItem : CollectionFilterMenuItem
|
||||||
{
|
{
|
||||||
public ManageCollectionsFilterMenuItem()
|
public ManageCollectionsFilterMenuItem()
|
||||||
: base(null)
|
: base("Manage collections...")
|
||||||
{
|
{
|
||||||
CollectionName.Value = "Manage collections...";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user