Update favourite statistic value on favourite button clicks

This commit is contained in:
Bartłomiej Dach 2021-11-07 17:42:32 +01:00
parent b5cbdcf981
commit f4b8dee2d0
No known key found for this signature in database
GPG Key ID: BCECCD4FA41F6497
5 changed files with 106 additions and 16 deletions

View File

@ -9,8 +9,11 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Beatmaps.Drawables.Cards;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays; using osu.Game.Overlays;
using osuTK; using osuTK;
@ -20,6 +23,8 @@ namespace osu.Game.Tests.Visual.Beatmaps
{ {
public class TestSceneBeatmapCard : OsuTestScene public class TestSceneBeatmapCard : OsuTestScene
{ {
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
private APIBeatmapSet[] testCases; private APIBeatmapSet[] testCases;
#region Test case generation #region Test case generation
@ -164,6 +169,19 @@ namespace osu.Game.Tests.Visual.Beatmaps
#endregion #endregion
[SetUpSteps]
public void SetUpSteps()
{
AddStep("register request handling", () => dummyAPI.HandleRequest = request =>
{
if (!(request is PostBeatmapFavouriteRequest))
return false;
request.TriggerSuccess();
return true;
});
}
private Drawable createContent(OverlayColourScheme colourScheme, Func<APIBeatmapSet, Drawable> creationFunc) private Drawable createContent(OverlayColourScheme colourScheme, Func<APIBeatmapSet, Drawable> creationFunc)
{ {
var colourProvider = new OverlayColourProvider(colourScheme); var colourProvider = new OverlayColourProvider(colourScheme);

View File

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -35,6 +36,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
private const float corner_radius = 10; private const float corner_radius = 10;
private readonly APIBeatmapSet beatmapSet; private readonly APIBeatmapSet beatmapSet;
private readonly Bindable<BeatmapSetFavouriteState> favouriteState;
private UpdateableOnlineBeatmapSetCover leftCover; private UpdateableOnlineBeatmapSetCover leftCover;
private FillFlowContainer leftIconArea; private FillFlowContainer leftIconArea;
@ -55,6 +57,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
: base(HoverSampleSet.Submit) : base(HoverSampleSet.Submit)
{ {
this.beatmapSet = beatmapSet; this.beatmapSet = beatmapSet;
favouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -108,7 +111,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
Spacing = new Vector2(0, 14), Spacing = new Vector2(0, 14),
Children = new BeatmapCardIconButton[] Children = new BeatmapCardIconButton[]
{ {
new FavouriteButton(beatmapSet), new FavouriteButton(beatmapSet) { Current = favouriteState },
new DownloadButton(beatmapSet) new DownloadButton(beatmapSet)
} }
} }
@ -312,7 +315,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
if (beatmapSet.HypeStatus != null && beatmapSet.NominationStatus != null) if (beatmapSet.HypeStatus != null && beatmapSet.NominationStatus != null)
yield return new NominationsStatistic(beatmapSet.NominationStatus); yield return new NominationsStatistic(beatmapSet.NominationStatus);
yield return new FavouritesStatistic(beatmapSet); yield return new FavouritesStatistic(beatmapSet) { Current = favouriteState };
yield return new PlayCountStatistic(beatmapSet); yield return new PlayCountStatistic(beatmapSet);
var dateStatistic = BeatmapCardDateStatistic.CreateFor(beatmapSet); var dateStatistic = BeatmapCardDateStatistic.CreateFor(beatmapSet);

View File

@ -0,0 +1,31 @@
// 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.Game.Beatmaps.Drawables.Cards.Buttons;
using osu.Game.Beatmaps.Drawables.Cards.Statistics;
namespace osu.Game.Beatmaps.Drawables.Cards
{
/// <summary>
/// Stores the current favourite state of a beatmap set.
/// Used to coordinate between <see cref="FavouriteButton"/> and <see cref="FavouritesStatistic"/>.
/// </summary>
public readonly struct BeatmapSetFavouriteState
{
/// <summary>
/// Whether the currently logged-in user has favourited this beatmap.
/// </summary>
public bool Favourited { get; }
/// <summary>
/// The number of favourites that the beatmap set has received, including the currently logged-in user.
/// </summary>
public int FavouriteCount { get; }
public BeatmapSetFavouriteState(bool favourited, int favouriteCount)
{
Favourited = favourited;
FavouriteCount = favouriteCount;
}
}
}

View File

@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Game.Online.API; using osu.Game.Online.API;
@ -11,17 +13,24 @@ using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Beatmaps.Drawables.Cards.Buttons namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{ {
public class FavouriteButton : BeatmapCardIconButton public class FavouriteButton : BeatmapCardIconButton, IHasCurrentValue<BeatmapSetFavouriteState>
{ {
private readonly APIBeatmapSet beatmapSet; private readonly BindableWithCurrent<BeatmapSetFavouriteState> current;
public Bindable<BeatmapSetFavouriteState> Current
{
get => current.Current;
set => current.Current = value;
}
private readonly int onlineBeatmapID;
private PostBeatmapFavouriteRequest favouriteRequest; private PostBeatmapFavouriteRequest favouriteRequest;
public FavouriteButton(APIBeatmapSet beatmapSet) public FavouriteButton(APIBeatmapSet beatmapSet)
{ {
this.beatmapSet = beatmapSet; current = new BindableWithCurrent<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
onlineBeatmapID = beatmapSet.OnlineID;
updateState();
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -29,17 +38,19 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{ {
Action = () => Action = () =>
{ {
var actionType = beatmapSet.HasFavourited ? BeatmapFavouriteAction.UnFavourite : BeatmapFavouriteAction.Favourite; var actionType = current.Value.Favourited ? BeatmapFavouriteAction.UnFavourite : BeatmapFavouriteAction.Favourite;
favouriteRequest?.Cancel(); favouriteRequest?.Cancel();
favouriteRequest = new PostBeatmapFavouriteRequest(beatmapSet.OnlineID, actionType); favouriteRequest = new PostBeatmapFavouriteRequest(onlineBeatmapID, actionType);
Enabled.Value = false; Enabled.Value = false;
favouriteRequest.Success += () => favouriteRequest.Success += () =>
{ {
beatmapSet.HasFavourited = actionType == BeatmapFavouriteAction.Favourite; bool favourited = actionType == BeatmapFavouriteAction.Favourite;
current.Value = new BeatmapSetFavouriteState(favourited, current.Value.FavouriteCount + (favourited ? 1 : -1));
Enabled.Value = true; Enabled.Value = true;
updateState();
}; };
favouriteRequest.Failure += e => favouriteRequest.Failure += e =>
{ {
@ -51,9 +62,15 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
}; };
} }
protected override void LoadComplete()
{
base.LoadComplete();
current.BindValueChanged(_ => updateState(), true);
}
private void updateState() private void updateState()
{ {
if (beatmapSet.HasFavourited) if (current.Value.Favourited)
{ {
Icon.Icon = FontAwesome.Solid.Heart; Icon.Icon = FontAwesome.Solid.Heart;
TooltipText = BeatmapsetsStrings.ShowDetailsUnfavourite; TooltipText = BeatmapsetsStrings.ShowDetailsUnfavourite;

View File

@ -2,8 +2,10 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using Humanizer; using Humanizer;
using osu.Framework.Bindables;
using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Beatmaps.Drawables.Cards.Statistics namespace osu.Game.Beatmaps.Drawables.Cards.Statistics
@ -11,13 +13,32 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Statistics
/// <summary> /// <summary>
/// Shows the number of favourites that a beatmap set has received. /// Shows the number of favourites that a beatmap set has received.
/// </summary> /// </summary>
public class FavouritesStatistic : BeatmapCardStatistic public class FavouritesStatistic : BeatmapCardStatistic, IHasCurrentValue<BeatmapSetFavouriteState>
{ {
private readonly BindableWithCurrent<BeatmapSetFavouriteState> current;
public Bindable<BeatmapSetFavouriteState> Current
{
get => current.Current;
set => current.Current = value;
}
public FavouritesStatistic(IBeatmapSetOnlineInfo onlineInfo) public FavouritesStatistic(IBeatmapSetOnlineInfo onlineInfo)
{ {
Icon = onlineInfo.HasFavourited ? FontAwesome.Solid.Heart : FontAwesome.Regular.Heart; current = new BindableWithCurrent<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(onlineInfo.HasFavourited, onlineInfo.FavouriteCount));
Text = onlineInfo.FavouriteCount.ToMetric(decimals: 1); }
TooltipText = BeatmapsStrings.PanelFavourites(onlineInfo.FavouriteCount.ToLocalisableString(@"N0"));
protected override void LoadComplete()
{
base.LoadComplete();
current.BindValueChanged(_ => updateState(), true);
}
private void updateState()
{
Icon = current.Value.Favourited ? FontAwesome.Solid.Heart : FontAwesome.Regular.Heart;
Text = current.Value.FavouriteCount.ToMetric(decimals: 1);
TooltipText = BeatmapsStrings.PanelFavourites(current.Value.FavouriteCount.ToLocalisableString(@"N0"));
} }
} }
} }