diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNano.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNano.cs index ba2142d28f..2f46bc51d6 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNano.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNano.cs @@ -20,15 +20,25 @@ namespace osu.Game.Beatmaps.Drawables.Cards protected override Drawable IdleContent => idleBottomContent; protected override Drawable DownloadInProgressContent => downloadProgressBar; + public override float Width + { + get => base.Width; + set + { + base.Width = value; + + if (LoadState >= LoadState.Ready) + buttonContainer.Width = value; + } + } + private const float height = 60; private const float width = 300; - private const float cover_width = 80; [Cached] private readonly BeatmapCardContent content; - private BeatmapCardThumbnail thumbnail = null!; - private CollapsibleButtonContainer buttonContainer = null!; + private CollapsibleButtonContainerSlim buttonContainer = null!; private FillFlowContainer idleBottomContent = null!; private BeatmapCardDownloadProgressBar downloadProgressBar = null!; @@ -52,22 +62,16 @@ namespace osu.Game.Beatmaps.Drawables.Cards { c.MainContent = new Container { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + Height = height, Children = new Drawable[] { - thumbnail = new BeatmapCardThumbnail(BeatmapSet) + buttonContainer = new CollapsibleButtonContainerSlim(BeatmapSet) { - Name = @"Left (icon) area", - Size = new Vector2(cover_width, height), - Padding = new MarginPadding { Right = CORNER_RADIUS }, - }, - buttonContainer = new CollapsibleButtonContainer(BeatmapSet) - { - X = cover_width - CORNER_RADIUS, - Width = width - cover_width + CORNER_RADIUS, + Width = Width, FavouriteState = { BindTarget = FavouriteState }, - ButtonsCollapsedWidth = CORNER_RADIUS, - ButtonsExpandedWidth = 30, + ButtonsCollapsedWidth = 5, + ButtonsExpandedWidth = 20, Children = new Drawable[] { new FillFlowContainer @@ -145,6 +149,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards }; c.Expanded.BindTarget = Expanded; }); + + Action = () => buttonContainer.TriggerClick(); } private LocalisableString createArtistText() @@ -160,7 +166,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards bool showDetails = IsHovered; buttonContainer.ShowDetails.Value = showDetails; - thumbnail.Dimmed.Value = showDetails; } } } diff --git a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainerSlim.cs b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainerSlim.cs new file mode 100644 index 0000000000..d17ff0d759 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainerSlim.cs @@ -0,0 +1,246 @@ +// 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.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Resources.Localisation.Web; +using osuTK; + +namespace osu.Game.Beatmaps.Drawables.Cards +{ + public partial class CollapsibleButtonContainerSlim : OsuClickableContainer + { + public Bindable ShowDetails = new Bindable(); + public Bindable FavouriteState = new Bindable(); + + private readonly BeatmapDownloadTracker downloadTracker; + + private float buttonsExpandedWidth; + + public float ButtonsExpandedWidth + { + get => buttonsExpandedWidth; + set + { + buttonsExpandedWidth = value; + buttonArea.Width = value; + if (IsLoaded) + updateState(); + } + } + + private float buttonsCollapsedWidth; + + public float ButtonsCollapsedWidth + { + get => buttonsCollapsedWidth; + set + { + buttonsCollapsedWidth = value; + if (IsLoaded) + updateState(); + } + } + + protected override Container Content => mainContent; + + private readonly APIBeatmapSet beatmapSet; + + private readonly Container background; + + private readonly Container buttonArea; + + private readonly Container mainArea; + private readonly Container mainContent; + + private readonly Container icons; + private readonly SpriteIcon downloadIcon; + private readonly LoadingSpinner spinner; + private readonly SpriteIcon goToBeatmapIcon; + + private const int icon_size = 12; + + private Bindable preferNoVideo = null!; + + [Resolved] + private BeatmapModelDownloader beatmaps { get; set; } = null!; + + [Resolved] + private OsuGame? game { get; set; } + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + public CollapsibleButtonContainerSlim(APIBeatmapSet beatmapSet) + { + this.beatmapSet = beatmapSet; + + downloadTracker = new BeatmapDownloadTracker(beatmapSet); + + RelativeSizeAxes = Axes.Y; + Masking = true; + CornerRadius = BeatmapCard.CORNER_RADIUS; + + base.Content.AddRange(new Drawable[] + { + downloadTracker, + background = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.White + }, + }, + buttonArea = new Container + { + Name = @"Right (button) area", + RelativeSizeAxes = Axes.Y, + Origin = Anchor.TopRight, + Anchor = Anchor.TopRight, + Child = icons = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + downloadIcon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.Download + }, + spinner = new LoadingSpinner + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(icon_size) + }, + goToBeatmapIcon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.AngleDoubleRight + }, + } + } + }, + mainArea = new Container + { + Name = @"Main content", + RelativeSizeAxes = Axes.Y, + CornerRadius = BeatmapCard.CORNER_RADIUS, + Masking = true, + Children = new Drawable[] + { + new BeatmapCardContentBackground(beatmapSet) + { + RelativeSizeAxes = Axes.Both, + Dimmed = { BindTarget = ShowDetails } + }, + mainContent = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Horizontal = 10, + Vertical = 4 + }, + } + } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + preferNoVideo = config.GetBindable(OsuSetting.PreferNoVideo); + + downloadIcon.Colour = spinner.Colour = colourProvider.Content1; + goToBeatmapIcon.Colour = colourProvider.Foreground1; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + preferNoVideo.BindValueChanged(_ => updateState()); + downloadTracker.State.BindValueChanged(_ => updateState()); + ShowDetails.BindValueChanged(_ => updateState(), true); + FinishTransforms(true); + } + + private void updateState() + { + float targetWidth = Width - (ShowDetails.Value ? ButtonsExpandedWidth : ButtonsCollapsedWidth); + + mainArea.ResizeWidthTo(targetWidth, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + + var backgroundColour = downloadTracker.State.Value == DownloadState.LocallyAvailable ? colours.Lime0 : colourProvider.Background3; + if (ShowDetails.Value) + backgroundColour = backgroundColour.Lighten(0.2f); + + background.FadeColour(backgroundColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + icons.FadeTo(ShowDetails.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + + if (beatmapSet.Availability.DownloadDisabled) + { + Enabled.Value = false; + TooltipText = BeatmapsetsStrings.AvailabilityDisabled; + return; + } + + switch (downloadTracker.State.Value) + { + case DownloadState.NotDownloaded: + Action = () => beatmaps.Download(beatmapSet, preferNoVideo.Value); + break; + + case DownloadState.LocallyAvailable: + Action = () => game?.PresentBeatmap(beatmapSet); + break; + + default: + Action = null; + break; + } + + downloadIcon.FadeTo(downloadTracker.State.Value == DownloadState.NotDownloaded ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + spinner.FadeTo(downloadTracker.State.Value == DownloadState.Downloading || downloadTracker.State.Value == DownloadState.Importing ? 1 : 0, + BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + goToBeatmapIcon.FadeTo(downloadTracker.State.Value == DownloadState.LocallyAvailable ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + + if (downloadTracker.State.Value == DownloadState.NotDownloaded) + { + if (!beatmapSet.HasVideo) + TooltipText = BeatmapsetsStrings.PanelDownloadAll; + else + TooltipText = preferNoVideo.Value ? BeatmapsetsStrings.PanelDownloadNoVideo : BeatmapsetsStrings.PanelDownloadVideo; + } + else + { + TooltipText = default; + } + } + } +}