-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #31821 from Layendan/playlist-collection
Add playlist to new collection button present on playlist room
- Loading branch information
Showing
3 changed files
with
301 additions
and
0 deletions.
There are no files selected for viewing
113 changes: 113 additions & 0 deletions
113
osu.Game.Tests/Visual/Playlists/TestSceneAddPlaylistToCollectionButton.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence. | ||
// See the LICENCE file in the repository root for full licence text. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using NUnit.Framework; | ||
using osu.Framework.Allocation; | ||
using osu.Framework.Audio; | ||
using osu.Framework.Graphics; | ||
using osu.Framework.Platform; | ||
using osu.Framework.Testing; | ||
using osu.Game.Beatmaps; | ||
using osu.Game.Collections; | ||
using osu.Game.Database; | ||
using osu.Game.Online.Rooms; | ||
using osu.Game.Overlays; | ||
using osu.Game.Rulesets; | ||
using osu.Game.Rulesets.Osu; | ||
using osu.Game.Screens.OnlinePlay.Playlists; | ||
using osuTK; | ||
using osuTK.Input; | ||
using SharpCompress; | ||
|
||
namespace osu.Game.Tests.Visual.Playlists | ||
{ | ||
public partial class TestSceneAddPlaylistToCollectionButton : OsuManualInputManagerTestScene | ||
{ | ||
private BeatmapManager manager = null!; | ||
private BeatmapSetInfo importedBeatmap = null!; | ||
private Room room = null!; | ||
private AddPlaylistToCollectionButton button = null!; | ||
|
||
[BackgroundDependencyLoader] | ||
private void load(GameHost host, AudioManager audio) | ||
{ | ||
Dependencies.Cache(new RealmRulesetStore(Realm)); | ||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default)); | ||
Dependencies.Cache(Realm); | ||
|
||
Add(notificationOverlay); | ||
} | ||
|
||
[Cached(typeof(INotificationOverlay))] | ||
private NotificationOverlay notificationOverlay = new NotificationOverlay | ||
{ | ||
Anchor = Anchor.TopRight, | ||
Origin = Anchor.TopRight, | ||
}; | ||
|
||
[SetUpSteps] | ||
public void SetUpSteps() | ||
{ | ||
AddStep("clear realm", () => Realm.Realm.Write(() => Realm.Realm.RemoveAll<BeatmapCollection>())); | ||
|
||
AddStep("clear notifications", () => notificationOverlay.AllNotifications.Empty()); | ||
|
||
importBeatmap(); | ||
|
||
setupRoom(); | ||
|
||
AddStep("create button", () => | ||
{ | ||
Add(button = new AddPlaylistToCollectionButton(room) | ||
{ | ||
Anchor = Anchor.Centre, | ||
Origin = Anchor.Centre, | ||
Size = new Vector2(300, 40), | ||
}); | ||
}); | ||
} | ||
|
||
[Test] | ||
public void TestButtonFlow() | ||
{ | ||
AddStep("move mouse to button", () => InputManager.MoveMouseTo(button)); | ||
|
||
AddStep("click button", () => InputManager.Click(MouseButton.Left)); | ||
|
||
AddUntilStep("notification shown", () => notificationOverlay.AllNotifications.Any(n => n.Text.ToString().StartsWith("Created new collection", StringComparison.Ordinal))); | ||
|
||
AddUntilStep("realm is updated", () => Realm.Realm.All<BeatmapCollection>().FirstOrDefault(c => c.Name == room.Name) != null); | ||
} | ||
|
||
private void importBeatmap() => AddStep("import beatmap", () => | ||
{ | ||
var beatmap = CreateBeatmap(new OsuRuleset().RulesetInfo); | ||
|
||
Debug.Assert(beatmap.BeatmapInfo.BeatmapSet != null); | ||
|
||
importedBeatmap = manager.Import(beatmap.BeatmapInfo.BeatmapSet)!.Value.Detach(); | ||
}); | ||
|
||
private void setupRoom() => AddStep("setup room", () => | ||
{ | ||
room = new Room | ||
{ | ||
Name = "my awesome room", | ||
MaxAttempts = 5, | ||
Host = API.LocalUser.Value | ||
}; | ||
room.RecentParticipants = [room.Host]; | ||
room.EndDate = DateTimeOffset.Now.AddMinutes(5); | ||
room.Playlist = | ||
[ | ||
new PlaylistItem(importedBeatmap.Beatmaps.First()) | ||
{ | ||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID | ||
} | ||
]; | ||
}); | ||
} | ||
} |
178 changes: 178 additions & 0 deletions
178
osu.Game/Screens/OnlinePlay/Playlists/AddPlaylistToCollectionButton.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence. | ||
// See the LICENCE file in the repository root for full licence text. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using osu.Framework.Allocation; | ||
using osu.Framework.Graphics.Cursor; | ||
using osu.Framework.Localisation; | ||
using osu.Game.Beatmaps; | ||
using osu.Game.Collections; | ||
using osu.Game.Database; | ||
using osu.Game.Graphics.UserInterfaceV2; | ||
using osu.Game.Online.Rooms; | ||
using osu.Game.Overlays; | ||
using osu.Game.Overlays.Notifications; | ||
using Realms; | ||
|
||
namespace osu.Game.Screens.OnlinePlay.Playlists | ||
{ | ||
public partial class AddPlaylistToCollectionButton : RoundedButton, IHasTooltip | ||
{ | ||
private readonly Room room; | ||
|
||
private IDisposable? beatmapSubscription; | ||
private IDisposable? collectionSubscription; | ||
|
||
private Live<BeatmapCollection>? collection; | ||
private HashSet<string> localBeatmapHashes = new HashSet<string>(); | ||
|
||
[Resolved] | ||
private RealmAccess realm { get; set; } = null!; | ||
|
||
[Resolved(canBeNull: true)] | ||
private INotificationOverlay? notifications { get; set; } | ||
|
||
public AddPlaylistToCollectionButton(Room room) | ||
{ | ||
this.room = room; | ||
} | ||
|
||
[BackgroundDependencyLoader] | ||
private void load() | ||
{ | ||
Action = () => | ||
{ | ||
if (room.Playlist.Count == 0) | ||
return; | ||
|
||
int countBefore = 0; | ||
int countAfter = 0; | ||
|
||
Text = "Updating collection..."; | ||
Enabled.Value = false; | ||
|
||
realm.WriteAsync(r => | ||
{ | ||
var beatmaps = getBeatmapsForPlaylist(r).ToArray(); | ||
var c = getCollectionsForPlaylist(r).FirstOrDefault() | ||
?? r.Add(new BeatmapCollection(room.Name)); | ||
|
||
countBefore = c.BeatmapMD5Hashes.Count; | ||
|
||
foreach (var item in beatmaps) | ||
{ | ||
if (!c.BeatmapMD5Hashes.Contains(item.MD5Hash)) | ||
c.BeatmapMD5Hashes.Add(item.MD5Hash); | ||
} | ||
|
||
countAfter = c.BeatmapMD5Hashes.Count; | ||
}).ContinueWith(_ => Schedule(() => | ||
{ | ||
if (countBefore == 0) | ||
notifications?.Post(new SimpleNotification { Text = $"Created new collection \"{room.Name}\" with {countAfter} beatmaps." }); | ||
else | ||
notifications?.Post(new SimpleNotification { Text = $"Added {countAfter - countBefore} beatmaps to collection \"{room.Name}\"." }); | ||
})); | ||
}; | ||
} | ||
|
||
protected override void LoadComplete() | ||
{ | ||
base.LoadComplete(); | ||
|
||
// will be updated via updateButtonState() when ready. | ||
Enabled.Value = false; | ||
|
||
if (room.Playlist.Count == 0) | ||
return; | ||
|
||
beatmapSubscription = realm.RegisterForNotifications(getBeatmapsForPlaylist, (sender, _) => | ||
{ | ||
localBeatmapHashes = sender.Select(b => b.MD5Hash).ToHashSet(); | ||
Schedule(updateButtonState); | ||
}); | ||
|
||
collectionSubscription = realm.RegisterForNotifications(getCollectionsForPlaylist, (sender, _) => | ||
{ | ||
collection = sender.FirstOrDefault()?.ToLive(realm); | ||
Schedule(updateButtonState); | ||
}); | ||
} | ||
|
||
private void updateButtonState() | ||
{ | ||
int countToAdd = getCountToBeAdded(); | ||
|
||
if (collection == null) | ||
Text = $"Create new collection with {countToAdd} beatmaps"; | ||
else if (hasAllItemsInCollection) | ||
Text = "Collection complete!"; | ||
else | ||
Text = $"Add {countToAdd} beatmaps to collection"; | ||
|
||
Enabled.Value = countToAdd > 0; | ||
} | ||
|
||
private int getCountToBeAdded() | ||
{ | ||
if (collection == null) | ||
return localBeatmapHashes.Count; | ||
|
||
return collection.PerformRead(c => | ||
{ | ||
int count = localBeatmapHashes.Count; | ||
|
||
foreach (string hash in localBeatmapHashes) | ||
{ | ||
if (c.BeatmapMD5Hashes.Contains(hash)) | ||
count--; | ||
} | ||
|
||
return count; | ||
}); | ||
} | ||
|
||
private IQueryable<BeatmapCollection> getCollectionsForPlaylist(Realm r) => r.All<BeatmapCollection>().Where(c => c.Name == room.Name); | ||
|
||
private IQueryable<BeatmapInfo> getBeatmapsForPlaylist(Realm r) | ||
{ | ||
return r.All<BeatmapInfo>().Filter(string.Join(" OR ", room.Playlist.Select(item => $"(OnlineID == {item.Beatmap.OnlineID})").Distinct())); | ||
} | ||
|
||
private bool hasAllItemsInCollection | ||
{ | ||
get | ||
{ | ||
if (collection == null) | ||
return false; | ||
|
||
return room.Playlist.DistinctBy(i => i.Beatmap.OnlineID).Count() == | ||
collection.PerformRead(c => c.BeatmapMD5Hashes.Count); | ||
} | ||
} | ||
|
||
protected override void Dispose(bool isDisposing) | ||
{ | ||
base.Dispose(isDisposing); | ||
|
||
beatmapSubscription?.Dispose(); | ||
collectionSubscription?.Dispose(); | ||
} | ||
|
||
public LocalisableString TooltipText | ||
{ | ||
get | ||
{ | ||
if (Enabled.Value) | ||
return string.Empty; | ||
|
||
if (hasAllItemsInCollection) | ||
return "All beatmaps have been added!"; | ||
|
||
return "Download some beatmaps first."; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters