mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 01:02:55 +08:00
Merge pull request #6416 from EVAST9919/favourite-beatmap
Add API functionality to beatmap favourite button
This commit is contained in:
commit
4adf967801
54
osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs
Normal file
54
osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.BeatmapSet.Buttons;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneFavouriteButton : OsuTestScene
|
||||
{
|
||||
private FavouriteButton favourite;
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("create button", () => Child = favourite = new FavouriteButton
|
||||
{
|
||||
RelativeSizeAxes = Axes.None,
|
||||
Size = new Vector2(50),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLoggedOutIn()
|
||||
{
|
||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
|
||||
AddStep("log out", () => API.Logout());
|
||||
checkEnabled(false);
|
||||
AddStep("log in", () => API.Login("test", "test"));
|
||||
checkEnabled(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapChange()
|
||||
{
|
||||
AddStep("log in", () => API.Login("test", "test"));
|
||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
|
||||
checkEnabled(true);
|
||||
AddStep("set invalid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo());
|
||||
checkEnabled(false);
|
||||
}
|
||||
|
||||
private void checkEnabled(bool expected)
|
||||
{
|
||||
AddAssert("is " + (expected ? "enabled" : "disabled"), () => favourite.Enabled.Value == expected);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
@ -15,7 +16,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
private readonly LoadingAnimation loading;
|
||||
|
||||
public DimmedLoadingLayer()
|
||||
public DimmedLoadingLayer(float dimAmount = 0.5f, float iconScale = 1f)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Children = new Drawable[]
|
||||
@ -23,9 +24,9 @@ namespace osu.Game.Graphics.UserInterface
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.5f),
|
||||
Colour = Color4.Black.Opacity(dimAmount),
|
||||
},
|
||||
loading = new LoadingAnimation(),
|
||||
loading = new LoadingAnimation { Scale = new Vector2(iconScale) },
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.IO.Network;
|
||||
using osu.Framework.Logging;
|
||||
|
||||
@ -112,6 +113,22 @@ namespace osu.Game.Online.API
|
||||
cancelled = true;
|
||||
WebRequest?.Abort();
|
||||
|
||||
string responseString = WebRequest?.ResponseString;
|
||||
|
||||
if (!string.IsNullOrEmpty(responseString))
|
||||
{
|
||||
try
|
||||
{
|
||||
// attempt to decode a displayable error string.
|
||||
var error = JsonConvert.DeserializeObject<DisplayableError>(responseString);
|
||||
if (error != null)
|
||||
e = new Exception(error.ErrorMessage, e);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Log($@"Failing request {this} ({e})", LoggingTarget.Network);
|
||||
pendingFailure = () => Failure?.Invoke(e);
|
||||
checkAndScheduleFailure();
|
||||
@ -129,6 +146,12 @@ namespace osu.Game.Online.API
|
||||
pendingFailure = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private class DisplayableError
|
||||
{
|
||||
[JsonProperty("error")]
|
||||
public string ErrorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void APIFailureHandler(Exception e);
|
||||
|
36
osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs
Normal file
36
osu.Game/Online/API/Requests/PostBeatmapFavouriteRequest.cs
Normal file
@ -0,0 +1,36 @@
|
||||
// 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.Framework.IO.Network;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class PostBeatmapFavouriteRequest : APIRequest
|
||||
{
|
||||
private readonly int id;
|
||||
private readonly BeatmapFavouriteAction action;
|
||||
|
||||
public PostBeatmapFavouriteRequest(int id, BeatmapFavouriteAction action)
|
||||
{
|
||||
this.id = id;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
protected override WebRequest CreateWebRequest()
|
||||
{
|
||||
var req = base.CreateWebRequest();
|
||||
req.Method = HttpMethod.Post;
|
||||
req.AddParameter(@"action", action.ToString().ToLowerInvariant());
|
||||
return req;
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmapsets/{id}/favourites";
|
||||
}
|
||||
|
||||
public enum BeatmapFavouriteAction
|
||||
{
|
||||
Favourite,
|
||||
UnFavourite
|
||||
}
|
||||
}
|
@ -1,52 +1,51 @@
|
||||
// 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 System.Diagnostics;
|
||||
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.Cursor;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
{
|
||||
public class FavouriteButton : HeaderButton
|
||||
public class FavouriteButton : HeaderButton, IHasTooltip
|
||||
{
|
||||
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
|
||||
private readonly Bindable<bool> favourited = new Bindable<bool>();
|
||||
private readonly BindableBool favourited = new BindableBool();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private PostBeatmapFavouriteRequest request;
|
||||
private DimmedLoadingLayer loading;
|
||||
|
||||
private readonly Bindable<User> localUser = new Bindable<User>();
|
||||
|
||||
public string TooltipText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Enabled.Value) return string.Empty;
|
||||
|
||||
return (favourited.Value ? "Unfavourite" : "Favourite") + " this beatmapset";
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(IAPIProvider api, NotificationOverlay notifications)
|
||||
{
|
||||
Container pink;
|
||||
SpriteIcon icon;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
pink = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"9f015f"),
|
||||
},
|
||||
new Triangles
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ColourLight = OsuColour.FromHex(@"cb2187"),
|
||||
ColourDark = OsuColour.FromHex(@"9f015f"),
|
||||
TriangleScale = 1.5f,
|
||||
},
|
||||
},
|
||||
},
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@ -55,31 +54,58 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||
Size = new Vector2(18),
|
||||
Shadow = false,
|
||||
},
|
||||
loading = new DimmedLoadingLayer(0.8f, 0.5f),
|
||||
});
|
||||
|
||||
BeatmapSet.BindValueChanged(setInfo =>
|
||||
Action = () =>
|
||||
{
|
||||
if (setInfo.NewValue?.OnlineInfo?.HasFavourited == null)
|
||||
if (loading.State.Value == Visibility.Visible)
|
||||
return;
|
||||
|
||||
favourited.Value = setInfo.NewValue.OnlineInfo.HasFavourited;
|
||||
});
|
||||
// guaranteed by disabled state above.
|
||||
Debug.Assert(BeatmapSet.Value.OnlineBeatmapSetID != null);
|
||||
|
||||
favourited.ValueChanged += favourited =>
|
||||
{
|
||||
if (favourited.NewValue)
|
||||
loading.Show();
|
||||
|
||||
request?.Cancel();
|
||||
|
||||
request = new PostBeatmapFavouriteRequest(BeatmapSet.Value.OnlineBeatmapSetID.Value, favourited.Value ? BeatmapFavouriteAction.UnFavourite : BeatmapFavouriteAction.Favourite);
|
||||
|
||||
request.Success += () =>
|
||||
{
|
||||
pink.FadeIn(200);
|
||||
icon.Icon = FontAwesome.Solid.Heart;
|
||||
}
|
||||
else
|
||||
favourited.Toggle();
|
||||
loading.Hide();
|
||||
};
|
||||
|
||||
request.Failure += e =>
|
||||
{
|
||||
pink.FadeOut(200);
|
||||
icon.Icon = FontAwesome.Regular.Heart;
|
||||
}
|
||||
notifications?.Post(new SimpleNotification
|
||||
{
|
||||
Text = e.Message,
|
||||
Icon = FontAwesome.Solid.Times,
|
||||
});
|
||||
|
||||
loading.Hide();
|
||||
};
|
||||
|
||||
api.Queue(request);
|
||||
};
|
||||
|
||||
favourited.ValueChanged += favourited => icon.Icon = favourited.NewValue ? FontAwesome.Solid.Heart : FontAwesome.Regular.Heart;
|
||||
|
||||
localUser.BindTo(api.LocalUser);
|
||||
localUser.BindValueChanged(_ => updateEnabled());
|
||||
|
||||
// must be run after setting the Action to ensure correct enabled state (setting an Action forces a button to be enabled).
|
||||
BeatmapSet.BindValueChanged(setInfo =>
|
||||
{
|
||||
updateEnabled();
|
||||
favourited.Value = setInfo.NewValue?.OnlineInfo?.HasFavourited ?? false;
|
||||
}, true);
|
||||
}
|
||||
|
||||
private void updateEnabled() => Enabled.Value = !(localUser.Value is GuestUser) && BeatmapSet.Value?.OnlineBeatmapSetID > 0;
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
Loading…
Reference in New Issue
Block a user