Skip to content

Commit

Permalink
Merge pull request #15520 from bdach/beatmap-card/favourite-button
Browse files Browse the repository at this point in the history
Add favourite button to beatmap card
  • Loading branch information
peppy authored Nov 8, 2021
2 parents f79c9e7 + 7460325 commit 694df5d
Show file tree
Hide file tree
Showing 9 changed files with 348 additions and 12 deletions.
18 changes: 18 additions & 0 deletions osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
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.Overlays;
using osuTK;
Expand All @@ -20,6 +23,8 @@ namespace osu.Game.Tests.Visual.Beatmaps
{
public class TestSceneBeatmapCard : OsuTestScene
{
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;

private APIBeatmapSet[] testCases;

#region Test case generation
Expand Down Expand Up @@ -164,6 +169,19 @@ private static APIBeatmapSet getManyDifficultiesBeatmapSet(int count)

#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)
{
var colourProvider = new OverlayColourProvider(colourScheme);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Beatmaps.Drawables.Cards.Buttons;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Resources.Localisation.Web;
using osuTK;
using osuTK.Input;

namespace osu.Game.Tests.Visual.Beatmaps
{
public class TestSceneBeatmapCardFavouriteButton : OsuManualInputManagerTestScene
{
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;

[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);

[Test]
public void TestInitialState([Values] bool favourited)
{
APIBeatmapSet beatmapSetInfo = null;
FavouriteButton button = null;

AddStep("create beatmap set", () =>
{
beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value);
beatmapSetInfo.HasFavourited = favourited;
});
AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) });

assertCorrectIcon(favourited);
AddAssert("correct tooltip text", () => button.TooltipText == (favourited ? BeatmapsetsStrings.ShowDetailsUnfavourite : BeatmapsetsStrings.ShowDetailsFavourite));
}

[Test]
public void TestRequestHandling()
{
APIBeatmapSet beatmapSetInfo = null;
FavouriteButton button = null;
BeatmapFavouriteAction? lastRequestAction = null;

AddStep("create beatmap set", () => beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value));
AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) });

assertCorrectIcon(false);

AddStep("register request handling", () => dummyAPI.HandleRequest = request =>
{
if (!(request is PostBeatmapFavouriteRequest favouriteRequest))
return false;

lastRequestAction = favouriteRequest.Action;
request.TriggerSuccess();
return true;
});

AddStep("click icon", () =>
{
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("favourite request sent", () => lastRequestAction == BeatmapFavouriteAction.Favourite);
assertCorrectIcon(true);

AddStep("click icon", () =>
{
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("unfavourite request sent", () => lastRequestAction == BeatmapFavouriteAction.UnFavourite);
assertCorrectIcon(false);
}

private void assertCorrectIcon(bool favourited) => AddAssert("icon correct",
() => this.ChildrenOfType<SpriteIcon>().Single().Icon.Equals(favourited ? FontAwesome.Solid.Heart : FontAwesome.Regular.Heart));
}
}
39 changes: 34 additions & 5 deletions osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
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.Buttons;
using osu.Game.Beatmaps.Drawables.Cards.Statistics;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
Expand All @@ -21,6 +23,7 @@
using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Resources.Localisation.Web;
using osuTK.Graphics;
using DownloadButton = osu.Game.Beatmaps.Drawables.Cards.Buttons.DownloadButton;

namespace osu.Game.Beatmaps.Drawables.Cards
{
Expand All @@ -33,9 +36,12 @@ public class BeatmapCard : OsuClickableContainer
private const float corner_radius = 10;

private readonly APIBeatmapSet beatmapSet;
private readonly Bindable<BeatmapSetFavouriteState> favouriteState;

private UpdateableOnlineBeatmapSetCover leftCover;
private FillFlowContainer iconArea;
private FillFlowContainer leftIconArea;

private Container rightButtonArea;

private Container mainContent;
private BeatmapCardContentBackground mainContentBackground;
Expand All @@ -51,6 +57,7 @@ public BeatmapCard(APIBeatmapSet beatmapSet)
: base(HoverSampleSet.Submit)
{
this.beatmapSet = beatmapSet;
favouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
}

[BackgroundDependencyLoader]
Expand Down Expand Up @@ -79,7 +86,7 @@ private void load()
RelativeSizeAxes = Axes.Both,
OnlineInfo = beatmapSet
},
iconArea = new FillFlowContainer
leftIconArea = new FillFlowContainer
{
Margin = new MarginPadding(5),
AutoSizeAxes = Axes.Both,
Expand All @@ -88,6 +95,27 @@ private void load()
}
}
},
rightButtonArea = new Container
{
Name = @"Right (button) area",
Width = 30,
RelativeSizeAxes = Axes.Y,
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Child = new FillFlowContainer<BeatmapCardIconButton>
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 14),
Children = new BeatmapCardIconButton[]
{
new FavouriteButton(beatmapSet) { Current = favouriteState },
new DownloadButton(beatmapSet)
}
}
},
mainContent = new Container
{
Name = @"Main content",
Expand Down Expand Up @@ -226,10 +254,10 @@ private void load()
};

if (beatmapSet.HasVideo)
iconArea.Add(new IconPill(FontAwesome.Solid.Film));
leftIconArea.Add(new IconPill(FontAwesome.Solid.Film));

if (beatmapSet.HasStoryboard)
iconArea.Add(new IconPill(FontAwesome.Solid.Image));
leftIconArea.Add(new IconPill(FontAwesome.Solid.Image));

if (beatmapSet.HasExplicitContent)
{
Expand Down Expand Up @@ -287,7 +315,7 @@ private IEnumerable<BeatmapCardStatistic> createStatistics()
if (beatmapSet.HypeStatus != null && beatmapSet.NominationStatus != null)
yield return new NominationsStatistic(beatmapSet.NominationStatus);

yield return new FavouritesStatistic(beatmapSet);
yield return new FavouritesStatistic(beatmapSet) { Current = favouriteState };
yield return new PlayCountStatistic(beatmapSet);

var dateStatistic = BeatmapCardDateStatistic.CreateFor(beatmapSet);
Expand All @@ -306,6 +334,7 @@ private void updateState()

leftCover.FadeColour(IsHovered ? OsuColour.Gray(0.2f) : Color4.White, TRANSITION_DURATION, Easing.OutQuint);
statisticsContainer.FadeTo(IsHovered ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
rightButtonArea.FadeTo(IsHovered ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
}
}
}
31 changes: 31 additions & 0 deletions osu.Game/Beatmaps/Drawables/Cards/BeatmapSetFavouriteState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. 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;
}
}
}
46 changes: 46 additions & 0 deletions osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. 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.Sprites;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays;
using osuTK;

namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{
public abstract class BeatmapCardIconButton : OsuHoverContainer
{
protected readonly SpriteIcon Icon;

private float size;

public new float Size
{
get => size;
set
{
size = value;
Icon.Size = new Vector2(size);
}
}

protected BeatmapCardIconButton()
{
Add(Icon = new SpriteIcon());

AutoSizeAxes = Axes.Both;
Size = 12;
}

[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
Anchor = Origin = Anchor.Centre;

IdleColour = colourProvider.Light1;
HoverColour = colourProvider.Content1;
}
}
}
18 changes: 18 additions & 0 deletions osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses;

namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{
public class DownloadButton : BeatmapCardIconButton
{
public DownloadButton(APIBeatmapSet beatmapSet)
{
Icon.Icon = FontAwesome.Solid.FileDownload;
}

// TODO: implement behaviour
}
}
Loading

0 comments on commit 694df5d

Please sign in to comment.