diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e488dacf80..f9bbe7b972 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -45,6 +45,11 @@ namespace osu.Game.Beatmaps /// public event Action BeatmapDownloadBegan; + /// + /// Fired when a beatmap download is interrupted, due to user cancellation or other failures. + /// + public event Action BeatmapDownloadFailed; + /// /// A default representation of a WorkingBeatmap to use when no beatmap is available. /// @@ -175,6 +180,8 @@ namespace osu.Game.Beatmaps request.Failure += error => { + BeatmapDownloadFailed?.Invoke(request); + if (error is OperationCanceledException) return; downloadNotification.State = ProgressNotificationState.Cancelled; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs index 6acb58e165..6f4d4c0d6f 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs @@ -5,6 +5,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Game.Online.API.Requests; namespace osu.Game.Beatmaps.Drawables { @@ -19,9 +20,9 @@ namespace osu.Game.Beatmaps.Drawables private BeatmapManager beatmaps; /// - /// Whether the associated beatmap set has been downloading (by this instance or any other instance). + /// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded. /// - public readonly BindableBool Downloaded = new BindableBool(); + public readonly Bindable DownloadState = new Bindable(); public BeatmapSetDownloader(BeatmapSetInfo set, bool noVideo = false) { @@ -36,10 +37,16 @@ namespace osu.Game.Beatmaps.Drawables beatmaps.ItemAdded += setAdded; beatmaps.ItemRemoved += setRemoved; + beatmaps.BeatmapDownloadBegan += downloadBegan; + beatmaps.BeatmapDownloadFailed += downloadFailed; // initial value - if (set.OnlineBeatmapSetID != null) - Downloaded.Value = beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID && !s.DeletePending).Any(); + if (set.OnlineBeatmapSetID != null && beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID && !s.DeletePending).Any()) + DownloadState.Value = DownloadStatus.Downloaded; + else if (beatmaps.GetExistingDownload(set) != null) + DownloadState.Value = DownloadStatus.Downloading; + else + DownloadState.Value = DownloadStatus.NotDownloaded; } protected override void Dispose(bool isDisposing) @@ -50,6 +57,8 @@ namespace osu.Game.Beatmaps.Drawables { beatmaps.ItemAdded -= setAdded; beatmaps.ItemRemoved -= setRemoved; + beatmaps.BeatmapDownloadBegan -= downloadBegan; + beatmaps.BeatmapDownloadFailed -= downloadFailed; } } @@ -57,28 +66,45 @@ namespace osu.Game.Beatmaps.Drawables /// Begin downloading the associated beatmap set. /// /// True if downloading began. False if an existing download is active or completed. - public bool Download() + public void Download() { - if (Downloaded.Value) - return false; - - if (beatmaps.GetExistingDownload(set) != null) - return false; + if (DownloadState.Value > DownloadStatus.NotDownloaded) + return; beatmaps.Download(set, noVideo); - return true; + + DownloadState.Value = DownloadStatus.Downloading; } private void setAdded(BeatmapSetInfo s) { if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID) - Downloaded.Value = true; + DownloadState.Value = DownloadStatus.Downloaded; } private void setRemoved(BeatmapSetInfo s) { if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID) - Downloaded.Value = false; + DownloadState.Value = DownloadStatus.NotDownloaded; + } + + private void downloadBegan(DownloadBeatmapSetRequest d) + { + if (d.BeatmapSet.OnlineBeatmapSetID == set.OnlineBeatmapSetID) + DownloadState.Value = DownloadStatus.Downloading; + } + + private void downloadFailed(DownloadBeatmapSetRequest d) + { + if (d.BeatmapSet.OnlineBeatmapSetID == set.OnlineBeatmapSetID) + DownloadState.Value = DownloadStatus.NotDownloaded; + } + + public enum DownloadStatus + { + NotDownloaded, + Downloading, + Downloaded, } } } diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs index 4fce6a49fb..7a227f4bfa 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/DownloadButton.cs @@ -61,20 +61,23 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons Action = () => { - if (!downloader.Download()) + if (downloader.DownloadState.Value == BeatmapSetDownloader.DownloadStatus.Downloading) { Content.MoveToX(-5, 50, Easing.OutSine).Then() .MoveToX(5, 100, Easing.InOutSine).Then() .MoveToX(-5, 100, Easing.InOutSine).Then() .MoveToX(0, 50, Easing.InSine); + return; } + + downloader.Download(); }; - downloader.Downloaded.ValueChanged += d => + downloader.DownloadState.ValueChanged += d => { - if (d) + if (d == BeatmapSetDownloader.DownloadStatus.Downloaded) this.FadeOut(200); - else + else if (d == BeatmapSetDownloader.DownloadStatus.NotDownloaded) this.FadeIn(200); }; } diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index e286837746..48963a91e8 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -168,11 +168,10 @@ namespace osu.Game.Overlays.Direct }, new DownloadButton(SetInfo) { - Size = new Vector2(30), + Size = new Vector2(50, 30), Margin = new MarginPadding(horizontal_padding), - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Colour = colours.Gray5, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, }, }, }, diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index e63c290ce5..76da4b61b0 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -99,6 +99,7 @@ namespace osu.Game.Overlays.Direct attachDownload(downloadRequest); beatmaps.BeatmapDownloadBegan += attachDownload; + beatmaps.ItemAdded += setAdded; } public override bool DisposeOnDeathRemoval => true; @@ -107,6 +108,7 @@ namespace osu.Game.Overlays.Direct { base.Dispose(isDisposing); beatmaps.BeatmapDownloadBegan -= attachDownload; + beatmaps.ItemAdded -= setAdded; } protected override void Update() @@ -171,6 +173,12 @@ namespace osu.Game.Overlays.Direct }; } + private void setAdded(BeatmapSetInfo s) + { + if (s.OnlineBeatmapSetID == SetInfo.OnlineBeatmapSetID) + progressBar.FadeOut(500); + } + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Overlays/Direct/DownloadButton.cs b/osu.Game/Overlays/Direct/DownloadButton.cs index 1ffa8dbd35..68380b951c 100644 --- a/osu.Game/Overlays/Direct/DownloadButton.cs +++ b/osu.Game/Overlays/Direct/DownloadButton.cs @@ -1,76 +1,146 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Overlays.Direct { public class DownloadButton : OsuClickableContainer { private readonly SpriteIcon icon; + private readonly SpriteIcon checkmark; + private readonly BeatmapSetDownloader downloader; + private readonly Box background; + + private OsuColour colours; public DownloadButton(BeatmapSetInfo set, bool noVideo = false) { - BeatmapSetDownloader downloader; Children = new Drawable[] { downloader = new BeatmapSetDownloader(set, noVideo), + new Container + { + RelativeSizeAxes = Axes.Both, + CornerRadius = 17, + Masking = true, + Child = background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + }, icon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(30), - Icon = FontAwesome.fa_osu_chevron_down_o, + Size = new Vector2(13), + Icon = FontAwesome.fa_download, }, + checkmark = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + X = 8, + Size = Vector2.Zero, + Icon = FontAwesome.fa_check, + } }; Action = () => { - if (!downloader.Download()) + if (downloader.DownloadState.Value == BeatmapSetDownloader.DownloadStatus.Downloading) { Content.MoveToX(-5, 50, Easing.OutSine).Then() .MoveToX(5, 100, Easing.InOutSine).Then() .MoveToX(-5, 100, Easing.InOutSine).Then() .MoveToX(0, 50, Easing.InSine); } + else if (downloader.DownloadState.Value == BeatmapSetDownloader.DownloadStatus.Downloaded) + { + // TODO: Jump to song select with this set when the capability is implemented + } + else + { + downloader.Download(); + } }; - downloader.Downloaded.ValueChanged += d => - { - if (d) - this.FadeOut(200); - else - this.FadeIn(200); - }; + downloader.DownloadState.ValueChanged += _ => updateState(); + + Colour = Color4.White; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateState(); + } + + [BackgroundDependencyLoader(permitNulls:true)] + private void load(OsuColour colours) + { + this.colours = colours; } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - icon.ScaleTo(0.9f, 1000, Easing.Out); + Content.ScaleTo(0.9f, 1000, Easing.Out); return base.OnMouseDown(state, args); } protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - icon.ScaleTo(1f, 500, Easing.OutElastic); + Content.ScaleTo(1f, 500, Easing.OutElastic); return base.OnMouseUp(state, args); } protected override bool OnHover(InputState state) { - icon.ScaleTo(1.1f, 500, Easing.OutElastic); + Content.ScaleTo(1.1f, 500, Easing.OutElastic); return base.OnHover(state); } protected override void OnHoverLost(InputState state) { - icon.ScaleTo(1f, 500, Easing.OutElastic); + Content.ScaleTo(1f, 500, Easing.OutElastic); + } + + private void updateState() + { + if (!IsLoaded) + return; + + switch (downloader.DownloadState.Value) + { + case BeatmapSetDownloader.DownloadStatus.NotDownloaded: + background.FadeColour(colours.Gray4, 500, Easing.InOutExpo); + icon.MoveToX(0, 500, Easing.InOutExpo); + checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo); + break; + + case BeatmapSetDownloader.DownloadStatus.Downloading: + background.FadeColour(colours.Blue, 500, Easing.InOutExpo); + icon.MoveToX(0, 500, Easing.InOutExpo); + checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo); + break; + + case BeatmapSetDownloader.DownloadStatus.Downloaded: + background.FadeColour(colours.Green, 500, Easing.InOutExpo); + icon.MoveToX(-8, 500, Easing.InOutExpo); + checkmark.ScaleTo(new Vector2(13), 500, Easing.InOutExpo); + break; + } } } }