diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index c39e9abf8b..157c814f55 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -71,9 +71,9 @@ namespace osu.Game.Graphics.Containers switch (linkType) { case LinkAction.OpenBeatmap: - // todo: replace this with overlay.ShowBeatmap(id) once an appropriate API call is implemented. - if (int.TryParse(linkArgument, out int beatmapId)) - Process.Start($"https://osu.ppy.sh/b/{beatmapId}"); + // TODO: proper query params handling + if (linkArgument != null && int.TryParse(linkArgument.Contains('?') ? linkArgument.Split('?')[0] : linkArgument, out int beatmapId)) + game?.ShowBeatmap(beatmapId); break; case LinkAction.OpenBeatmapSet: if (int.TryParse(linkArgument, out int setId)) diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs index b031791900..37dd77af46 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetRequest.cs @@ -5,13 +5,21 @@ namespace osu.Game.Online.API.Requests { public class GetBeatmapSetRequest : APIRequest { - private readonly int beatmapSetId; + private readonly int id; + private readonly BeatmapSetLookupType type; - public GetBeatmapSetRequest(int beatmapSetId) + public GetBeatmapSetRequest(int id, BeatmapSetLookupType type = BeatmapSetLookupType.SetId) { - this.beatmapSetId = beatmapSetId; + this.id = id; + this.type = type; } - protected override string Target => $@"beatmapsets/{beatmapSetId}"; + protected override string Target => type == BeatmapSetLookupType.SetId ? $@"beatmapsets/{id}" : $@"beatmapsets/lookup?beatmap_id={id}"; + } + + public enum BeatmapSetLookupType + { + SetId, + BeatmapId, } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 578d88bd89..3852580c49 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -166,6 +166,12 @@ namespace osu.Game /// The user to display. public void ShowUser(long userId) => userProfile.ShowUser(userId); + /// + /// Show a beatmap's set as an overlay, displaying the given beatmap. + /// + /// The beatmap to show. + public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId); + protected void LoadScore(Score s) { scoreLoad?.Cancel(); diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 366c34eae3..096f7bb63c 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -17,21 +17,39 @@ using osu.Game.Online.API.Requests; using osu.Game.Overlays.BeatmapSet; using osu.Game.Rulesets; using osu.Game.Overlays.BeatmapSet.Scores; +using System.Linq; namespace osu.Game.Overlays { public class BeatmapSetOverlay : WaveOverlayContainer { + private const int fade_duration = 300; + public const float X_PADDING = 40; public const float RIGHT_WIDTH = 275; private readonly Header header; private readonly Info info; + private APIAccess api; private RulesetStore rulesets; private readonly ScrollContainer scroll; + private BeatmapSetInfo beatmapSet; + + public BeatmapSetInfo BeatmapSet + { + get => beatmapSet; + set + { + if (value == beatmapSet) + return; + + header.BeatmapSet = info.BeatmapSet = beatmapSet = value; + } + } + // receive input outside our bounds so we can trigger a close event on ourselves. public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true; @@ -107,7 +125,8 @@ namespace osu.Game.Overlays { base.PopOut(); header.Details.StopPreview(); - FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out); + + FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); } protected override bool OnClick(InputState state) @@ -116,17 +135,31 @@ namespace osu.Game.Overlays return true; } + public void FetchAndShowBeatmap(int beatmapId) + { + BeatmapSet = null; + var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId); + req.Success += res => + { + ShowBeatmapSet(res.ToBeatmapSet(rulesets)); + header.Picker.Beatmap.Value = header.BeatmapSet.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId); + }; + api.Queue(req); + Show(); + } + public void FetchAndShowBeatmapSet(int beatmapSetId) { - // todo: display the overlay while we are loading here. we need to support setting BeatmapSet to null for this to work. + BeatmapSet = null; var req = new GetBeatmapSetRequest(beatmapSetId); req.Success += res => ShowBeatmapSet(res.ToBeatmapSet(rulesets)); api.Queue(req); + Show(); } public void ShowBeatmapSet(BeatmapSetInfo set) { - header.BeatmapSet = info.BeatmapSet = set; + BeatmapSet = set; Show(); scroll.ScrollTo(0); } diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index cda8a549da..f39952dc31 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -17,6 +17,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; using OpenTK; using OpenTK.Graphics; @@ -35,6 +36,8 @@ namespace osu.Game.Screens.Select.Carousel private Triangles triangles; private StarCounter starCounter; + private BeatmapSetOverlay beatmapOverlay; + public DrawableCarouselBeatmap(CarouselBeatmap panel) : base(panel) { beatmap = panel.Beatmap; @@ -42,8 +45,10 @@ namespace osu.Game.Screens.Select.Carousel } [BackgroundDependencyLoader(true)] - private void load(SongSelect songSelect, BeatmapManager manager) + private void load(SongSelect songSelect, BeatmapManager manager, BeatmapSetOverlay beatmapOverlay) { + this.beatmapOverlay = beatmapOverlay; + if (songSelect != null) { startRequested = songSelect.FinaliseSelection; @@ -171,6 +176,10 @@ namespace osu.Game.Screens.Select.Carousel new OsuMenuItem("Play", MenuItemType.Highlighted, () => startRequested?.Invoke(beatmap)), new OsuMenuItem("Edit", MenuItemType.Standard, () => editRequested?.Invoke(beatmap)), new OsuMenuItem("Hide", MenuItemType.Destructive, () => hideRequested?.Invoke(beatmap)), + new OsuMenuItem("Details", MenuItemType.Standard, () => + { + if (beatmap.OnlineBeatmapID.HasValue) beatmapOverlay?.FetchAndShowBeatmap(beatmap.OnlineBeatmapID.Value); + }), }; } }