diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs new file mode 100644 index 0000000000..88de1f8b98 --- /dev/null +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs @@ -0,0 +1,166 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables.Cards.Buttons; +using osu.Game.Online; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Rulesets.Osu; +using osu.Game.Tests.Resources; +using osuTK; + +namespace osu.Game.Tests.Visual.Beatmaps +{ + public class TestSceneBeatmapCardDownloadButton : OsuTestScene + { + private TestDownloadButton downloadButton; + + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + [Resolved] + private BeatmapManager beatmaps { get; set; } + + [Test] + public void TestDownloadableBeatmap() + { + createButton(true); + assertDownloadEnabled(true); + + AddStep("set downloading state", () => downloadButton.State.Value = DownloadState.Downloading); + AddStep("set progress to 30%", () => downloadButton.Progress.Value = 0.3f); + AddStep("set progress to 100%", () => downloadButton.Progress.Value = 1f); + AddStep("set importing state", () => downloadButton.State.Value = DownloadState.Importing); + AddStep("set locally available state", () => downloadButton.State.Value = DownloadState.LocallyAvailable); + } + + [Test] + public void TestUndownloadableBeatmap() + { + createButton(false); + assertDownloadEnabled(false); + } + + [Test] + public void TestDownloadState() + { + AddUntilStep("ensure manager loaded", () => beatmaps != null); + ensureSoleilyRemoved(); + createButtonWithBeatmap(createSoleily()); + AddAssert("button state not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded); + AddStep("import soleily", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport())); + + AddUntilStep("wait for beatmap import", () => beatmaps.GetAllUsableBeatmapSets().Any(b => b.OnlineBeatmapSetID == 241526)); + AddUntilStep("button state downloaded", () => downloadButton.State.Value == DownloadState.LocallyAvailable); + + createButtonWithBeatmap(createSoleily()); + AddUntilStep("button state downloaded", () => downloadButton.State.Value == DownloadState.LocallyAvailable); + ensureSoleilyRemoved(); + AddUntilStep("button state not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded); + } + + private void ensureSoleilyRemoved() + { + AddStep("remove soleily", () => + { + var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineBeatmapSetID == 241526); + + if (beatmap != null) beatmaps.Delete(beatmap); + }); + } + + private void assertDownloadEnabled(bool enabled) + { + AddAssert($"button {(enabled ? "enabled" : "disabled")}", () => downloadButton.Download.IsPresent && downloadButton.Download.Enabled.Value == enabled); + } + + private APIBeatmapSet createSoleily() + { + return new APIBeatmapSet + { + OnlineID = 241526, + Availability = new BeatmapSetOnlineAvailability + { + DownloadDisabled = false, + ExternalLink = string.Empty, + }, + }; + } + + private void createButtonWithBeatmap(APIBeatmapSet beatmap) + { + AddStep("create button", () => + { + Child = downloadButton = new TestDownloadButton(beatmap) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(2) + }; + }); + } + + private void createButton(bool downloadable) + { + AddStep("create button", () => + { + Child = downloadButton = new TestDownloadButton(downloadable ? getDownloadableBeatmapSet() : getUndownloadableBeatmapSet()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(2) + }; + }); + } + + private APIBeatmapSet getDownloadableBeatmapSet() + { + var normal = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo); + normal.HasVideo = true; + normal.HasStoryboard = true; + + return normal; + } + + private APIBeatmapSet getUndownloadableBeatmapSet() + { + var beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo); + beatmap.Artist = "test"; + beatmap.Title = "undownloadable"; + beatmap.AuthorString = "test"; + + beatmap.HasVideo = true; + beatmap.HasStoryboard = true; + + beatmap.Availability = new BeatmapSetOnlineAvailability + { + DownloadDisabled = true, + ExternalLink = "https://osu.ppy.sh", + }; + + return beatmap; + } + + private class TestDownloadButton : DownloadButton + { + public readonly Bindable State = new Bindable(); + public readonly BindableNumber Progress = new BindableNumber(); + + public new BeatmapCardIconButton Download => base.Download; + public new BeatmapCardIconButton Play => base.Play; + + public TestDownloadButton(APIBeatmapSet beatmapSet) + : base(beatmapSet) + { + Tracker.State.BindTo(State); + Tracker.Progress.BindTo(Progress); + } + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs index 71376c28f1..3202ac4b3c 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs @@ -102,14 +102,14 @@ namespace osu.Game.Beatmaps.Drawables.Cards RelativeSizeAxes = Axes.Y, Origin = Anchor.TopRight, Anchor = Anchor.TopRight, - Child = new FillFlowContainer + Child = new FillFlowContainer { AutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 14), - Children = new BeatmapCardIconButton[] + Children = new Drawable[] { new FavouriteButton(beatmapSet) { Current = favouriteState }, new DownloadButton(beatmapSet) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs index 00c0ccc3ce..47475e5b31 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs @@ -1,16 +1,71 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Online; +using osu.Game.Overlays; +using osuTK; namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { - public class DownloadButton : BeatmapCardIconButton + public class DownloadButton : CompositeDrawable { + protected readonly DownloadIcon Download; + protected readonly PlayIcon Play; + protected readonly BeatmapDownloadTracker Tracker; + + private readonly CircularProgress downloadProgress; + public DownloadButton(APIBeatmapSet beatmapSet) { - Icon.Icon = FontAwesome.Solid.FileDownload; + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + InternalChildren = new Drawable[] + { + Tracker = new BeatmapDownloadTracker(beatmapSet), + Download = new DownloadIcon(), + downloadProgress = new CircularProgress + { + Size = new Vector2(16), + InnerRadius = 0.1f, + }, + Play = new PlayIcon() + }; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + downloadProgress.Colour = colourProvider.Highlight1; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + ((IBindable)downloadProgress.Current).BindTo(Tracker.Progress); + } + + protected class DownloadIcon : BeatmapCardIconButton + { + public DownloadIcon() + { + Icon.Icon = FontAwesome.Solid.Download; + } + } + + protected class PlayIcon : BeatmapCardIconButton + { + public PlayIcon() + { + Icon.Icon = FontAwesome.Regular.PlayCircle; + } } // TODO: implement behaviour