diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs index bb7fcc2fce..879e35057b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDirectDownloadButton.cs @@ -5,6 +5,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; @@ -144,7 +145,7 @@ namespace osu.Game.Tests.Visual.Online { public new bool DownloadEnabled => base.DownloadEnabled; - public DownloadState DownloadState => State.Value; + public DownloadState DownloadState => this.ChildrenOfType().First().State.Value; public TestDownloadButton(BeatmapSetInfo beatmapSet) : base(beatmapSet) diff --git a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs index a8c4334ffb..5c6472cd1b 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapListing/Panels/BeatmapPanelDownloadButton.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Containers; @@ -13,7 +14,7 @@ using osu.Game.Online; namespace osu.Game.Overlays.BeatmapListing.Panels { - public class BeatmapPanelDownloadButton : BeatmapDownloadTrackingComposite + public class BeatmapPanelDownloadButton : CompositeDrawable { protected bool DownloadEnabled => button.Enabled.Value; @@ -26,16 +27,29 @@ namespace osu.Game.Overlays.BeatmapListing.Panels private readonly DownloadButton button; private Bindable noVideoSetting; + protected readonly BeatmapDownloadTracker DownloadTracker; + + protected readonly Bindable State = new Bindable(); + + private readonly BeatmapSetInfo beatmapSet; + public BeatmapPanelDownloadButton(BeatmapSetInfo beatmapSet) - : base(beatmapSet) { - InternalChild = shakeContainer = new ShakeContainer + this.beatmapSet = beatmapSet; + InternalChildren = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Child = button = new DownloadButton + shakeContainer = new ShakeContainer { RelativeSizeAxes = Axes.Both, + Child = button = new DownloadButton + { + RelativeSizeAxes = Axes.Both, + }, }, + DownloadTracker = new BeatmapDownloadTracker(beatmapSet) + { + State = { BindTarget = State } + } }; button.Add(new DownloadProgressBar(beatmapSet) @@ -50,7 +64,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels { base.LoadComplete(); - button.State.BindTo(State); + ((IBindable)button.State).BindTo(DownloadTracker.State); FinishTransforms(true); } @@ -61,7 +75,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels button.Action = () => { - switch (State.Value) + switch (DownloadTracker.State.Value) { case DownloadState.Downloading: case DownloadState.Importing: @@ -73,16 +87,16 @@ namespace osu.Game.Overlays.BeatmapListing.Panels if (SelectedBeatmap.Value != null) findPredicate = b => b.OnlineBeatmapID == SelectedBeatmap.Value.OnlineBeatmapID; - game?.PresentBeatmap(BeatmapSet.Value, findPredicate); + game?.PresentBeatmap(beatmapSet, findPredicate); break; default: - beatmaps.Download(BeatmapSet.Value, noVideoSetting.Value); + beatmaps.Download(beatmapSet, noVideoSetting.Value); break; } }; - State.BindValueChanged(state => + DownloadTracker.State.BindValueChanged(state => { switch (state.NewValue) { @@ -92,7 +106,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels break; default: - if (BeatmapSet.Value?.OnlineInfo?.Availability.DownloadDisabled ?? false) + if (beatmapSet.OnlineInfo?.Availability.DownloadDisabled ?? false) { button.Enabled.Value = false; button.TooltipText = "this beatmap is currently not available for download."; diff --git a/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs b/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs index ca94078401..24f929f55e 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs +++ b/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; @@ -12,13 +13,22 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapListing.Panels { - public class DownloadProgressBar : BeatmapDownloadTrackingComposite + public class DownloadProgressBar : CompositeDrawable { private readonly ProgressBar progressBar; + private readonly BeatmapDownloadTracker downloadTracker; public DownloadProgressBar(BeatmapSetInfo beatmapSet) - : base(beatmapSet) { + InternalChildren = new Drawable[] + { + progressBar = new ProgressBar(false) + { + Height = 0, + Alpha = 0, + }, + downloadTracker = new BeatmapDownloadTracker(beatmapSet), + }; AddInternal(progressBar = new ProgressBar(false) { Height = 0, @@ -34,9 +44,9 @@ namespace osu.Game.Overlays.BeatmapListing.Panels { progressBar.FillColour = colours.Blue; progressBar.BackgroundColour = Color4.Black.Opacity(0.7f); - progressBar.Current = Progress; + progressBar.Current.BindTarget = downloadTracker.Progress; - State.BindValueChanged(state => + downloadTracker.State.BindValueChanged(state => { switch (state.NewValue) { diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs index 6f85846720..e0a09ed520 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs @@ -3,12 +3,14 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -21,8 +23,10 @@ using osuTK; namespace osu.Game.Overlays.BeatmapSet { - public class BeatmapSetHeaderContent : BeatmapDownloadTrackingComposite + public class BeatmapSetHeaderContent : CompositeDrawable { + public readonly Bindable BeatmapSet = new Bindable(); + private const float transition_duration = 200; private const float buttons_height = 45; private const float buttons_spacing = 5; @@ -45,6 +49,8 @@ namespace osu.Game.Overlays.BeatmapSet private readonly FillFlowContainer fadeContent; private readonly LoadingSpinner loading; + private BeatmapDownloadTracker downloadTracker; + [Resolved] private IAPIProvider api { get; set; } @@ -222,13 +228,13 @@ namespace osu.Game.Overlays.BeatmapSet { coverGradient.Colour = ColourInfo.GradientVertical(colourProvider.Background6.Opacity(0.3f), colourProvider.Background6.Opacity(0.8f)); - State.BindValueChanged(_ => updateDownloadButtons()); - BeatmapSet.BindValueChanged(setInfo => { Picker.BeatmapSet = rulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue; cover.BeatmapSet = setInfo.NewValue; + downloadTracker?.Expire(); + if (setInfo.NewValue == null) { onlineStatusPill.FadeTo(0.5f, 500, Easing.OutQuint); @@ -241,6 +247,9 @@ namespace osu.Game.Overlays.BeatmapSet } else { + downloadTracker = new BeatmapDownloadTracker(setInfo.NewValue); + downloadTracker.State.BindValueChanged(_ => updateDownloadButtons()); + fadeContent.FadeIn(500, Easing.OutQuint); loading.Hide(); @@ -266,13 +275,13 @@ namespace osu.Game.Overlays.BeatmapSet { if (BeatmapSet.Value == null) return; - if (BeatmapSet.Value.OnlineInfo.Availability.DownloadDisabled && State.Value != DownloadState.LocallyAvailable) + if (BeatmapSet.Value.OnlineInfo.Availability.DownloadDisabled && downloadTracker.State.Value != DownloadState.LocallyAvailable) { downloadButtonsContainer.Clear(); return; } - switch (State.Value) + switch (downloadTracker.State.Value) { case DownloadState.LocallyAvailable: // temporary for UX until new design is implemented. diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index e7a55079ec..88d0778ae4 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet.Buttons { - public class HeaderDownloadButton : BeatmapDownloadTrackingComposite, IHasTooltip + public class HeaderDownloadButton : CompositeDrawable, IHasTooltip { private const int text_size = 12; @@ -35,9 +35,12 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private ShakeContainer shakeContainer; private HeaderButton button; + private BeatmapDownloadTracker downloadTracker; + private readonly BeatmapSetInfo beatmapSet; + public HeaderDownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false) - : base(beatmapSet) { + this.beatmapSet = beatmapSet; this.noVideo = noVideo; Width = 120; @@ -49,13 +52,17 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { FillFlowContainer textSprites; - AddInternal(shakeContainer = new ShakeContainer + InternalChildren = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 5, - Child = button = new HeaderButton { RelativeSizeAxes = Axes.Both }, - }); + shakeContainer = new ShakeContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 5, + Child = button = new HeaderButton { RelativeSizeAxes = Axes.Both }, + }, + downloadTracker = new BeatmapDownloadTracker(beatmapSet), + }; button.AddRange(new Drawable[] { @@ -83,7 +90,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons }, } }, - new DownloadProgressBar(BeatmapSet.Value) + new DownloadProgressBar(beatmapSet) { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, @@ -92,20 +99,20 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons button.Action = () => { - if (State.Value != DownloadState.NotDownloaded) + if (downloadTracker.State.Value != DownloadState.NotDownloaded) { shakeContainer.Shake(); return; } - beatmaps.Download(BeatmapSet.Value, noVideo); + beatmaps.Download(beatmapSet, noVideo); }; localUser.BindTo(api.LocalUser); localUser.BindValueChanged(userChanged, true); button.Enabled.BindValueChanged(enabledChanged, true); - State.BindValueChanged(state => + downloadTracker.State.BindValueChanged(state => { switch (state.NewValue) { @@ -161,7 +168,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private LocalisableString getVideoSuffixText() { - if (!BeatmapSet.Value.OnlineInfo.HasVideo) + if (!beatmapSet.OnlineInfo.HasVideo) return string.Empty; return noVideo ? BeatmapsetsStrings.ShowDetailsDownloadNoVideo : BeatmapsetsStrings.ShowDetailsDownloadVideo; diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 585b024623..16dd7b498b 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -302,7 +302,7 @@ namespace osu.Game.Screens.OnlinePlay { base.LoadComplete(); - State.BindValueChanged(stateChanged, true); + DownloadTracker.State.BindValueChanged(stateChanged, true); FinishTransforms(true); } diff --git a/osu.Game/Screens/Ranking/ReplayDownloadButton.cs b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs index e644eb671a..f7325d2eb4 100644 --- a/osu.Game/Screens/Ranking/ReplayDownloadButton.cs +++ b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online; @@ -12,13 +13,17 @@ using osuTK; namespace osu.Game.Screens.Ranking { - public class ReplayDownloadButton : DownloadTrackingComposite + public class ReplayDownloadButton : CompositeDrawable { - public Bindable Score => Model; + public readonly Bindable Score = new Bindable(); + + protected readonly Bindable State = new Bindable(); private DownloadButton button; private ShakeContainer shakeContainer; + private ScoreDownloadTracker downloadTracker; + private ReplayAvailability replayAvailability { get @@ -26,7 +31,7 @@ namespace osu.Game.Screens.Ranking if (State.Value == DownloadState.LocallyAvailable) return ReplayAvailability.Local; - if (!string.IsNullOrEmpty(Model.Value?.Hash)) + if (!string.IsNullOrEmpty(Score.Value?.Hash)) return ReplayAvailability.Online; return ReplayAvailability.NotAvailable; @@ -34,8 +39,8 @@ namespace osu.Game.Screens.Ranking } public ReplayDownloadButton(ScoreInfo score) - : base(score) { + Score.Value = score; Size = new Vector2(50, 30); } @@ -56,11 +61,11 @@ namespace osu.Game.Screens.Ranking switch (State.Value) { case DownloadState.LocallyAvailable: - game?.PresentScore(Model.Value, ScorePresentType.Gameplay); + game?.PresentScore(Score.Value, ScorePresentType.Gameplay); break; case DownloadState.NotDownloaded: - scores.Download(Model.Value, false); + scores.Download(Score.Value, false); break; case DownloadState.Importing: @@ -70,17 +75,25 @@ namespace osu.Game.Screens.Ranking } }; - State.BindValueChanged(state => + Score.BindValueChanged(score => { - button.State.Value = state.NewValue; + downloadTracker?.Expire(); + if (score.NewValue != null) + { + AddInternal(downloadTracker = new ScoreDownloadTracker(score.NewValue) + { + State = { BindTarget = State } + }); + } + + button.Enabled.Value = replayAvailability != ReplayAvailability.NotAvailable; updateTooltip(); }, true); - Model.BindValueChanged(_ => + State.BindValueChanged(state => { - button.Enabled.Value = replayAvailability != ReplayAvailability.NotAvailable; - + button.State.Value = state.NewValue; updateTooltip(); }, true); }