1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-13 20:33:35 +08:00
Files
osu-lazer/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs
T
Bartłomiej Dach 199bcd7fdb Improve input handling in beatmap card buttons
This is in response to feedback in
https://osu.ppy.sh/community/forums/topics/2056547?n=1.

Upon examining the button further, there was indeed some rather weird...
almost hysteresis in how the button behaved with respect to the area on
the screen that activated it. Because of the following scourge of a
method that continues to haunt us to this day:

https://github.com/ppy/osu/blob/31487545d0d17c4337d4b4cc5d4afb3ba1dae838/osu.Game/Graphics/Containers/OsuClickableContainer.cs#L24-L25

the button would effectively only be activated by 80% of its drawable
area when it was not hovered, because of the scale applied to the
`content` container which `Container.Content` redirected to.

This is resolved here by various rearrangements of paddings and sizes
such that the clickable area of any of the buttons of the card is always
the full top or bottom half of the button area.

Also included are some cosmetic touch-ups which happened to be
convenient like folding the loading spinner into the base
`BeatmapCardIconButton`, adding loading support for the favourite
button, using BDL more, and resolving some "virtual member call in
constructor" inspections.
2025-03-25 12:59:37 +01:00

90 lines
2.9 KiB
C#

// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses;
using osu.Framework.Logging;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{
public partial class FavouriteButton : BeatmapCardIconButton, IHasCurrentValue<BeatmapSetFavouriteState>
{
private readonly BindableWithCurrent<BeatmapSetFavouriteState> current;
public Bindable<BeatmapSetFavouriteState> Current
{
get => current.Current;
set => current.Current = value;
}
private readonly APIBeatmapSet beatmapSet;
private PostBeatmapFavouriteRequest favouriteRequest;
[Resolved]
private IAPIProvider api { get; set; }
public FavouriteButton(APIBeatmapSet beatmapSet)
{
current = new BindableWithCurrent<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
this.beatmapSet = beatmapSet;
}
protected override void LoadComplete()
{
base.LoadComplete();
Action = toggleFavouriteStatus;
current.BindValueChanged(_ => updateState(), true);
}
private void toggleFavouriteStatus()
{
var actionType = current.Value.Favourited ? BeatmapFavouriteAction.UnFavourite : BeatmapFavouriteAction.Favourite;
favouriteRequest?.Cancel();
favouriteRequest = new PostBeatmapFavouriteRequest(beatmapSet.OnlineID, actionType);
SetLoading(true);
favouriteRequest.Success += () =>
{
bool favourited = actionType == BeatmapFavouriteAction.Favourite;
current.Value = new BeatmapSetFavouriteState(favourited, current.Value.FavouriteCount + (favourited ? 1 : -1));
SetLoading(false);
};
favouriteRequest.Failure += e =>
{
Logger.Error(e, $"Failed to {actionType.ToString().ToLowerInvariant()} beatmap: {e.Message}");
SetLoading(false);
};
api.Queue(favouriteRequest);
}
private void updateState()
{
if (current.Value.Favourited)
{
Icon.Icon = FontAwesome.Solid.Heart;
TooltipText = BeatmapsetsStrings.ShowDetailsUnfavourite;
}
else
{
Icon.Icon = FontAwesome.Regular.Heart;
TooltipText = BeatmapsetsStrings.ShowDetailsFavourite;
}
}
}
}