From 04c2a9cd59a61e3951f1ab36566abbb78bf15ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 17 Oct 2021 20:50:44 +0200 Subject: [PATCH] Display basic statistics on card hover --- .../Visual/Beatmaps/TestSceneBeatmapCard.cs | 10 +++ .../Beatmaps/Drawables/Cards/BeatmapCard.cs | 23 ++++++ .../Statistics/BeatmapCardDateStatistic.cs | 55 +++++++++++++ .../Cards/Statistics/BeatmapCardStatistic.cs | 81 +++++++++++++++++++ .../Cards/Statistics/FavouritesStatistic.cs | 23 ++++++ .../Cards/Statistics/PlayCountStatistic.cs | 23 ++++++ 6 files changed, 215 insertions(+) create mode 100644 osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs create mode 100644 osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs create mode 100644 osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs create mode 100644 osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs index 2aeb4ab4e2..b56dcb0a43 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs @@ -31,11 +31,20 @@ namespace osu.Game.Tests.Visual.Beatmaps normal.HasVideo = true; normal.HasStoryboard = true; + var withStatistics = CreateAPIBeatmapSet(Ruleset.Value); + withStatistics.Status = BeatmapSetOnlineStatus.Approved; + withStatistics.FavouriteCount = 284_239; + withStatistics.PlayCount = 999_001; + withStatistics.Ranked = DateTimeOffset.Now.AddDays(-45); + var undownloadable = getUndownloadableBeatmapSet(); + undownloadable.LastUpdated = DateTimeOffset.Now.AddYears(-1); var someDifficulties = getManyDifficultiesBeatmapSet(11); someDifficulties.Title = someDifficulties.TitleUnicode = "some difficulties"; someDifficulties.Status = BeatmapSetOnlineStatus.Qualified; + someDifficulties.HasFavourited = true; + someDifficulties.FavouriteCount = 1; var manyDifficulties = getManyDifficultiesBeatmapSet(100); manyDifficulties.Status = BeatmapSetOnlineStatus.Pending; @@ -59,6 +68,7 @@ namespace osu.Game.Tests.Visual.Beatmaps testCases = new[] { normal, + withStatistics, undownloadable, someDifficulties, manyDifficulties, diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs index 8136ebbd70..5d8f0a93cd 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -8,6 +9,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Game.Beatmaps.Drawables.Cards.Statistics; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -40,6 +42,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards private GridContainer titleContainer; private GridContainer artistContainer; + private FillFlowContainer statisticsContainer; [Resolved] private OverlayColourProvider colourProvider { get; set; } @@ -176,6 +179,15 @@ namespace osu.Game.Beatmaps.Drawables.Cards d.AddText("mapped by ", t => t.Colour = colourProvider.Content2); d.AddUserLink(beatmapSet.Author); }), + statisticsContainer = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Alpha = 0, + ChildrenEnumerable = createStatistics() + } } }, new FillFlowContainer @@ -265,6 +277,16 @@ namespace osu.Game.Beatmaps.Drawables.Cards return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist); } + private IEnumerable createStatistics() + { + yield return new FavouritesStatistic(beatmapSet); + yield return new PlayCountStatistic(beatmapSet); + + var dateStatistic = BeatmapCardDateStatistic.CreateFor(beatmapSet); + if (dateStatistic != null) + yield return dateStatistic; + } + private void updateState() { float targetWidth = width - height; @@ -275,6 +297,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards mainContentBackground.Dimmed.Value = IsHovered; leftCover.FadeColour(IsHovered ? OsuColour.Gray(0.2f) : Color4.White, TRANSITION_DURATION, Easing.OutQuint); + statisticsContainer.FadeTo(IsHovered ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint); } } } diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs new file mode 100644 index 0000000000..8f2c4b538c --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + public class BeatmapCardDateStatistic : BeatmapCardStatistic + { + private readonly DateTimeOffset dateTime; + + private BeatmapCardDateStatistic(DateTimeOffset dateTime) + { + this.dateTime = dateTime; + + Icon = FontAwesome.Regular.CheckCircle; + Text = dateTime.ToLocalisableString(@"d MMM yyyy"); + } + + public override object TooltipContent => dateTime; + public override ITooltip GetCustomTooltip() => new DateTooltip(); + + public static BeatmapCardDateStatistic? CreateFor(IBeatmapSetOnlineInfo beatmapSetInfo) + { + var displayDate = displayDateFor(beatmapSetInfo); + + if (displayDate == null) + return null; + + return new BeatmapCardDateStatistic(displayDate.Value); + } + + private static DateTimeOffset? displayDateFor(IBeatmapSetOnlineInfo beatmapSetInfo) + { + // reference: https://github.com/ppy/osu-web/blob/ef432c11719fd1207bec5f9194b04f0033bdf02c/resources/assets/lib/beatmapset-panel.tsx#L36-L44 + switch (beatmapSetInfo.Status) + { + case BeatmapSetOnlineStatus.Ranked: + case BeatmapSetOnlineStatus.Approved: + case BeatmapSetOnlineStatus.Loved: + case BeatmapSetOnlineStatus.Qualified: + return beatmapSetInfo.Ranked; + + default: + return beatmapSetInfo.LastUpdated; + } + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs new file mode 100644 index 0000000000..95d99b9128 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs @@ -0,0 +1,81 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + /// + /// A single statistic shown on a beatmap card. + /// + public abstract class BeatmapCardStatistic : CompositeDrawable, IHasTooltip, IHasCustomTooltip + { + protected IconUsage Icon + { + get => spriteIcon.Icon; + set => spriteIcon.Icon = value; + } + + protected LocalisableString Text + { + get => spriteText.Text; + set => spriteText.Text = value; + } + + protected LocalisableString TooltipText { get; set; } + + private readonly SpriteIcon spriteIcon; + private readonly OsuSpriteText spriteText; + + protected BeatmapCardStatistic() + { + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] + { + spriteIcon = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(10), + Margin = new MarginPadding { Top = 1 } + }, + spriteText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.Default.With(size: 14) + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + spriteIcon.Colour = colourProvider.Content2; + } + + #region Tooltip implementation + + LocalisableString IHasTooltip.TooltipText => TooltipText; + public virtual ITooltip GetCustomTooltip() => null; + public virtual object TooltipContent => null; + + #endregion + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs new file mode 100644 index 0000000000..7b3286ddcc --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Humanizer; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + /// + /// Shows the number of favourites that a beatmap set has received. + /// + public class FavouritesStatistic : BeatmapCardStatistic + { + public FavouritesStatistic(IBeatmapSetOnlineInfo onlineInfo) + { + Icon = onlineInfo.HasFavourited ? FontAwesome.Solid.Heart : FontAwesome.Regular.Heart; + Text = onlineInfo.FavouriteCount.ToMetric(decimals: 1); + TooltipText = BeatmapsStrings.PanelFavourites(onlineInfo.FavouriteCount.ToLocalisableString(@"N0")); + } + } +} diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs new file mode 100644 index 0000000000..d8f0c36bd9 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Humanizer; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Beatmaps.Drawables.Cards.Statistics +{ + /// + /// Shows the number of times the given beatmap set has been played. + /// + public class PlayCountStatistic : BeatmapCardStatistic + { + public PlayCountStatistic(IBeatmapSetOnlineInfo onlineInfo) + { + Icon = FontAwesome.Regular.PlayCircle; + Text = onlineInfo.PlayCount.ToMetric(decimals: 1); + TooltipText = BeatmapsStrings.PanelPlaycount(onlineInfo.PlayCount.ToLocalisableString(@"N0")); + } + } +}