mirror of
https://github.com/ppy/osu.git
synced 2025-01-14 19:22:56 +08:00
Merge pull request #4092 from peppy/download-tracking-component
Add a download tracking component
This commit is contained in:
commit
ccc6968697
@ -1,112 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// A component to allow downloading of a beatmap set. Automatically handles state syncing between other instances.
|
||||
/// </summary>
|
||||
public class BeatmapSetDownloader : Component
|
||||
{
|
||||
private readonly BeatmapSetInfo set;
|
||||
private readonly bool noVideo;
|
||||
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded.
|
||||
/// </summary>
|
||||
public readonly Bindable<DownloadStatus> DownloadState = new Bindable<DownloadStatus>();
|
||||
|
||||
public BeatmapSetDownloader(BeatmapSetInfo set, bool noVideo = false)
|
||||
{
|
||||
this.set = set;
|
||||
this.noVideo = noVideo;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapManager beatmaps)
|
||||
{
|
||||
this.beatmaps = beatmaps;
|
||||
|
||||
beatmaps.ItemAdded += setAdded;
|
||||
beatmaps.ItemRemoved += setRemoved;
|
||||
beatmaps.BeatmapDownloadBegan += downloadBegan;
|
||||
beatmaps.BeatmapDownloadFailed += downloadFailed;
|
||||
|
||||
// initial value
|
||||
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)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (beatmaps != null)
|
||||
{
|
||||
beatmaps.ItemAdded -= setAdded;
|
||||
beatmaps.ItemRemoved -= setRemoved;
|
||||
beatmaps.BeatmapDownloadBegan -= downloadBegan;
|
||||
beatmaps.BeatmapDownloadFailed -= downloadFailed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begin downloading the associated beatmap set.
|
||||
/// </summary>
|
||||
/// <returns>True if downloading began. False if an existing download is active or completed.</returns>
|
||||
public void Download()
|
||||
{
|
||||
if (DownloadState.Value > DownloadStatus.NotDownloaded)
|
||||
return;
|
||||
|
||||
if (beatmaps.Download(set, noVideo))
|
||||
{
|
||||
// Only change state if download can happen
|
||||
DownloadState.Value = DownloadStatus.Downloading;
|
||||
}
|
||||
}
|
||||
|
||||
private void setAdded(BeatmapSetInfo s, bool existing, bool silent) => Schedule(() =>
|
||||
{
|
||||
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
|
||||
DownloadState.Value = DownloadStatus.Downloaded;
|
||||
});
|
||||
|
||||
private void setRemoved(BeatmapSetInfo s) => Schedule(() =>
|
||||
{
|
||||
if (s.OnlineBeatmapSetID == set.OnlineBeatmapSetID)
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
@ -355,11 +355,7 @@ namespace osu.Game.Online.API
|
||||
State = APIState.Offline;
|
||||
}
|
||||
|
||||
private static User createGuestUser() => new User
|
||||
{
|
||||
Username = @"Guest",
|
||||
Id = 1,
|
||||
};
|
||||
private static User createGuestUser() => new GuestUser();
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
@ -370,6 +366,15 @@ namespace osu.Game.Online.API
|
||||
}
|
||||
}
|
||||
|
||||
internal class GuestUser : User
|
||||
{
|
||||
public GuestUser()
|
||||
{
|
||||
Username = @"Guest";
|
||||
Id = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public enum APIState
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Online.API
|
||||
return request;
|
||||
}
|
||||
|
||||
private void request_Progress(long current, long total) => API.Schedule(() => Progress?.Invoke(current, total));
|
||||
private void request_Progress(long current, long total) => API.Schedule(() => Progressed?.Invoke(current, total));
|
||||
|
||||
protected APIDownloadRequest()
|
||||
{
|
||||
@ -29,7 +29,7 @@ namespace osu.Game.Online.API
|
||||
Success?.Invoke(filename);
|
||||
}
|
||||
|
||||
public event APIProgressHandler Progress;
|
||||
public event APIProgressHandler Progressed;
|
||||
|
||||
public new event APISuccessHandler<string> Success;
|
||||
}
|
||||
|
@ -10,7 +10,9 @@ namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public readonly BeatmapSetInfo BeatmapSet;
|
||||
|
||||
public Action<float> DownloadProgressed;
|
||||
public float Progress;
|
||||
|
||||
public event Action<float> DownloadProgressed;
|
||||
|
||||
private readonly bool noVideo;
|
||||
|
||||
@ -19,7 +21,7 @@ namespace osu.Game.Online.API.Requests
|
||||
this.noVideo = noVideo;
|
||||
BeatmapSet = set;
|
||||
|
||||
Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total);
|
||||
Progressed += (current, total) => DownloadProgressed?.Invoke(Progress = (float)current / total);
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}";
|
||||
|
@ -7,42 +7,138 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
public class DownloadButton : HeaderButton, IHasTooltip
|
||||
public class DownloadButton : DownloadTrackingComposite, IHasTooltip
|
||||
{
|
||||
public string TooltipText => "Download this beatmap";
|
||||
private readonly bool noVideo;
|
||||
|
||||
public string TooltipText => button.Enabled ? "Download this beatmap" : "Login to download";
|
||||
|
||||
private readonly IBindable<User> localUser = new Bindable<User>();
|
||||
|
||||
public DownloadButton(BeatmapSetInfo set, bool noVideo = false)
|
||||
{
|
||||
Width = 120;
|
||||
private ShakeContainer shakeContainer;
|
||||
private HeaderButton button;
|
||||
|
||||
BeatmapSetDownloader downloader;
|
||||
Add(new Container
|
||||
public DownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
|
||||
: base(beatmapSet)
|
||||
{
|
||||
this.noVideo = noVideo;
|
||||
|
||||
Width = 120;
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api, BeatmapManager beatmaps)
|
||||
{
|
||||
FillFlowContainer textSprites;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
Depth = -1,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Horizontal = 10 },
|
||||
Children = new Drawable[]
|
||||
shakeContainer = new ShakeContainer
|
||||
{
|
||||
downloader = new BeatmapSetDownloader(set, noVideo),
|
||||
new FillFlowContainer
|
||||
Depth = -1,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
CornerRadius = 5,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new[]
|
||||
button = new HeaderButton { RelativeSizeAxes = Axes.Both },
|
||||
new Container
|
||||
{
|
||||
// cannot nest inside here due to the structure of button (putting things in its own content).
|
||||
// requires framework fix.
|
||||
Padding = new MarginPadding { Horizontal = 10 },
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
textSprites = new FillFlowContainer
|
||||
{
|
||||
Depth = -1,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
AutoSizeDuration = 500,
|
||||
AutoSizeEasing = Easing.OutQuint,
|
||||
Direction = FillDirection.Vertical,
|
||||
},
|
||||
new SpriteIcon
|
||||
{
|
||||
Depth = -1,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Icon = FontAwesome.fa_download,
|
||||
Size = new Vector2(16),
|
||||
Margin = new MarginPadding { Right = 5 },
|
||||
},
|
||||
}
|
||||
},
|
||||
new DownloadProgressBar(BeatmapSet)
|
||||
{
|
||||
Depth = -2,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
button.Action = () =>
|
||||
{
|
||||
if (State.Value != DownloadState.NotDownloaded)
|
||||
{
|
||||
shakeContainer.Shake();
|
||||
return;
|
||||
}
|
||||
|
||||
beatmaps.Download(BeatmapSet, noVideo);
|
||||
};
|
||||
|
||||
localUser.BindTo(api.LocalUser);
|
||||
localUser.BindValueChanged(userChanged, true);
|
||||
button.Enabled.BindValueChanged(enabledChanged, true);
|
||||
|
||||
State.BindValueChanged(state =>
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case DownloadState.Downloading:
|
||||
textSprites.Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Downloading...",
|
||||
TextSize = 13,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
};
|
||||
break;
|
||||
case DownloadState.Downloaded:
|
||||
textSprites.Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Importing...",
|
||||
TextSize = 13,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
};
|
||||
break;
|
||||
case DownloadState.LocallyAvailable:
|
||||
this.FadeOut(200);
|
||||
break;
|
||||
case DownloadState.NotDownloaded:
|
||||
textSprites.Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
@ -52,57 +148,18 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = set.OnlineInfo.HasVideo && noVideo ? "without Video" : string.Empty,
|
||||
Text = BeatmapSet.Value.OnlineInfo.HasVideo && noVideo ? "without Video" : string.Empty,
|
||||
TextSize = 11,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
},
|
||||
},
|
||||
new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Icon = FontAwesome.fa_download,
|
||||
Size = new Vector2(16),
|
||||
Margin = new MarginPadding { Right = 5 },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Action = () =>
|
||||
{
|
||||
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.DownloadState.ValueChanged += state =>
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case BeatmapSetDownloader.DownloadStatus.Downloaded:
|
||||
this.FadeOut(200);
|
||||
break;
|
||||
case BeatmapSetDownloader.DownloadStatus.NotDownloaded:
|
||||
};
|
||||
this.FadeIn(200);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}, true);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api)
|
||||
{
|
||||
localUser.BindTo(api.LocalUser);
|
||||
Enabled.BindValueChanged(enabledChanged, true);
|
||||
}
|
||||
private void userChanged(User user) => button.Enabled.Value = !(user is GuestUser);
|
||||
|
||||
private void enabledChanged(bool enabled) => this.FadeColour(enabled ? Color4.White : Color4.Gray, 200, Easing.OutQuint);
|
||||
}
|
||||
|
@ -13,12 +13,14 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.BeatmapSet.Buttons;
|
||||
using osu.Game.Overlays.Direct;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using DownloadButton = osu.Game.Overlays.BeatmapSet.Buttons.DownloadButton;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class Header : Container
|
||||
public class Header : DownloadTrackingComposite
|
||||
{
|
||||
private const float transition_duration = 200;
|
||||
private const float tabs_height = 50;
|
||||
@ -28,76 +30,23 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private readonly Box tabsBg;
|
||||
private readonly UpdateableBeatmapSetCover cover;
|
||||
private readonly OsuSpriteText title, artist;
|
||||
private readonly Container noVideoButtons;
|
||||
private readonly FillFlowContainer videoButtons;
|
||||
private readonly AuthorInfo author;
|
||||
private readonly Container downloadButtonsContainer;
|
||||
private readonly FillFlowContainer downloadButtonsContainer;
|
||||
private readonly BeatmapSetOnlineStatusPill onlineStatusPill;
|
||||
public Details Details;
|
||||
|
||||
public readonly BeatmapPicker Picker;
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
private readonly FavouriteButton favouriteButton;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
{
|
||||
get { return beatmapSet; }
|
||||
set
|
||||
{
|
||||
if (value == beatmapSet) return;
|
||||
beatmapSet = value;
|
||||
|
||||
Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = BeatmapSet;
|
||||
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDisplay()
|
||||
{
|
||||
title.Text = BeatmapSet?.Metadata.Title ?? string.Empty;
|
||||
artist.Text = BeatmapSet?.Metadata.Artist ?? string.Empty;
|
||||
onlineStatusPill.Status = BeatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None;
|
||||
cover.BeatmapSet = BeatmapSet;
|
||||
|
||||
if (BeatmapSet != null)
|
||||
{
|
||||
downloadButtonsContainer.FadeIn(transition_duration);
|
||||
favouriteButton.FadeIn(transition_duration);
|
||||
|
||||
if (BeatmapSet.OnlineInfo.HasVideo)
|
||||
{
|
||||
videoButtons.Children = new[]
|
||||
{
|
||||
new DownloadButton(BeatmapSet),
|
||||
new DownloadButton(BeatmapSet, true),
|
||||
};
|
||||
|
||||
videoButtons.FadeIn(transition_duration);
|
||||
noVideoButtons.FadeOut(transition_duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
noVideoButtons.Child = new DownloadButton(BeatmapSet);
|
||||
|
||||
noVideoButtons.FadeIn(transition_duration);
|
||||
videoButtons.FadeOut(transition_duration);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
downloadButtonsContainer.FadeOut(transition_duration);
|
||||
favouriteButton.FadeOut(transition_duration);
|
||||
}
|
||||
}
|
||||
|
||||
public Header()
|
||||
{
|
||||
ExternalLinkButton externalLink;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 400;
|
||||
Masking = true;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
@ -105,7 +54,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
Children = new Drawable[]
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
@ -196,24 +146,11 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
Children = new Drawable[]
|
||||
{
|
||||
favouriteButton = new FavouriteButton(),
|
||||
downloadButtonsContainer = new Container
|
||||
downloadButtonsContainer = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
noVideoButtons = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0f,
|
||||
},
|
||||
videoButtons = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(buttons_spacing),
|
||||
Alpha = 0f,
|
||||
},
|
||||
},
|
||||
Spacing = new Vector2(buttons_spacing),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -245,14 +182,64 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
};
|
||||
|
||||
Picker.Beatmap.ValueChanged += b => Details.Beatmap = b;
|
||||
Picker.Beatmap.ValueChanged += b => externalLink.Link = $@"https://osu.ppy.sh/beatmapsets/{BeatmapSet?.OnlineBeatmapSetID}#{b?.Ruleset.ShortName}/{b?.OnlineBeatmapID}";
|
||||
Picker.Beatmap.ValueChanged += b => externalLink.Link = $@"https://osu.ppy.sh/beatmapsets/{BeatmapSet.Value?.OnlineBeatmapSetID}#{b?.Ruleset.ShortName}/{b?.OnlineBeatmapID}";
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
tabsBg.Colour = colours.Gray3;
|
||||
updateDisplay();
|
||||
|
||||
State.BindValueChanged(_ => updateDownloadButtons());
|
||||
|
||||
BeatmapSet.BindValueChanged(beatmapSet =>
|
||||
{
|
||||
Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = beatmapSet;
|
||||
|
||||
title.Text = beatmapSet?.Metadata.Title ?? string.Empty;
|
||||
artist.Text = beatmapSet?.Metadata.Artist ?? string.Empty;
|
||||
onlineStatusPill.Status = beatmapSet?.OnlineInfo.Status ?? BeatmapSetOnlineStatus.None;
|
||||
cover.BeatmapSet = beatmapSet;
|
||||
|
||||
if (beatmapSet != null)
|
||||
{
|
||||
downloadButtonsContainer.FadeIn(transition_duration);
|
||||
favouriteButton.FadeIn(transition_duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
downloadButtonsContainer.FadeOut(transition_duration);
|
||||
favouriteButton.FadeOut(transition_duration);
|
||||
}
|
||||
|
||||
updateDownloadButtons();
|
||||
}, true);
|
||||
}
|
||||
|
||||
private void updateDownloadButtons()
|
||||
{
|
||||
if (BeatmapSet.Value == null) return;
|
||||
switch (State.Value)
|
||||
{
|
||||
case DownloadState.LocallyAvailable:
|
||||
// temporary for UX until new design is implemented.
|
||||
downloadButtonsContainer.Child = new osu.Game.Overlays.Direct.DownloadButton(BeatmapSet)
|
||||
{
|
||||
Width = 50,
|
||||
RelativeSizeAxes = Axes.Y
|
||||
};
|
||||
break;
|
||||
case DownloadState.Downloading:
|
||||
case DownloadState.Downloaded:
|
||||
// temporary to avoid showing two buttons for maps with novideo. will be fixed in new beatmap overlay design.
|
||||
downloadButtonsContainer.Child = new DownloadButton(BeatmapSet);
|
||||
break;
|
||||
default:
|
||||
downloadButtonsContainer.Child = new DownloadButton(BeatmapSet);
|
||||
if (BeatmapSet.Value.OnlineInfo.HasVideo)
|
||||
downloadButtonsContainer.Add(new DownloadButton(BeatmapSet, true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ namespace osu.Game.Overlays
|
||||
if (value == beatmapSet)
|
||||
return;
|
||||
|
||||
header.BeatmapSet = info.BeatmapSet = beatmapSet = value;
|
||||
header.BeatmapSet.Value = info.BeatmapSet = beatmapSet = value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ namespace osu.Game.Overlays
|
||||
req.Success += res =>
|
||||
{
|
||||
BeatmapSet = res.ToBeatmapSet(rulesets);
|
||||
header.Picker.Beatmap.Value = header.BeatmapSet.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId);
|
||||
header.Picker.Beatmap.Value = header.BeatmapSet.Value.Beatmaps.First(b => b.OnlineBeatmapID == beatmapId);
|
||||
};
|
||||
api.Queue(req);
|
||||
Show();
|
||||
|
@ -16,8 +16,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -31,8 +29,6 @@ namespace osu.Game.Overlays.Direct
|
||||
|
||||
private Container content;
|
||||
|
||||
private ProgressBar progressBar;
|
||||
private BeatmapManager beatmaps;
|
||||
private BeatmapSetOverlay beatmapSetOverlay;
|
||||
|
||||
public PreviewTrack Preview => PlayButton.Preview;
|
||||
@ -65,14 +61,10 @@ namespace osu.Game.Overlays.Direct
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
};
|
||||
|
||||
private OsuColour colours;
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay)
|
||||
{
|
||||
this.beatmaps = beatmaps;
|
||||
this.beatmapSetOverlay = beatmapSetOverlay;
|
||||
this.colours = colours;
|
||||
|
||||
AddInternal(content = new Container
|
||||
{
|
||||
@ -82,33 +74,14 @@ namespace osu.Game.Overlays.Direct
|
||||
Children = new[]
|
||||
{
|
||||
CreateBackground(),
|
||||
progressBar = new ProgressBar
|
||||
new DownloadProgressBar(SetInfo)
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Height = 0,
|
||||
Alpha = 0,
|
||||
BackgroundColour = Color4.Black.Opacity(0.7f),
|
||||
FillColour = colours.Blue,
|
||||
Depth = -1,
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var downloadRequest = beatmaps.GetExistingDownload(SetInfo);
|
||||
|
||||
if (downloadRequest != null)
|
||||
attachDownload(downloadRequest);
|
||||
|
||||
beatmaps.BeatmapDownloadBegan += attachDownload;
|
||||
beatmaps.ItemAdded += setAdded;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
beatmaps.BeatmapDownloadBegan -= attachDownload;
|
||||
beatmaps.ItemAdded -= setAdded;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@ -149,37 +122,6 @@ namespace osu.Game.Overlays.Direct
|
||||
|
||||
protected void ShowInformation() => beatmapSetOverlay?.ShowBeatmapSet(SetInfo);
|
||||
|
||||
private void attachDownload(DownloadBeatmapSetRequest request)
|
||||
{
|
||||
if (request.BeatmapSet.OnlineBeatmapSetID != SetInfo.OnlineBeatmapSetID)
|
||||
return;
|
||||
|
||||
progressBar.FadeIn(400, Easing.OutQuint);
|
||||
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
|
||||
|
||||
progressBar.Current.Value = 0;
|
||||
|
||||
request.Failure += e =>
|
||||
{
|
||||
progressBar.Current.Value = 0;
|
||||
progressBar.FadeOut(500);
|
||||
};
|
||||
|
||||
request.DownloadProgressed += progress => Schedule(() => progressBar.Current.Value = progress);
|
||||
|
||||
request.Success += data =>
|
||||
{
|
||||
progressBar.Current.Value = 1;
|
||||
progressBar.FillColour = colours.Yellow;
|
||||
};
|
||||
}
|
||||
|
||||
private void setAdded(BeatmapSetInfo s, bool existing, bool silent) => Schedule(() =>
|
||||
{
|
||||
if (s.OnlineBeatmapSetID == SetInfo.OnlineBeatmapSetID)
|
||||
progressBar.FadeOut(500);
|
||||
});
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
@ -5,103 +5,114 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public class DownloadButton : OsuAnimatedButton
|
||||
public class DownloadButton : DownloadTrackingComposite
|
||||
{
|
||||
private readonly BeatmapSetInfo beatmapSet;
|
||||
private readonly bool noVideo;
|
||||
private readonly SpriteIcon icon;
|
||||
private readonly SpriteIcon checkmark;
|
||||
private readonly BeatmapSetDownloader downloader;
|
||||
private readonly Box background;
|
||||
|
||||
private OsuColour colours;
|
||||
|
||||
public DownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
|
||||
{
|
||||
this.beatmapSet = beatmapSet;
|
||||
private readonly ShakeContainer shakeContainer;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
private readonly OsuAnimatedButton button;
|
||||
|
||||
public DownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
|
||||
: base(beatmapSet)
|
||||
{
|
||||
this.noVideo = noVideo;
|
||||
|
||||
InternalChild = shakeContainer = new ShakeContainer
|
||||
{
|
||||
downloader = new BeatmapSetDownloader(beatmapSet, noVideo),
|
||||
background = new Box
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = button = new OsuAnimatedButton
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = float.MaxValue
|
||||
},
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
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,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = float.MaxValue
|
||||
},
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
downloader.DownloadState.BindValueChanged(updateState, true);
|
||||
|
||||
State.BindValueChanged(updateState, true);
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(OsuColour colours, OsuGame game)
|
||||
private void load(OsuColour colours, OsuGame game, BeatmapManager beatmaps)
|
||||
{
|
||||
this.colours = colours;
|
||||
|
||||
Action = () =>
|
||||
button.Action = () =>
|
||||
{
|
||||
switch (downloader.DownloadState.Value)
|
||||
switch (State.Value)
|
||||
{
|
||||
case BeatmapSetDownloader.DownloadStatus.Downloading:
|
||||
// todo: replace with ShakeContainer after https://github.com/ppy/osu/pull/2909 is merged.
|
||||
Content.MoveToX(-5, 50, Easing.OutSine).Then()
|
||||
.MoveToX(5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(-5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(0, 50, Easing.InSine);
|
||||
case DownloadState.Downloading:
|
||||
case DownloadState.Downloaded:
|
||||
shakeContainer.Shake();
|
||||
break;
|
||||
case BeatmapSetDownloader.DownloadStatus.Downloaded:
|
||||
game.PresentBeatmap(beatmapSet);
|
||||
case DownloadState.LocallyAvailable:
|
||||
game.PresentBeatmap(BeatmapSet);
|
||||
break;
|
||||
default:
|
||||
downloader.Download();
|
||||
beatmaps.Download(BeatmapSet, noVideo);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateState(BeatmapSetDownloader.DownloadStatus state)
|
||||
private void updateState(DownloadState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case BeatmapSetDownloader.DownloadStatus.NotDownloaded:
|
||||
case DownloadState.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:
|
||||
case DownloadState.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:
|
||||
case DownloadState.Downloaded:
|
||||
background.FadeColour(colours.Yellow, 500, Easing.InOutExpo);
|
||||
break;
|
||||
case DownloadState.LocallyAvailable:
|
||||
background.FadeColour(colours.Green, 500, Easing.InOutExpo);
|
||||
icon.MoveToX(-8, 500, Easing.InOutExpo);
|
||||
checkmark.ScaleTo(new Vector2(13), 500, Easing.InOutExpo);
|
||||
|
64
osu.Game/Overlays/Direct/DownloadProgressBar.cs
Normal file
64
osu.Game/Overlays/Direct/DownloadProgressBar.cs
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public class DownloadProgressBar : DownloadTrackingComposite
|
||||
{
|
||||
private readonly ProgressBar progressBar;
|
||||
|
||||
public DownloadProgressBar(BeatmapSetInfo beatmapSet)
|
||||
: base(beatmapSet)
|
||||
{
|
||||
AddInternal(progressBar = new ProgressBar
|
||||
{
|
||||
Height = 0,
|
||||
Alpha = 0,
|
||||
});
|
||||
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
progressBar.FillColour = colours.Blue;
|
||||
progressBar.BackgroundColour = Color4.Black.Opacity(0.7f);
|
||||
progressBar.Current = Progress;
|
||||
|
||||
State.BindValueChanged(state =>
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case DownloadState.NotDownloaded:
|
||||
progressBar.Current.Value = 0;
|
||||
progressBar.FadeOut(500);
|
||||
break;
|
||||
case DownloadState.Downloading:
|
||||
progressBar.FadeIn(400, Easing.OutQuint);
|
||||
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
|
||||
break;
|
||||
case DownloadState.Downloaded:
|
||||
progressBar.FadeIn(400, Easing.OutQuint);
|
||||
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
|
||||
|
||||
progressBar.Current.Value = 1;
|
||||
progressBar.FillColour = colours.Yellow;
|
||||
break;
|
||||
case DownloadState.LocallyAvailable:
|
||||
progressBar.FadeOut(500);
|
||||
break;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
13
osu.Game/Overlays/Direct/DownloadState.cs
Normal file
13
osu.Game/Overlays/Direct/DownloadState.cs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public enum DownloadState
|
||||
{
|
||||
NotDownloaded,
|
||||
Downloading,
|
||||
Downloaded,
|
||||
LocallyAvailable
|
||||
}
|
||||
}
|
131
osu.Game/Overlays/Direct/DownloadTrackingComposite.cs
Normal file
131
osu.Game/Overlays/Direct/DownloadTrackingComposite.cs
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public abstract class DownloadTrackingComposite : CompositeDrawable
|
||||
{
|
||||
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded.
|
||||
/// </summary>
|
||||
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
|
||||
|
||||
protected readonly Bindable<double> Progress = new Bindable<double>();
|
||||
|
||||
protected DownloadTrackingComposite(BeatmapSetInfo beatmapSet = null)
|
||||
{
|
||||
BeatmapSet.Value = beatmapSet;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(BeatmapManager beatmaps)
|
||||
{
|
||||
this.beatmaps = beatmaps;
|
||||
|
||||
BeatmapSet.BindValueChanged(set =>
|
||||
{
|
||||
if (set == null)
|
||||
attachDownload(null);
|
||||
else if (beatmaps.QueryBeatmapSets(s => s.OnlineBeatmapSetID == set.OnlineBeatmapSetID).Any())
|
||||
State.Value = DownloadState.LocallyAvailable;
|
||||
else
|
||||
attachDownload(beatmaps.GetExistingDownload(set));
|
||||
}, true);
|
||||
|
||||
beatmaps.BeatmapDownloadBegan += download =>
|
||||
{
|
||||
if (download.BeatmapSet.OnlineBeatmapSetID == BeatmapSet.Value?.OnlineBeatmapSetID)
|
||||
attachDownload(download);
|
||||
};
|
||||
|
||||
beatmaps.ItemAdded += setAdded;
|
||||
}
|
||||
|
||||
#region Disposal
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
beatmaps.BeatmapDownloadBegan -= attachDownload;
|
||||
beatmaps.ItemAdded -= setAdded;
|
||||
|
||||
State.UnbindAll();
|
||||
|
||||
attachDownload(null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private DownloadBeatmapSetRequest attachedRequest;
|
||||
|
||||
private void attachDownload(DownloadBeatmapSetRequest request)
|
||||
{
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
attachedRequest.Failure -= onRequestFailure;
|
||||
attachedRequest.DownloadProgressed -= onRequestProgress;
|
||||
attachedRequest.Success -= onRequestSuccess;
|
||||
}
|
||||
|
||||
attachedRequest = request;
|
||||
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
if (attachedRequest.Progress == 1)
|
||||
{
|
||||
State.Value = DownloadState.Downloaded;
|
||||
Progress.Value = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
State.Value = DownloadState.Downloading;
|
||||
Progress.Value = attachedRequest.Progress;
|
||||
|
||||
attachedRequest.Failure += onRequestFailure;
|
||||
attachedRequest.DownloadProgressed += onRequestProgress;
|
||||
attachedRequest.Success += onRequestSuccess;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
State.Value = DownloadState.NotDownloaded;
|
||||
}
|
||||
}
|
||||
|
||||
private void onRequestSuccess(string data)
|
||||
{
|
||||
Schedule(() => State.Value = DownloadState.Downloaded);
|
||||
}
|
||||
|
||||
private void onRequestProgress(float progress)
|
||||
{
|
||||
Schedule(() => Progress.Value = progress);
|
||||
}
|
||||
|
||||
private void onRequestFailure(Exception e)
|
||||
{
|
||||
Schedule(() => attachDownload(null));
|
||||
}
|
||||
|
||||
private void setAdded(BeatmapSetInfo s, bool existing, bool silent)
|
||||
{
|
||||
if (s.OnlineBeatmapSetID != BeatmapSet.Value?.OnlineBeatmapSetID)
|
||||
return;
|
||||
|
||||
Schedule(() => State.Value = DownloadState.LocallyAvailable);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user