mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 23:24:04 +09:00
Replace BeatmapCollection
with RealmBeatmapCollection
This commit is contained in:
@ -1,32 +1,50 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using osu.Framework.Bindables;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using Realms;
|
||||
|
||||
namespace osu.Game.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of beatmaps grouped by a name.
|
||||
/// </summary>
|
||||
public class BeatmapCollection
|
||||
public class BeatmapCollection : RealmObject, IHasGuidPrimaryKey
|
||||
{
|
||||
[PrimaryKey]
|
||||
public Guid ID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The collection's name.
|
||||
/// </summary>
|
||||
public readonly Bindable<string> Name = new Bindable<string>();
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="BeatmapInfo.MD5Hash"/>es of beatmaps contained by the collection.
|
||||
/// </summary>
|
||||
public readonly BindableList<string> BeatmapHashes = new BindableList<string>();
|
||||
public IList<string> BeatmapMD5Hashes { get; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The date when this collection was last modified.
|
||||
/// </summary>
|
||||
public DateTimeOffset LastModifyDate { get; private set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset LastModified { get; set; }
|
||||
|
||||
public BeatmapCollection(string? name = null, IList<string>? beatmapMD5Hashes = null)
|
||||
{
|
||||
ID = Guid.NewGuid();
|
||||
Name = name ?? string.Empty;
|
||||
BeatmapMD5Hashes = beatmapMD5Hashes ?? new List<string>();
|
||||
|
||||
LastModified = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
private BeatmapCollection()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -15,6 +13,7 @@ using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
@ -43,8 +42,8 @@ namespace osu.Game.Collections
|
||||
private readonly IBindableList<string> beatmaps = new BindableList<string>();
|
||||
private readonly BindableList<CollectionFilterMenuItem> filters = new BindableList<CollectionFilterMenuItem>();
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private ManageCollectionsDialog manageCollectionsDialog { get; set; }
|
||||
[Resolved]
|
||||
private ManageCollectionsDialog? manageCollectionsDialog { get; set; }
|
||||
|
||||
public CollectionFilterDropdown()
|
||||
{
|
||||
@ -81,7 +80,7 @@ namespace osu.Game.Collections
|
||||
if (ShowManageCollectionsItem)
|
||||
filters.Add(new ManageCollectionsFilterMenuItem());
|
||||
|
||||
Current.Value = filters.SingleOrDefault(f => f.Collection != null && f.Collection == selectedItem) ?? filters[0];
|
||||
Current.Value = filters.SingleOrDefault(f => f.Collection != null && f.Collection.ID == selectedItem?.ID) ?? filters[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -92,11 +91,12 @@ namespace osu.Game.Collections
|
||||
// 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;
|
||||
|
||||
if (filter.OldValue?.Collection != null)
|
||||
beatmaps.UnbindFrom(filter.OldValue.Collection.BeatmapHashes);
|
||||
|
||||
if (filter.NewValue?.Collection != null)
|
||||
beatmaps.BindTo(filter.NewValue.Collection.BeatmapHashes);
|
||||
// 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;
|
||||
|
||||
@ -187,26 +187,24 @@ namespace osu.Game.Collections
|
||||
|
||||
protected class CollectionDropdownMenuItem : OsuDropdownMenu.DrawableOsuDropdownMenuItem
|
||||
{
|
||||
[NotNull]
|
||||
protected new CollectionFilterMenuItem Item => ((DropdownMenuItem<CollectionFilterMenuItem>)base.Item).Value;
|
||||
|
||||
[Resolved]
|
||||
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
||||
private IBindable<WorkingBeatmap> beatmap { get; set; } = null!;
|
||||
|
||||
[CanBeNull]
|
||||
private readonly BindableList<string> collectionBeatmaps;
|
||||
|
||||
[NotNull]
|
||||
private readonly Bindable<string> collectionName;
|
||||
|
||||
private IconButton addOrRemoveButton;
|
||||
private Content content;
|
||||
private IconButton addOrRemoveButton = null!;
|
||||
private Content content = null!;
|
||||
private bool beatmapInCollection;
|
||||
|
||||
private IDisposable? realmSubscription;
|
||||
|
||||
private BeatmapCollection? collection => Item.Collection;
|
||||
|
||||
public CollectionDropdownMenuItem(MenuItem item)
|
||||
: base(item)
|
||||
{
|
||||
collectionBeatmaps = Item.Collection?.BeatmapHashes.GetBoundCopy();
|
||||
collectionName = Item.CollectionName.GetBoundCopy();
|
||||
}
|
||||
|
||||
@ -223,14 +221,17 @@ namespace osu.Game.Collections
|
||||
});
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private RealmAccess realm { get; set; } = null!;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (collectionBeatmaps != null)
|
||||
if (Item.Collection != null)
|
||||
{
|
||||
collectionBeatmaps.CollectionChanged += (_, _) => collectionChanged();
|
||||
beatmap.BindValueChanged(_ => collectionChanged(), true);
|
||||
realmSubscription = realm.SubscribeToPropertyChanged(r => r.Find<BeatmapCollection>(Item.Collection.ID), c => c.BeatmapMD5Hashes, _ => hashesChanged());
|
||||
beatmap.BindValueChanged(_ => hashesChanged(), true);
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -252,11 +253,11 @@ namespace osu.Game.Collections
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
private void collectionChanged()
|
||||
private void hashesChanged()
|
||||
{
|
||||
Debug.Assert(collectionBeatmaps != null);
|
||||
Debug.Assert(collection != null);
|
||||
|
||||
beatmapInCollection = collectionBeatmaps.Contains(beatmap.Value.BeatmapInfo.MD5Hash);
|
||||
beatmapInCollection = collection.BeatmapMD5Hashes.Contains(beatmap.Value.BeatmapInfo.MD5Hash);
|
||||
|
||||
addOrRemoveButton.Enabled.Value = !beatmap.IsDefault;
|
||||
addOrRemoveButton.Icon = beatmapInCollection ? FontAwesome.Solid.MinusSquare : FontAwesome.Solid.PlusSquare;
|
||||
@ -273,7 +274,7 @@ namespace osu.Game.Collections
|
||||
|
||||
private void updateButtonVisibility()
|
||||
{
|
||||
if (collectionBeatmaps == null)
|
||||
if (collection == null)
|
||||
addOrRemoveButton.Alpha = 0;
|
||||
else
|
||||
addOrRemoveButton.Alpha = IsHovered || IsPreSelected || beatmapInCollection ? 1 : 0;
|
||||
@ -281,13 +282,22 @@ namespace osu.Game.Collections
|
||||
|
||||
private void addOrRemove()
|
||||
{
|
||||
Debug.Assert(collectionBeatmaps != null);
|
||||
Debug.Assert(collection != null);
|
||||
|
||||
if (!collectionBeatmaps.Remove(beatmap.Value.BeatmapInfo.MD5Hash))
|
||||
collectionBeatmaps.Add(beatmap.Value.BeatmapInfo.MD5Hash);
|
||||
realm.Write(r =>
|
||||
{
|
||||
if (!collection.BeatmapMD5Hashes.Remove(beatmap.Value.BeatmapInfo.MD5Hash))
|
||||
collection.BeatmapMD5Hashes.Add(beatmap.Value.BeatmapInfo.MD5Hash);
|
||||
});
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => content = (Content)base.CreateContent();
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
realmSubscription?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Bindables;
|
||||
|
||||
namespace osu.Game.Collections
|
||||
@ -18,26 +15,26 @@ namespace osu.Game.Collections
|
||||
/// The collection to filter beatmaps from.
|
||||
/// May be null to not filter by collection (include all beatmaps).
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public readonly BeatmapCollection Collection;
|
||||
public readonly BeatmapCollection? Collection;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the collection.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
public readonly Bindable<string> CollectionName;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="CollectionFilterMenuItem"/>.
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection to filter beatmaps from.</param>
|
||||
public CollectionFilterMenuItem([CanBeNull] BeatmapCollection collection)
|
||||
public CollectionFilterMenuItem(BeatmapCollection? collection)
|
||||
{
|
||||
Collection = collection;
|
||||
CollectionName = Collection?.Name.GetBoundCopy() ?? new Bindable<string>("All beatmaps");
|
||||
CollectionName = new Bindable<string>(collection?.Name ?? "All beatmaps");
|
||||
}
|
||||
|
||||
public bool Equals(CollectionFilterMenuItem other)
|
||||
// TODO: track name changes i guess?
|
||||
|
||||
public bool Equals(CollectionFilterMenuItem? other)
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
@ -45,7 +42,7 @@ namespace osu.Game.Collections
|
||||
// collections may have the same name, so compare first on reference equality.
|
||||
// this relies on the assumption that only one instance of the BeatmapCollection exists game-wide, managed by CollectionManager.
|
||||
if (Collection != null)
|
||||
return Collection == other.Collection;
|
||||
return Collection.ID == other.Collection?.ID;
|
||||
|
||||
// fallback to name-based comparison.
|
||||
// this is required for special dropdown items which don't have a collection (all beatmaps / manage collections items below).
|
||||
|
@ -8,7 +8,7 @@ namespace osu.Game.Collections
|
||||
{
|
||||
public class CollectionToggleMenuItem : ToggleMenuItem
|
||||
{
|
||||
public CollectionToggleMenuItem(RealmBeatmapCollection collection, IBeatmapInfo beatmap)
|
||||
public CollectionToggleMenuItem(BeatmapCollection collection, IBeatmapInfo beatmap)
|
||||
: base(collection.Name, MenuItemType.Standard, state =>
|
||||
{
|
||||
if (state)
|
||||
|
@ -1,19 +1,16 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using Humanizer;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.Dialog;
|
||||
|
||||
namespace osu.Game.Collections
|
||||
{
|
||||
public class DeleteCollectionDialog : PopupDialog
|
||||
{
|
||||
public DeleteCollectionDialog(RealmBeatmapCollection collection, Action deleteAction)
|
||||
public DeleteCollectionDialog(BeatmapCollection collection, Action deleteAction)
|
||||
{
|
||||
HeaderText = "Confirm deletion of";
|
||||
BodyText = $"{collection.Name} ({"beatmap".ToQuantity(collection.BeatmapMD5Hashes.Count)})";
|
||||
|
@ -1,35 +1,33 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Visualises a list of <see cref="RealmBeatmapCollection"/>s.
|
||||
/// Visualises a list of <see cref="BeatmapCollection"/>s.
|
||||
/// </summary>
|
||||
public class DrawableCollectionList : OsuRearrangeableListContainer<RealmBeatmapCollection>
|
||||
public class DrawableCollectionList : OsuRearrangeableListContainer<BeatmapCollection>
|
||||
{
|
||||
private Scroll scroll;
|
||||
private Scroll scroll = null!;
|
||||
|
||||
protected override ScrollContainer<Drawable> CreateScrollContainer() => scroll = new Scroll();
|
||||
|
||||
protected override FillFlowContainer<RearrangeableListItem<RealmBeatmapCollection>> CreateListFillFlowContainer() => new Flow
|
||||
protected override FillFlowContainer<RearrangeableListItem<BeatmapCollection>> CreateListFillFlowContainer() => new Flow
|
||||
{
|
||||
DragActive = { BindTarget = DragActive }
|
||||
};
|
||||
|
||||
// TODO: source from realm
|
||||
|
||||
protected override OsuRearrangeableListItem<RealmBeatmapCollection> CreateOsuDrawable(RealmBeatmapCollection item)
|
||||
protected override OsuRearrangeableListItem<BeatmapCollection> CreateOsuDrawable(BeatmapCollection item)
|
||||
{
|
||||
if (item.ID == scroll.PlaceholderItem.Model.ID)
|
||||
return scroll.ReplacePlaceholder();
|
||||
@ -49,7 +47,7 @@ namespace osu.Game.Collections
|
||||
/// <summary>
|
||||
/// The currently-displayed placeholder item.
|
||||
/// </summary>
|
||||
public DrawableCollectionListItem PlaceholderItem { get; private set; }
|
||||
public DrawableCollectionListItem PlaceholderItem { get; private set; } = null!;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
private readonly Container content;
|
||||
@ -79,6 +77,7 @@ namespace osu.Game.Collections
|
||||
});
|
||||
|
||||
ReplacePlaceholder();
|
||||
Debug.Assert(PlaceholderItem != null);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -98,7 +97,7 @@ namespace osu.Game.Collections
|
||||
var previous = PlaceholderItem;
|
||||
|
||||
placeholderContainer.Clear(false);
|
||||
placeholderContainer.Add(PlaceholderItem = new DrawableCollectionListItem(new RealmBeatmapCollection(), false));
|
||||
placeholderContainer.Add(PlaceholderItem = new DrawableCollectionListItem(new BeatmapCollection(), false));
|
||||
|
||||
return previous;
|
||||
}
|
||||
@ -107,7 +106,7 @@ namespace osu.Game.Collections
|
||||
/// <summary>
|
||||
/// The flow of <see cref="DrawableCollectionListItem"/>. Disables layout easing unless a drag is in progress.
|
||||
/// </summary>
|
||||
private class Flow : FillFlowContainer<RearrangeableListItem<RealmBeatmapCollection>>
|
||||
private class Flow : FillFlowContainer<RearrangeableListItem<BeatmapCollection>>
|
||||
{
|
||||
public readonly IBindable<bool> DragActive = new Bindable<bool>();
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -12,7 +10,6 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
@ -24,15 +21,15 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Visualises a <see cref="RealmBeatmapCollection"/> inside a <see cref="DrawableCollectionList"/>.
|
||||
/// Visualises a <see cref="BeatmapCollection"/> inside a <see cref="DrawableCollectionList"/>.
|
||||
/// </summary>
|
||||
public class DrawableCollectionListItem : OsuRearrangeableListItem<RealmBeatmapCollection>
|
||||
public class DrawableCollectionListItem : OsuRearrangeableListItem<BeatmapCollection>
|
||||
{
|
||||
private const float item_height = 35;
|
||||
private const float button_width = item_height * 0.75f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the <see cref="RealmBeatmapCollection"/> currently exists inside realm.
|
||||
/// Whether the <see cref="BeatmapCollection"/> currently exists inside realm.
|
||||
/// </summary>
|
||||
public IBindable<bool> IsCreated => isCreated;
|
||||
|
||||
@ -41,9 +38,9 @@ namespace osu.Game.Collections
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="DrawableCollectionListItem"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The <see cref="RealmBeatmapCollection"/>.</param>
|
||||
/// <param name="item">The <see cref="BeatmapCollection"/>.</param>
|
||||
/// <param name="isCreated">Whether <paramref name="item"/> currently exists inside realm.</param>
|
||||
public DrawableCollectionListItem(RealmBeatmapCollection item, bool isCreated)
|
||||
public DrawableCollectionListItem(BeatmapCollection item, bool isCreated)
|
||||
: base(item)
|
||||
{
|
||||
this.isCreated.Value = isCreated;
|
||||
@ -63,12 +60,15 @@ namespace osu.Game.Collections
|
||||
{
|
||||
public readonly Bindable<bool> IsCreated = new Bindable<bool>();
|
||||
|
||||
private readonly RealmBeatmapCollection collection;
|
||||
private readonly BeatmapCollection collection;
|
||||
|
||||
private Container textBoxPaddingContainer;
|
||||
private ItemTextBox textBox;
|
||||
private Container textBoxPaddingContainer = null!;
|
||||
private ItemTextBox textBox = null!;
|
||||
|
||||
public ItemContent(RealmBeatmapCollection collection)
|
||||
[Resolved]
|
||||
private RealmAccess realm { get; set; } = null!;
|
||||
|
||||
public ItemContent(BeatmapCollection collection)
|
||||
{
|
||||
this.collection = collection;
|
||||
|
||||
@ -107,9 +107,6 @@ namespace osu.Game.Collections
|
||||
};
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private RealmAccess realm { get; set; }
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
@ -156,20 +153,20 @@ namespace osu.Game.Collections
|
||||
{
|
||||
public readonly IBindable<bool> IsCreated = new Bindable<bool>();
|
||||
|
||||
public Func<Vector2, bool> IsTextBoxHovered;
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IDialogOverlay dialogOverlay { get; set; }
|
||||
public Func<Vector2, bool> IsTextBoxHovered = null!;
|
||||
|
||||
[Resolved]
|
||||
private RealmAccess realmAccess { get; set; }
|
||||
private IDialogOverlay? dialogOverlay { get; set; }
|
||||
|
||||
private readonly RealmBeatmapCollection collection;
|
||||
[Resolved]
|
||||
private RealmAccess realmAccess { get; set; } = null!;
|
||||
|
||||
private Drawable fadeContainer;
|
||||
private Drawable background;
|
||||
private readonly BeatmapCollection collection;
|
||||
|
||||
public DeleteButton(RealmBeatmapCollection collection)
|
||||
private Drawable fadeContainer = null!;
|
||||
private Drawable background = null!;
|
||||
|
||||
public DeleteButton(BeatmapCollection collection)
|
||||
{
|
||||
this.collection = collection;
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
|
Reference in New Issue
Block a user