From 958cfde60834a0e5a9342c3dfc7f59893e52942d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Jan 2022 23:45:06 +0900 Subject: [PATCH 01/10] Stop detaching and exposing beatmaps from `MusicController` --- osu.Game/Overlays/MusicController.cs | 14 ++++++-------- osu.Game/Overlays/NowPlayingOverlay.cs | 1 - 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 9dc55d24dd..335abb53dc 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -30,8 +30,6 @@ namespace osu.Game.Overlays [Resolved] private BeatmapManager beatmaps { get; set; } - public IBindableList BeatmapSets => beatmapSets; - /// /// Point in time after which the current track will be restarted on triggering a "previous track" action. /// @@ -88,12 +86,12 @@ namespace osu.Game.Overlays { beatmapSets.Clear(); foreach (var s in sender) - beatmapSets.Add(s.Detach()); + beatmapSets.Add(s); return; } foreach (int i in changes.InsertedIndices) - beatmapSets.Insert(i, sender[i].Detach()); + beatmapSets.Insert(i, sender[i]); foreach (int i in changes.DeletedIndices.OrderByDescending(i => i)) beatmapSets.RemoveAt(i); @@ -240,7 +238,7 @@ namespace osu.Game.Overlays queuedDirection = TrackChangeDirection.Prev; - var playable = BeatmapSets.TakeWhile(i => !i.Equals(current.BeatmapSetInfo)).LastOrDefault() ?? BeatmapSets.LastOrDefault(); + var playable = beatmapSets.TakeWhile(i => !i.Equals(current.BeatmapSetInfo)).LastOrDefault() ?? beatmapSets.LastOrDefault(); if (playable != null) { @@ -271,7 +269,7 @@ namespace osu.Game.Overlays queuedDirection = TrackChangeDirection.Next; - var playableSet = BeatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).ElementAtOrDefault(1) ?? BeatmapSets.FirstOrDefault(); + var playableSet = beatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).ElementAtOrDefault(1) ?? beatmapSets.FirstOrDefault(); var playableBeatmap = playableSet?.Beatmaps.FirstOrDefault(); if (playableBeatmap != null) @@ -322,8 +320,8 @@ namespace osu.Game.Overlays else { // figure out the best direction based on order in playlist. - int last = BeatmapSets.TakeWhile(b => !b.Equals(current.BeatmapSetInfo)).Count(); - int next = newWorking == null ? -1 : BeatmapSets.TakeWhile(b => !b.Equals(newWorking.BeatmapSetInfo)).Count(); + int last = beatmapSets.TakeWhile(b => !b.Equals(current.BeatmapSetInfo)).Count(); + int next = newWorking == null ? -1 : beatmapSets.TakeWhile(b => !b.Equals(newWorking.BeatmapSetInfo)).Count(); direction = last > next ? TrackChangeDirection.Prev : TrackChangeDirection.Next; } diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 4dd23c0008..4617a91885 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -197,7 +197,6 @@ namespace osu.Game.Overlays { dragContainer.Add(playlist); - playlist.BeatmapSets.BindTo(musicController.BeatmapSets); playlist.State.BindValueChanged(s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint), true); togglePlaylist(); From 8a4f3a7ce093b02dbbfa655146a30308214330d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Jan 2022 01:18:21 +0900 Subject: [PATCH 02/10] Reimplement subscription logic in `PlaylistOverlay` directly --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 78b2d58dae..245886743a 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -10,9 +11,11 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; +using osu.Game.Database; using osu.Game.Graphics; using osuTK; using osuTK.Graphics; +using Realms; namespace osu.Game.Overlays.Music { @@ -30,6 +33,15 @@ namespace osu.Game.Overlays.Music [Resolved] private BeatmapManager beatmaps { get; set; } + [Resolved] + private RealmContextFactory realmFactory { get; set; } + + private IDisposable beatmapSubscription; + + private IQueryable availableBeatmaps => realmFactory.Context + .All() + .Where(s => !s.DeletePending); + private FilterControl filter; private Playlist list; @@ -91,10 +103,31 @@ namespace osu.Game.Overlays.Music { base.LoadComplete(); + // tests might bind externally, in which case we don't want to involve realm. + if (beatmapSets.Count == 0) + beatmapSubscription = realmFactory.RegisterForNotifications(realm => availableBeatmaps, beatmapsChanged); + list.Items.BindTo(beatmapSets); beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo, true); } + private void beatmapsChanged(IRealmCollection sender, ChangeSet changes, Exception error) + { + if (changes == null) + { + beatmapSets.Clear(); + // must use AddRange to avoid RearrangeableList sort overhead per add op. + beatmapSets.AddRange(sender); + return; + } + + foreach (int i in changes.InsertedIndices) + beatmapSets.Insert(i, sender[i]); + + foreach (int i in changes.DeletedIndices.OrderByDescending(i => i)) + beatmapSets.RemoveAt(i); + } + protected override void PopIn() { filter.Search.HoldFocus = true; @@ -123,5 +156,11 @@ namespace osu.Game.Overlays.Music beatmap.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First()); beatmap.Value.Track.Restart(); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + beatmapSubscription?.Dispose(); + } } } From ace2bd2208eead324a2ad8753b4c33bb6e1d02ea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Jan 2022 01:18:29 +0900 Subject: [PATCH 03/10] Apply some initial optimisations to `PlaylistItem` --- osu.Game/Overlays/Music/PlaylistItem.cs | 44 +++++++++++-------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 04c12b8cd7..b3b039148b 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -32,8 +32,6 @@ namespace osu.Game.Overlays.Music : base(item) { Padding = new MarginPadding { Left = 5 }; - - FilterTerms = item.Metadata.GetSearchableTerms(); } [BackgroundDependencyLoader] @@ -46,6 +44,25 @@ namespace osu.Game.Overlays.Music { base.LoadComplete(); + var metadata = Model.Metadata; + + var title = new RomanisableString(metadata.TitleUnicode, metadata.Title); + var artist = new RomanisableString(metadata.ArtistUnicode, metadata.Artist); + + titlePart = text.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)); + + updateSelectionState(true); + titlePart.DrawablePartsRecreated += _ => updateSelectionState(true); + + text.AddText(@" "); // to separate the title from the artist. + + text.AddText(artist, sprite => + { + sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold); + sprite.Colour = colours.Gray9; + sprite.Padding = new MarginPadding { Top = 1 }; + }); + SelectedSet.BindValueChanged(set => { if (set.OldValue?.Equals(Model) != true && set.NewValue?.Equals(Model) != true) @@ -67,27 +84,6 @@ namespace osu.Game.Overlays.Music AutoSizeAxes = Axes.Y, }; - protected override void LoadAsyncComplete() - { - base.LoadAsyncComplete(); - - var title = new RomanisableString(Model.Metadata.TitleUnicode, Model.Metadata.Title); - var artist = new RomanisableString(Model.Metadata.ArtistUnicode, Model.Metadata.Artist); - - titlePart = text.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)); - updateSelectionState(true); - titlePart.DrawablePartsRecreated += _ => updateSelectionState(true); - - text.AddText(@" "); // to separate the title from the artist. - - text.AddText(artist, sprite => - { - sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold); - sprite.Colour = colours.Gray9; - sprite.Padding = new MarginPadding { Top = 1 }; - }); - } - protected override bool OnClick(ClickEvent e) { RequestSelection?.Invoke(Model); @@ -109,7 +105,7 @@ namespace osu.Game.Overlays.Music } } - public IEnumerable FilterTerms { get; } + public IEnumerable FilterTerms => Model.Metadata.GetSearchableTerms(); private bool matchingFilter = true; From 2a786f9ec0302f3ba39561ae5a5d56a0eafa7fe5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Jan 2022 01:49:07 +0900 Subject: [PATCH 04/10] Load text only after it comes on screen (and tidy up selection handling logic) --- osu.Game/Overlays/Music/PlaylistItem.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index b3b039148b..b31a03a64d 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -50,12 +50,9 @@ namespace osu.Game.Overlays.Music var artist = new RomanisableString(metadata.ArtistUnicode, metadata.Artist); titlePart = text.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)); - - updateSelectionState(true); titlePart.DrawablePartsRecreated += _ => updateSelectionState(true); text.AddText(@" "); // to separate the title from the artist. - text.AddText(artist, sprite => { sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold); @@ -65,24 +62,31 @@ namespace osu.Game.Overlays.Music SelectedSet.BindValueChanged(set => { - if (set.OldValue?.Equals(Model) != true && set.NewValue?.Equals(Model) != true) + bool newSelected = set.NewValue?.Equals(Model) == true; + + if (newSelected == selected) return; + selected = newSelected; updateSelectionState(false); - }, true); + }); + + updateSelectionState(true); } + private bool selected; + private void updateSelectionState(bool instant) { foreach (Drawable s in titlePart.Drawables) - s.FadeColour(SelectedSet.Value?.Equals(Model) == true ? colours.Yellow : Color4.White, instant ? 0 : FADE_DURATION); + s.FadeColour(selected ? colours.Yellow : Color4.White, instant ? 0 : FADE_DURATION); } - protected override Drawable CreateContent() => text = new OsuTextFlowContainer + protected override Drawable CreateContent() => new DelayedLoadWrapper(text = new OsuTextFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - }; + }); protected override bool OnClick(ClickEvent e) { From 83b0e4572a057c520723c3319d7227c1ccf8951f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Jan 2022 02:39:01 +0900 Subject: [PATCH 05/10] Fix test failures --- osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index 62f3b63780..7131c19471 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("drag to 5th", () => { var item = this.ChildrenOfType().ElementAt(4); - InputManager.MoveMouseTo(item.ScreenSpaceDrawQuad.Centre); + InputManager.MoveMouseTo(item.ScreenSpaceDrawQuad.BottomLeft); }); AddAssert("song 1 is 5th", () => beatmapSets[4].Equals(first)); From 1a776a95877907b7d9304ffa6ac4a529558f1b79 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Jan 2022 04:27:07 +0900 Subject: [PATCH 06/10] Completely remove subscription from `MusicController` --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 10 ++-- osu.Game/Overlays/MusicController.cs | 68 ++++------------------ 2 files changed, 16 insertions(+), 62 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 245886743a..6adcd2a6d6 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -34,13 +34,13 @@ namespace osu.Game.Overlays.Music private BeatmapManager beatmaps { get; set; } [Resolved] - private RealmContextFactory realmFactory { get; set; } + private RealmAccess realm { get; set; } private IDisposable beatmapSubscription; - private IQueryable availableBeatmaps => realmFactory.Context - .All() - .Where(s => !s.DeletePending); + private IQueryable availableBeatmaps => realm.Realm + .All() + .Where(s => !s.DeletePending); private FilterControl filter; private Playlist list; @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.Music // tests might bind externally, in which case we don't want to involve realm. if (beatmapSets.Count == 0) - beatmapSubscription = realmFactory.RegisterForNotifications(realm => availableBeatmaps, beatmapsChanged); + beatmapSubscription = realm.RegisterForNotifications(realm => availableBeatmaps, beatmapsChanged); list.Items.BindTo(beatmapSets); beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo, true); diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 335abb53dc..5fc0da8891 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -16,7 +16,6 @@ using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Rulesets.Mods; -using Realms; namespace osu.Game.Overlays { @@ -25,8 +24,6 @@ namespace osu.Game.Overlays /// public class MusicController : CompositeDrawable { - private IDisposable beatmapSubscription; - [Resolved] private BeatmapManager beatmaps { get; set; } @@ -35,8 +32,6 @@ namespace osu.Game.Overlays /// private const double restart_cutoff_point = 5000; - private readonly BindableList beatmapSets = new BindableList(); - /// /// Whether the user has requested the track to be paused. Use to determine whether the track is still playing. /// @@ -69,50 +64,11 @@ namespace osu.Game.Overlays mods.BindValueChanged(_ => ResetTrackAdjustments(), true); } - private IQueryable queryRealmBeatmapSets() => - realm.Realm - .All() - .Where(s => !s.DeletePending); - - protected override void LoadComplete() - { - base.LoadComplete(); - beatmapSubscription = realm.RegisterForNotifications(r => queryRealmBeatmapSets(), beatmapsChanged); - } - - private void beatmapsChanged(IRealmCollection sender, ChangeSet changes, Exception error) - { - if (changes == null) - { - beatmapSets.Clear(); - foreach (var s in sender) - beatmapSets.Add(s); - return; - } - - foreach (int i in changes.InsertedIndices) - beatmapSets.Insert(i, sender[i]); - - foreach (int i in changes.DeletedIndices.OrderByDescending(i => i)) - beatmapSets.RemoveAt(i); - } - /// /// Forcefully reload the current 's track from disk. /// public void ReloadCurrentTrack() => changeTrack(); - /// - /// Change the position of a in the current playlist. - /// - /// The beatmap to move. - /// The new position. - public void ChangeBeatmapSetPosition(BeatmapSetInfo beatmapSetInfo, int index) - { - beatmapSets.Remove(beatmapSetInfo); - beatmapSets.Insert(index, beatmapSetInfo); - } - /// /// Returns whether the beatmap track is playing. /// @@ -238,11 +194,12 @@ namespace osu.Game.Overlays queuedDirection = TrackChangeDirection.Prev; - var playable = beatmapSets.TakeWhile(i => !i.Equals(current.BeatmapSetInfo)).LastOrDefault() ?? beatmapSets.LastOrDefault(); + var playableSet = getBeatmapSets().AsEnumerable().TakeWhile(i => !i.Equals(current.BeatmapSetInfo)).LastOrDefault() + ?? getBeatmapSets().LastOrDefault(); - if (playable != null) + if (playableSet != null) { - changeBeatmap(beatmaps.GetWorkingBeatmap(playable.Beatmaps.First())); + changeBeatmap(beatmaps.GetWorkingBeatmap(playableSet.Beatmaps.First())); restartTrack(); return PreviousTrackResult.Previous; } @@ -269,7 +226,9 @@ namespace osu.Game.Overlays queuedDirection = TrackChangeDirection.Next; - var playableSet = beatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).ElementAtOrDefault(1) ?? beatmapSets.FirstOrDefault(); + var playableSet = getBeatmapSets().AsEnumerable().SkipWhile(i => !i.Equals(current.BeatmapSetInfo)).ElementAtOrDefault(1) + ?? getBeatmapSets().FirstOrDefault(); + var playableBeatmap = playableSet?.Beatmaps.FirstOrDefault(); if (playableBeatmap != null) @@ -293,6 +252,8 @@ namespace osu.Game.Overlays private TrackChangeDirection? queuedDirection; + private IQueryable getBeatmapSets() => realm.Realm.All().Where(s => !s.DeletePending); + private void beatmapChanged(ValueChangedEvent beatmap) => changeBeatmap(beatmap.NewValue); private void changeBeatmap(WorkingBeatmap newWorking) @@ -320,8 +281,8 @@ namespace osu.Game.Overlays else { // figure out the best direction based on order in playlist. - int last = beatmapSets.TakeWhile(b => !b.Equals(current.BeatmapSetInfo)).Count(); - int next = newWorking == null ? -1 : beatmapSets.TakeWhile(b => !b.Equals(newWorking.BeatmapSetInfo)).Count(); + int last = getBeatmapSets().AsEnumerable().TakeWhile(b => !b.Equals(current.BeatmapSetInfo)).Count(); + int next = newWorking == null ? -1 : getBeatmapSets().AsEnumerable().TakeWhile(b => !b.Equals(newWorking.BeatmapSetInfo)).Count(); direction = last > next ? TrackChangeDirection.Prev : TrackChangeDirection.Next; } @@ -435,13 +396,6 @@ namespace osu.Game.Overlays mod.ApplyToTrack(CurrentTrack); } } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - beatmapSubscription?.Dispose(); - } } public enum TrackChangeDirection From 64914c45a4d7528713b8d06d3e7d54c2335db2cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Jan 2022 11:53:50 +0900 Subject: [PATCH 07/10] Remove unnecessary realm query helper method --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 6adcd2a6d6..ffddf168ed 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -38,10 +38,6 @@ namespace osu.Game.Overlays.Music private IDisposable beatmapSubscription; - private IQueryable availableBeatmaps => realm.Realm - .All() - .Where(s => !s.DeletePending); - private FilterControl filter; private Playlist list; @@ -105,7 +101,7 @@ namespace osu.Game.Overlays.Music // tests might bind externally, in which case we don't want to involve realm. if (beatmapSets.Count == 0) - beatmapSubscription = realm.RegisterForNotifications(realm => availableBeatmaps, beatmapsChanged); + beatmapSubscription = realm.RegisterForNotifications(r => r.All().Where(s => !s.DeletePending), beatmapsChanged); list.Items.BindTo(beatmapSets); beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo, true); From dda513dd08f4aad11b847fef0da0ef4e669f35b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Jan 2022 12:19:05 +0900 Subject: [PATCH 08/10] Change `PlaylistOverlay` to use `ILive` --- .../UserInterface/TestScenePlaylistOverlay.cs | 9 +-- osu.Game/Collections/BeatmapCollection.cs | 2 +- .../Collections/CollectionFilterDropdown.cs | 4 +- osu.Game/Overlays/Music/Playlist.cs | 17 ++--- osu.Game/Overlays/Music/PlaylistItem.cs | 66 ++++++++++--------- osu.Game/Overlays/Music/PlaylistOverlay.cs | 42 +++++++----- 6 files changed, 76 insertions(+), 64 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index 7131c19471..1a3e38ddd7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Database; using osu.Game.Graphics.Containers; using osu.Game.Overlays.Music; using osu.Game.Tests.Resources; @@ -18,11 +19,11 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestScenePlaylistOverlay : OsuManualInputManagerTestScene { - private readonly BindableList beatmapSets = new BindableList(); + private readonly BindableList> beatmapSets = new BindableList>(); private PlaylistOverlay playlistOverlay; - private BeatmapSetInfo first; + private ILive first; [SetUp] public void Setup() => Schedule(() => @@ -45,7 +46,7 @@ namespace osu.Game.Tests.Visual.UserInterface for (int i = 0; i < 100; i++) { - beatmapSets.Add(TestResources.CreateTestBeatmapSetInfo()); + beatmapSets.Add(TestResources.CreateTestBeatmapSetInfo().ToLiveUnmanaged()); } first = beatmapSets.First(); @@ -60,7 +61,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("hold 1st item handle", () => { - var handle = this.ChildrenOfType.PlaylistItemHandle>().First(); + var handle = this.ChildrenOfType>.PlaylistItemHandle>().First(); InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre); InputManager.PressButton(MouseButton.Left); }); diff --git a/osu.Game/Collections/BeatmapCollection.cs b/osu.Game/Collections/BeatmapCollection.cs index 1a739f824f..7e4b15ecf9 100644 --- a/osu.Game/Collections/BeatmapCollection.cs +++ b/osu.Game/Collections/BeatmapCollection.cs @@ -25,7 +25,7 @@ namespace osu.Game.Collections /// /// The beatmaps contained by the collection. /// - public readonly BindableList Beatmaps = new BindableList(); + public readonly BindableList Beatmaps = new BindableList(); /// /// The date when this collection was last modified. diff --git a/osu.Game/Collections/CollectionFilterDropdown.cs b/osu.Game/Collections/CollectionFilterDropdown.cs index 77bda00107..c46ba8e06e 100644 --- a/osu.Game/Collections/CollectionFilterDropdown.cs +++ b/osu.Game/Collections/CollectionFilterDropdown.cs @@ -38,7 +38,7 @@ namespace osu.Game.Collections } private readonly IBindableList collections = new BindableList(); - private readonly IBindableList beatmaps = new BindableList(); + private readonly IBindableList beatmaps = new BindableList(); private readonly BindableList filters = new BindableList(); [Resolved(CanBeNull = true)] @@ -196,7 +196,7 @@ namespace osu.Game.Collections private IBindable beatmap { get; set; } [CanBeNull] - private readonly BindableList collectionBeatmaps; + private readonly BindableList collectionBeatmaps; [NotNull] private readonly Bindable collectionName; diff --git a/osu.Game/Overlays/Music/Playlist.cs b/osu.Game/Overlays/Music/Playlist.cs index 0b15a3a1bc..c86146ff25 100644 --- a/osu.Game/Overlays/Music/Playlist.cs +++ b/osu.Game/Overlays/Music/Playlist.cs @@ -7,16 +7,17 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; +using osu.Game.Database; using osu.Game.Graphics.Containers; using osuTK; namespace osu.Game.Overlays.Music { - public class Playlist : OsuRearrangeableListContainer + public class Playlist : OsuRearrangeableListContainer> { - public Action RequestSelection; + public Action> RequestSelection; - public readonly Bindable SelectedSet = new Bindable(); + public readonly Bindable> SelectedSet = new Bindable>(); public new MarginPadding Padding { @@ -26,23 +27,23 @@ namespace osu.Game.Overlays.Music public void Filter(FilterCriteria criteria) { - var items = (SearchContainer>)ListContainer; + var items = (SearchContainer>>)ListContainer; foreach (var item in items.OfType()) - item.InSelectedCollection = criteria.Collection?.Beatmaps.Any(b => item.Model.Equals(b.BeatmapSet)) ?? true; + item.InSelectedCollection = criteria.Collection?.Beatmaps.Any(b => item.Model.ID == b.BeatmapSet?.ID) ?? true; items.SearchTerm = criteria.SearchText; } - public BeatmapSetInfo FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); + public ILive FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); - protected override OsuRearrangeableListItem CreateOsuDrawable(BeatmapSetInfo item) => new PlaylistItem(item) + protected override OsuRearrangeableListItem> CreateOsuDrawable(ILive item) => new PlaylistItem(item) { SelectedSet = { BindTarget = SelectedSet }, RequestSelection = set => RequestSelection?.Invoke(set) }; - protected override FillFlowContainer> CreateListFillFlowContainer() => new SearchContainer> + protected override FillFlowContainer>> CreateListFillFlowContainer() => new SearchContainer>> { Spacing = new Vector2(0, 3), LayoutDuration = 200, diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index b31a03a64d..3f82580bfb 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -10,17 +10,18 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Beatmaps; +using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK.Graphics; namespace osu.Game.Overlays.Music { - public class PlaylistItem : OsuRearrangeableListItem, IFilterable + public class PlaylistItem : OsuRearrangeableListItem>, IFilterable { - public readonly Bindable SelectedSet = new Bindable(); + public readonly Bindable> SelectedSet = new Bindable>(); - public Action RequestSelection; + public Action> RequestSelection; private TextFlowContainer text; private ITextPart titlePart; @@ -28,7 +29,7 @@ namespace osu.Game.Overlays.Music [Resolved] private OsuColour colours { get; set; } - public PlaylistItem(BeatmapSetInfo item) + public PlaylistItem(ILive item) : base(item) { Padding = new MarginPadding { Left = 5 }; @@ -44,34 +45,37 @@ namespace osu.Game.Overlays.Music { base.LoadComplete(); - var metadata = Model.Metadata; - - var title = new RomanisableString(metadata.TitleUnicode, metadata.Title); - var artist = new RomanisableString(metadata.ArtistUnicode, metadata.Artist); - - titlePart = text.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)); - titlePart.DrawablePartsRecreated += _ => updateSelectionState(true); - - text.AddText(@" "); // to separate the title from the artist. - text.AddText(artist, sprite => + Model.PerformRead(m => { - sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold); - sprite.Colour = colours.Gray9; - sprite.Padding = new MarginPadding { Top = 1 }; + var metadata = m.Metadata; + + var title = new RomanisableString(metadata.TitleUnicode, metadata.Title); + var artist = new RomanisableString(metadata.ArtistUnicode, metadata.Artist); + + titlePart = text.AddText(title, sprite => sprite.Font = OsuFont.GetFont(weight: FontWeight.Regular)); + titlePart.DrawablePartsRecreated += _ => updateSelectionState(true); + + text.AddText(@" "); // to separate the title from the artist. + text.AddText(artist, sprite => + { + sprite.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold); + sprite.Colour = colours.Gray9; + sprite.Padding = new MarginPadding { Top = 1 }; + }); + + SelectedSet.BindValueChanged(set => + { + bool newSelected = set.NewValue?.Equals(Model) == true; + + if (newSelected == selected) + return; + + selected = newSelected; + updateSelectionState(false); + }); + + updateSelectionState(true); }); - - SelectedSet.BindValueChanged(set => - { - bool newSelected = set.NewValue?.Equals(Model) == true; - - if (newSelected == selected) - return; - - selected = newSelected; - updateSelectionState(false); - }); - - updateSelectionState(true); } private bool selected; @@ -109,7 +113,7 @@ namespace osu.Game.Overlays.Music } } - public IEnumerable FilterTerms => Model.Metadata.GetSearchableTerms(); + public IEnumerable FilterTerms => Model.PerformRead(m => m.Metadata.GetSearchableTerms()); private bool matchingFilter = true; diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index ffddf168ed..4b10bb779e 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -24,9 +24,9 @@ namespace osu.Game.Overlays.Music private const float transition_duration = 600; private const float playlist_height = 510; - public IBindableList BeatmapSets => beatmapSets; + public IBindableList> BeatmapSets => beatmapSets; - private readonly BindableList beatmapSets = new BindableList(); + private readonly BindableList> beatmapSets = new BindableList>(); private readonly Bindable beatmap = new Bindable(); @@ -85,13 +85,16 @@ namespace osu.Game.Overlays.Music filter.Search.OnCommit += (sender, newText) => { - BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps.FirstOrDefault(); - - if (toSelect != null) + list.FirstVisibleSet.PerformRead(set => { - beatmap.Value = beatmaps.GetWorkingBeatmap(toSelect); - beatmap.Value.Track.Restart(); - } + BeatmapInfo toSelect = set.Beatmaps.FirstOrDefault(); + + if (toSelect != null) + { + beatmap.Value = beatmaps.GetWorkingBeatmap(toSelect); + beatmap.Value.Track.Restart(); + } + }); }; } @@ -104,7 +107,7 @@ namespace osu.Game.Overlays.Music beatmapSubscription = realm.RegisterForNotifications(r => r.All().Where(s => !s.DeletePending), beatmapsChanged); list.Items.BindTo(beatmapSets); - beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo, true); + beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo.ToLive(realm), true); } private void beatmapsChanged(IRealmCollection sender, ChangeSet changes, Exception error) @@ -113,12 +116,12 @@ namespace osu.Game.Overlays.Music { beatmapSets.Clear(); // must use AddRange to avoid RearrangeableList sort overhead per add op. - beatmapSets.AddRange(sender); + beatmapSets.AddRange(sender.ToLive(realm)); return; } foreach (int i in changes.InsertedIndices) - beatmapSets.Insert(i, sender[i]); + beatmapSets.Insert(i, sender[i].ToLive(realm)); foreach (int i in changes.DeletedIndices.OrderByDescending(i => i)) beatmapSets.RemoveAt(i); @@ -141,16 +144,19 @@ namespace osu.Game.Overlays.Music this.FadeOut(transition_duration); } - private void itemSelected(BeatmapSetInfo set) + private void itemSelected(ILive beatmapSet) { - if (set.Equals((beatmap.Value?.BeatmapSetInfo))) + beatmapSet.PerformRead(set => { - beatmap.Value?.Track.Seek(0); - return; - } + if (set.Equals((beatmap.Value?.BeatmapSetInfo))) + { + beatmap.Value?.Track.Seek(0); + return; + } - beatmap.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First()); - beatmap.Value.Track.Restart(); + beatmap.Value = beatmaps.GetWorkingBeatmap(set.Beatmaps.First()); + beatmap.Value.Track.Restart(); + }); } protected override void Dispose(bool isDisposing) From 9532454e2a0d691652f40b7e15c3bd3503d9c9b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Jan 2022 15:12:01 +0900 Subject: [PATCH 09/10] Remove `ILive` remnants --- .../UserInterface/TestScenePlaylistOverlay.cs | 6 +++--- osu.Game/Overlays/Music/Playlist.cs | 14 +++++++------- osu.Game/Overlays/Music/PlaylistItem.cs | 8 ++++---- osu.Game/Overlays/Music/PlaylistOverlay.cs | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index 1a3e38ddd7..09e5bc849e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -19,11 +19,11 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestScenePlaylistOverlay : OsuManualInputManagerTestScene { - private readonly BindableList> beatmapSets = new BindableList>(); + private readonly BindableList> beatmapSets = new BindableList>(); private PlaylistOverlay playlistOverlay; - private ILive first; + private Live first; [SetUp] public void Setup() => Schedule(() => @@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("hold 1st item handle", () => { - var handle = this.ChildrenOfType>.PlaylistItemHandle>().First(); + var handle = this.ChildrenOfType>.PlaylistItemHandle>().First(); InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre); InputManager.PressButton(MouseButton.Left); }); diff --git a/osu.Game/Overlays/Music/Playlist.cs b/osu.Game/Overlays/Music/Playlist.cs index c86146ff25..24d867141c 100644 --- a/osu.Game/Overlays/Music/Playlist.cs +++ b/osu.Game/Overlays/Music/Playlist.cs @@ -13,11 +13,11 @@ using osuTK; namespace osu.Game.Overlays.Music { - public class Playlist : OsuRearrangeableListContainer> + public class Playlist : OsuRearrangeableListContainer> { - public Action> RequestSelection; + public Action> RequestSelection; - public readonly Bindable> SelectedSet = new Bindable>(); + public readonly Bindable> SelectedSet = new Bindable>(); public new MarginPadding Padding { @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Music public void Filter(FilterCriteria criteria) { - var items = (SearchContainer>>)ListContainer; + var items = (SearchContainer>>)ListContainer; foreach (var item in items.OfType()) item.InSelectedCollection = criteria.Collection?.Beatmaps.Any(b => item.Model.ID == b.BeatmapSet?.ID) ?? true; @@ -35,15 +35,15 @@ namespace osu.Game.Overlays.Music items.SearchTerm = criteria.SearchText; } - public ILive FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); + public Live FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); - protected override OsuRearrangeableListItem> CreateOsuDrawable(ILive item) => new PlaylistItem(item) + protected override OsuRearrangeableListItem> CreateOsuDrawable(Live item) => new PlaylistItem(item) { SelectedSet = { BindTarget = SelectedSet }, RequestSelection = set => RequestSelection?.Invoke(set) }; - protected override FillFlowContainer>> CreateListFillFlowContainer() => new SearchContainer>> + protected override FillFlowContainer>> CreateListFillFlowContainer() => new SearchContainer>> { Spacing = new Vector2(0, 3), LayoutDuration = 200, diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 3f82580bfb..f081cc0503 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -17,11 +17,11 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Music { - public class PlaylistItem : OsuRearrangeableListItem>, IFilterable + public class PlaylistItem : OsuRearrangeableListItem>, IFilterable { - public readonly Bindable> SelectedSet = new Bindable>(); + public readonly Bindable> SelectedSet = new Bindable>(); - public Action> RequestSelection; + public Action> RequestSelection; private TextFlowContainer text; private ITextPart titlePart; @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Music [Resolved] private OsuColour colours { get; set; } - public PlaylistItem(ILive item) + public PlaylistItem(Live item) : base(item) { Padding = new MarginPadding { Left = 5 }; diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 4b10bb779e..7b705a905b 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -24,9 +24,9 @@ namespace osu.Game.Overlays.Music private const float transition_duration = 600; private const float playlist_height = 510; - public IBindableList> BeatmapSets => beatmapSets; + public IBindableList> BeatmapSets => beatmapSets; - private readonly BindableList> beatmapSets = new BindableList>(); + private readonly BindableList> beatmapSets = new BindableList>(); private readonly Bindable beatmap = new Bindable(); @@ -144,7 +144,7 @@ namespace osu.Game.Overlays.Music this.FadeOut(transition_duration); } - private void itemSelected(ILive beatmapSet) + private void itemSelected(Live beatmapSet) { beatmapSet.PerformRead(set => { From b3f2392358ac141b17f28328932d299384e3bec9 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 26 Jan 2022 19:04:18 +0900 Subject: [PATCH 10/10] Resolve compilation error due to removed method --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 7b705a905b..59ade0918d 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -116,7 +116,7 @@ namespace osu.Game.Overlays.Music { beatmapSets.Clear(); // must use AddRange to avoid RearrangeableList sort overhead per add op. - beatmapSets.AddRange(sender.ToLive(realm)); + beatmapSets.AddRange(sender.Select(b => b.ToLive(realm))); return; }